From 71573fd35cf04c2390c542128326b547095e4fcd Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sun, 19 Nov 2023 15:43:59 -0800 Subject: [PATCH 001/197] Avoid repeated triggers in nested `tryceratops` diagnostics (#8772) Closes https://github.com/astral-sh/ruff/issues/8770. --- .../test/fixtures/tryceratops/TRY400.py | 10 +++++++++ .../test/fixtures/tryceratops/TRY401.py | 22 +++++++++++++++++++ .../src/rules/tryceratops/helpers.rs | 7 +++++- .../rules/error_instead_of_exception.rs | 6 ++--- .../tryceratops/rules/verbose_log_message.rs | 16 ++++++++------ ..._error-instead-of-exception_TRY400.py.snap | 8 +++++++ ..._tests__verbose-log-message_TRY401.py.snap | 16 ++++++++++++++ 7 files changed, 74 insertions(+), 11 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/tryceratops/TRY400.py b/crates/ruff_linter/resources/test/fixtures/tryceratops/TRY400.py index 987c321907880..e5b4757691364 100644 --- a/crates/ruff_linter/resources/test/fixtures/tryceratops/TRY400.py +++ b/crates/ruff_linter/resources/test/fixtures/tryceratops/TRY400.py @@ -109,3 +109,13 @@ def fine(): a = 1 except Exception: error("Context message here", exc_info=sys.exc_info()) + + +def nested(): + try: + a = 1 + except Exception: + try: + b = 2 + except Exception: + error("Context message here") diff --git a/crates/ruff_linter/resources/test/fixtures/tryceratops/TRY401.py b/crates/ruff_linter/resources/test/fixtures/tryceratops/TRY401.py index 0aa58677837fd..968e0f957b804 100644 --- a/crates/ruff_linter/resources/test/fixtures/tryceratops/TRY401.py +++ b/crates/ruff_linter/resources/test/fixtures/tryceratops/TRY401.py @@ -126,3 +126,25 @@ def main_function(): except Exception as ex: exception(f"Found an error: {er}") exception(f"Found an error: {ex.field}") + + +def nested(): + try: + process() + handle() + except Exception as ex: + try: + finish() + except Exception as ex: + logger.exception(f"Found an error: {ex}") # TRY401 + + +def nested(): + try: + process() + handle() + except Exception as ex: + try: + finish() + except Exception: + logger.exception(f"Found an error: {ex}") # TRY401 diff --git a/crates/ruff_linter/src/rules/tryceratops/helpers.rs b/crates/ruff_linter/src/rules/tryceratops/helpers.rs index 0e707c1e3924e..bd12ddebfe93b 100644 --- a/crates/ruff_linter/src/rules/tryceratops/helpers.rs +++ b/crates/ruff_linter/src/rules/tryceratops/helpers.rs @@ -1,6 +1,6 @@ use ruff_python_ast::visitor; use ruff_python_ast::visitor::Visitor; -use ruff_python_ast::{self as ast, Expr}; +use ruff_python_ast::{self as ast, ExceptHandler, Expr}; use ruff_python_semantic::analyze::logging; use ruff_python_semantic::SemanticModel; use ruff_python_stdlib::logging::LoggingLevel; @@ -50,4 +50,9 @@ impl<'a, 'b> Visitor<'b> for LoggerCandidateVisitor<'a, 'b> { } visitor::walk_expr(self, expr); } + + fn visit_except_handler(&mut self, _except_handler: &'b ExceptHandler) { + // Don't recurse into exception handlers, since we'll re-run the visitor on any such + // handlers. + } } diff --git a/crates/ruff_linter/src/rules/tryceratops/rules/error_instead_of_exception.rs b/crates/ruff_linter/src/rules/tryceratops/rules/error_instead_of_exception.rs index fda19f79e8b58..d390dafda4492 100644 --- a/crates/ruff_linter/src/rules/tryceratops/rules/error_instead_of_exception.rs +++ b/crates/ruff_linter/src/rules/tryceratops/rules/error_instead_of_exception.rs @@ -23,7 +23,7 @@ use crate::rules::tryceratops::helpers::LoggerCandidateVisitor; /// import logging /// /// -/// def foo(): +/// def func(): /// try: /// raise NotImplementedError /// except NotImplementedError: @@ -35,10 +35,10 @@ use crate::rules::tryceratops::helpers::LoggerCandidateVisitor; /// import logging /// /// -/// def foo(): +/// def func(): /// try: /// raise NotImplementedError -/// except NotImplementedError as exc: +/// except NotImplementedError: /// logging.exception("Exception occurred") /// ``` /// diff --git a/crates/ruff_linter/src/rules/tryceratops/rules/verbose_log_message.rs b/crates/ruff_linter/src/rules/tryceratops/rules/verbose_log_message.rs index 8b3fad0f082d9..701e9a575df6c 100644 --- a/crates/ruff_linter/src/rules/tryceratops/rules/verbose_log_message.rs +++ b/crates/ruff_linter/src/rules/tryceratops/rules/verbose_log_message.rs @@ -30,7 +30,7 @@ use crate::rules::tryceratops::helpers::LoggerCandidateVisitor; /// ```python /// try: /// ... -/// except ValueError as e: +/// except ValueError: /// logger.exception("Found an error") /// ``` #[violation] @@ -61,11 +61,7 @@ impl<'a> Visitor<'a> for NameVisitor<'a> { /// TRY401 pub(crate) fn verbose_log_message(checker: &mut Checker, handlers: &[ExceptHandler]) { for handler in handlers { - let ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler { name, body, .. }) = - handler; - let Some(target) = name else { - continue; - }; + let ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler { body, .. }) = handler; // Find all calls to `logging.exception`. let calls = { @@ -87,8 +83,14 @@ pub(crate) fn verbose_log_message(checker: &mut Checker, handlers: &[ExceptHandl } names }; + + // Find any bound exceptions in the call. for expr in names { - if expr.id == target.as_str() { + let Some(id) = checker.semantic().resolve_name(expr) else { + continue; + }; + let binding = checker.semantic().binding(id); + if binding.kind.is_bound_exception() { checker .diagnostics .push(Diagnostic::new(VerboseLogMessage, expr.range())); diff --git a/crates/ruff_linter/src/rules/tryceratops/snapshots/ruff_linter__rules__tryceratops__tests__error-instead-of-exception_TRY400.py.snap b/crates/ruff_linter/src/rules/tryceratops/snapshots/ruff_linter__rules__tryceratops__tests__error-instead-of-exception_TRY400.py.snap index 35b36493ec3a9..918fae360ea3a 100644 --- a/crates/ruff_linter/src/rules/tryceratops/snapshots/ruff_linter__rules__tryceratops__tests__error-instead-of-exception_TRY400.py.snap +++ b/crates/ruff_linter/src/rules/tryceratops/snapshots/ruff_linter__rules__tryceratops__tests__error-instead-of-exception_TRY400.py.snap @@ -86,4 +86,12 @@ TRY400.py:90:13: TRY400 Use `logging.exception` instead of `logging.error` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY400 | +TRY400.py:121:13: TRY400 Use `logging.exception` instead of `logging.error` + | +119 | b = 2 +120 | except Exception: +121 | error("Context message here") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY400 + | + diff --git a/crates/ruff_linter/src/rules/tryceratops/snapshots/ruff_linter__rules__tryceratops__tests__verbose-log-message_TRY401.py.snap b/crates/ruff_linter/src/rules/tryceratops/snapshots/ruff_linter__rules__tryceratops__tests__verbose-log-message_TRY401.py.snap index 3681b880d1f06..3f71c86e70cdc 100644 --- a/crates/ruff_linter/src/rules/tryceratops/snapshots/ruff_linter__rules__tryceratops__tests__verbose-log-message_TRY401.py.snap +++ b/crates/ruff_linter/src/rules/tryceratops/snapshots/ruff_linter__rules__tryceratops__tests__verbose-log-message_TRY401.py.snap @@ -177,4 +177,20 @@ TRY401.py:117:40: TRY401 Redundant exception object included in `logging.excepti | ^^ TRY401 | +TRY401.py:139:49: TRY401 Redundant exception object included in `logging.exception` call + | +137 | finish() +138 | except Exception as ex: +139 | logger.exception(f"Found an error: {ex}") # TRY401 + | ^^ TRY401 + | + +TRY401.py:150:49: TRY401 Redundant exception object included in `logging.exception` call + | +148 | finish() +149 | except Exception: +150 | logger.exception(f"Found an error: {ex}") # TRY401 + | ^^ TRY401 + | + From 1de5425f7d9d0060474092f25deaa8b72f9d60d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 09:32:22 +0100 Subject: [PATCH 002/197] Bump docker/build-push-action from 3 to 5 (#8779) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3 to 5.
Release notes

Sourced from docker/build-push-action's releases.

v5.0.0

Full Changelog: https://github.com/docker/build-push-action/compare/v4.2.1...v5.0.0

v4.2.1

Note

Buildx v0.10 enables support for a minimal SLSA Provenance attestation, which requires support for OCI-compliant multi-platform images. This may introduce issues with registry and runtime support (e.g. Google Cloud Run and AWS Lambda). You can optionally disable the default provenance attestation functionality using provenance: false.

Full Changelog: https://github.com/docker/build-push-action/compare/v4.2.0...v4.2.1

v4.2.0

Note

Buildx v0.10 enables support for a minimal SLSA Provenance attestation, which requires support for OCI-compliant multi-platform images. This may introduce issues with registry and runtime support (e.g. Google Cloud Run and AWS Lambda). You can optionally disable the default provenance attestation functionality using provenance: false.

Full Changelog: https://github.com/docker/build-push-action/compare/v4.1.1...v4.2.0

v4.1.1

Note

Buildx v0.10 enables support for a minimal SLSA Provenance attestation, which requires support for OCI-compliant multi-platform images. This may introduce issues with registry and runtime support (e.g. Google Cloud Run and AWS Lambda). You can optionally disable the default provenance attestation functionality using provenance: false.

Full Changelog: https://github.com/docker/build-push-action/compare/v4.1.0...v4.1.1

v4.1.0

Note

Buildx v0.10 enables support for a minimal SLSA Provenance attestation, which requires support for OCI-compliant multi-platform images. This may introduce issues with registry and runtime support (e.g. Google Cloud Run and AWS Lambda). You can optionally disable the default provenance attestation functionality using provenance: false.

Full Changelog: https://github.com/docker/build-push-action/compare/v4.0.0...v4.1.0

v4.0.0

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=docker/build-push-action&package-manager=github_actions&previous-version=3&new-version=5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a958e80a8b67c..4e86ac8bf3776 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -561,7 +561,7 @@ jobs: fi - name: "Build and push Docker image" - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm64 From bba43029d402a1740855d75d964d92aee6bd7d78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 09:32:31 +0100 Subject: [PATCH 003/197] Bump docker/metadata-action from 4 to 5 (#8778) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 4 to 5.
Release notes

Sourced from docker/metadata-action's releases.

v5.0.0

Full Changelog: https://github.com/docker/metadata-action/compare/v4.6.0...v5.0.0

v4.6.0

Full Changelog: https://github.com/docker/metadata-action/compare/v4.5.0...v4.6.0

v4.5.0

Full Changelog: https://github.com/docker/metadata-action/compare/v4.4.0...v4.5.0

v4.4.0

Full Changelog: https://github.com/docker/metadata-action/compare/v4.3.0...v4.4.0

v4.3.0

Full Changelog: https://github.com/docker/metadata-action/compare/v4.2.0...v4.3.0

v4.2.0

  • Add tz attribute to handlebar date function by @​chroju (#251)
  • Bump minimatch from 3.0.4 to 3.1.2 (#242)
  • Bump csv-parse from 5.3.1 to 5.3.3 (#245)
  • Bump json5 from 2.2.0 to 2.2.3 (#252)

Full Changelog: https://github.com/docker/metadata-action/compare/v4.1.1...v4.2.0

v4.1.1

  • Revert changes to set associated head sha on pull request event by @​crazy-max (#239)
    • User can still set associated head sha on PR by setting the env var DOCKER_METADATA_PR_HEAD_SHA=true
  • Bump csv-parse from 5.3.0 to 5.3.1 (#237)

Full Changelog: https://github.com/docker/metadata-action/compare/v4.1.0...v4.1.1

... (truncated)

Upgrade guide

Sourced from docker/metadata-action's upgrade guide.

Upgrade notes

v2 to v3

  • Repository has been moved to docker org. Replace crazy-max/ghaction-docker-meta@v2 with docker/metadata-action@v5
  • The default bake target has been changed: ghaction-docker-meta > docker-metadata-action

v1 to v2

inputs

New Unchanged Removed
tags images tag-sha
flavor sep-tags tag-edge
labels sep-labels tag-edge-branch
tag-semver
tag-match
tag-match-group
tag-latest
tag-schedule
tag-custom
tag-custom-only
label-custom

tag-sha

tags: |
  type=sha

tag-edge / tag-edge-branch

tags: |
  # default branch
</tr></table>

... (truncated)

Commits
  • 96383f4 Merge pull request #320 from docker/dependabot/npm_and_yarn/csv-parse-5.5.0
  • f138b96 chore: update generated content
  • 9cf7015 Bump csv-parse from 5.4.0 to 5.5.0
  • 5a8a5ff Merge pull request #315 from docker/dependabot/npm_and_yarn/handlebars-4.7.8
  • 2279d9a chore: update generated content
  • c659933 Bump handlebars from 4.7.7 to 4.7.8
  • 48d23cc Merge pull request #333 from docker/dependabot/npm_and_yarn/actions/core-1.10.1
  • b83ffb4 chore: update generated content
  • 3207f24 Bump @​actions/core from 1.10.0 to 1.10.1
  • 63f4a26 Merge pull request #328 from crazy-max/update-node20
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=docker/metadata-action&package-manager=github_actions&previous-version=4&new-version=5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4e86ac8bf3776..0f96c302af9ab 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -541,7 +541,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ghcr.io/astral-sh/ruff From 779a5a9c322329a2ef3313f5625931218377b631 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 09:32:56 +0100 Subject: [PATCH 004/197] Bump actions/github-script from 6 to 7 (#8780) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/github-script](https://github.com/actions/github-script) from 6 to 7.
Release notes

Sourced from actions/github-script's releases.

v7.0.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/github-script/compare/v6.4.1...v7.0.0

v6.4.1

What's Changed

New Contributors

Full Changelog: https://github.com/actions/github-script/compare/v6.4.0...v6.4.1

v6.4.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/github-script/compare/v6.3.3...v6.4.0

v6.3.3

What's Changed

New Contributors

Full Changelog: https://github.com/actions/github-script/compare/v6.3.2...v6.3.3

v6.3.2

What's Changed

... (truncated)

Commits
  • 60a0d83 Merge pull request #440 from actions/joshmgross/v7.0.1
  • b7fb200 Update version to 7.0.1
  • 12e22ed Merge pull request #439 from actions/joshmgross/avoid-setting-base-url
  • d319f8f Avoid setting baseUrl to undefined when input is not provided
  • e69ef54 Merge pull request #425 from actions/joshmgross/node-20
  • ee0914b Update licenses
  • d6fc56f Use @types/node for Node 20
  • 384d6cf Fix quotations in tests
  • 8472492 Only validate GraphQL previews
  • 84903f5 Remove node-fetch from type
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/github-script&package-manager=github_actions&previous-version=6&new-version=7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0f96c302af9ab..2ec8ef052f0f5 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -580,7 +580,7 @@ jobs: needs: publish-release steps: - name: "Update pre-commit mirror" - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{ secrets.RUFF_PRE_COMMIT_PAT }} script: | From 0f2c9ab4d2c3a3656c35c9f0d1b4085b49db4f25 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 09:37:33 +0100 Subject: [PATCH 005/197] Bump uuid from 1.5.0 to 1.6.0 (#8783) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.5.0 to 1.6.0.
Release notes

Sourced from uuid's releases.

1.6.0

What's Changed

New Contributors

Full Changelog: https://github.com/uuid-rs/uuid/compare/1.5.0...1.6.0

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=uuid&package-manager=cargo&previous-version=1.5.0&new-version=1.6.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 18a152cbca0ee..95ecae9182976 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3367,9 +3367,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" +checksum = "c58fe91d841bc04822c9801002db4ea904b9e4b8e6bbad25127b46eff8dc516b" dependencies = [ "getrandom", "rand", @@ -3379,9 +3379,9 @@ dependencies = [ [[package]] name = "uuid-macro-internal" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d8c6bba9b149ee82950daefc9623b32bb1dacbfb1890e352f6b887bd582adaf" +checksum = "57fccbdae4ed44e1ea6c1aae832af19cd3487ee186953f721b46d1c441176050" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index c52264fe4b124..8fe8c6054fd71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } unicode-ident = { version = "1.0.12" } unicode_names2 = { version = "1.2.0" } unicode-width = { version = "0.1.11" } -uuid = { version = "1.5.0", features = ["v4", "fast-rng", "macro-diagnostics", "js"] } +uuid = { version = "1.6.0", features = ["v4", "fast-rng", "macro-diagnostics", "js"] } wsl = { version = "0.1.0" } [workspace.lints.rust] From f750257ef43d670cef157f7ae38082cbb4e6df6c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 09:43:17 +0100 Subject: [PATCH 006/197] Bump js-sys from 0.3.64 to 0.3.65 (#8781) Bumps [js-sys](https://github.com/rustwasm/wasm-bindgen) from 0.3.64 to 0.3.65.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=js-sys&package-manager=cargo&previous-version=0.3.64&new-version=0.3.65)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 24 ++++++++++++------------ crates/ruff_wasm/Cargo.toml | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 95ecae9182976..395a72d45d43f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1170,9 +1170,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -3460,9 +3460,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3470,9 +3470,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", @@ -3497,9 +3497,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3507,9 +3507,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", @@ -3520,9 +3520,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "wasm-bindgen-test" diff --git a/crates/ruff_wasm/Cargo.toml b/crates/ruff_wasm/Cargo.toml index d8884eb14a6a6..b1abff1d3fb4f 100644 --- a/crates/ruff_wasm/Cargo.toml +++ b/crates/ruff_wasm/Cargo.toml @@ -38,7 +38,7 @@ log = { workspace = true } serde = { workspace = true } serde-wasm-bindgen = { version = "0.6.1" } wasm-bindgen = { version = "0.2.84" } -js-sys = { version = "0.3.61" } +js-sys = { version = "0.3.65" } [dev-dependencies] wasm-bindgen-test = { version = "0.3.34" } From 29dc8b986ba48c018782436588cf5a1aa20d77fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 09:55:55 +0100 Subject: [PATCH 007/197] Bump tracing-subscriber from 0.3.17 to 0.3.18 (#8777) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [tracing-subscriber](https://github.com/tokio-rs/tracing) from 0.3.17 to 0.3.18.
Release notes

Sourced from tracing-subscriber's releases.

tracing-subscriber 0.3.18

This release of tracing-subscriber adds support for the NO_COLOR environment variable (an informal standard to disable emitting ANSI color escape codes) in fmt::Layer, reintroduces support for the chrono crate, and increases the minimum supported Rust version (MSRV) to Rust 1.63.0.

It also introduces several minor API improvements.

Added

  • chrono: Add chrono implementations of FormatTime (#2690)
  • subscriber: Add support for the NO_COLOR environment variable in fmt::Layer (#2647)
  • fmt: make format::Writer::new() public (#2680)
  • filter: Implement layer::Filter for Option<Filter> (#2407)

Changed

  • log: bump version of tracing-log to 0.2 (#2772)
  • Increased minimum supported Rust version (MSRV) to 1.63.0+.

#2690: tokio-rs/tracing#2690 #2647: tokio-rs/tracing#2647 #2680: tokio-rs/tracing#2680 #2407: tokio-rs/tracing#2407 #2772: tokio-rs/tracing#2772

Thanks to @​shayne-fletcher, @​dmlary, @​kaifastromai, and @​jsgf for contributing!

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tracing-subscriber&package-manager=cargo&previous-version=0.3.17&new-version=0.3.18)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 10 +++++----- Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 395a72d45d43f..cf6fc89c17b3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3194,20 +3194,20 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", diff --git a/Cargo.toml b/Cargo.toml index 8fe8c6054fd71..2a12303cd8d7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ thiserror = { version = "1.0.50" } toml = { version = "0.7.8" } tracing = { version = "0.1.40" } tracing-indicatif = { version = "0.3.4" } -tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } +tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } unicode-ident = { version = "1.0.12" } unicode_names2 = { version = "1.2.0" } unicode-width = { version = "0.1.11" } From 04f0625d23c95e5d635fda8a839de5960adf3b3e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 11:10:48 +0000 Subject: [PATCH 008/197] Bump codspeed-criterion-compat from 2.3.1 to 2.3.3 (#8784) --- Cargo.lock | 8 ++++---- crates/ruff_benchmark/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cf6fc89c17b3d..18464bcbec0a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -405,9 +405,9 @@ dependencies = [ [[package]] name = "codspeed" -version = "2.3.1" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "918b13a0f1a32460ab3bd5debd56b5a27a7071fa5ff5dfeb3a5cf291a85b174b" +checksum = "0eb4ab4dcb6554eb4f590fb16f99d3b102ab76f5f56554c9a5340518b32c499b" dependencies = [ "colored", "libc", @@ -416,9 +416,9 @@ dependencies = [ [[package]] name = "codspeed-criterion-compat" -version = "2.3.1" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c683c7fef2b873fbbdf4062782914c652309951244bf0bd362fe608b7d6f901c" +checksum = "cc07a3d3f7e0c8961d0ffdee149d39b231bafdcdc3d978dc5ad790c615f55f3f" dependencies = [ "codspeed", "colored", diff --git a/crates/ruff_benchmark/Cargo.toml b/crates/ruff_benchmark/Cargo.toml index 192add9fd92ac..96d3476da697c 100644 --- a/crates/ruff_benchmark/Cargo.toml +++ b/crates/ruff_benchmark/Cargo.toml @@ -37,7 +37,7 @@ serde_json.workspace = true url = "2.3.1" ureq = "2.8.0" criterion = { version = "0.5.1", default-features = false } -codspeed-criterion-compat = { version="2.3.1", default-features = false, optional = true} +codspeed-criterion-compat = { version="2.3.3", default-features = false, optional = true} [dev-dependencies] ruff_linter.path = "../ruff_linter" From 653e51ae97c17071a8fd21ed64e27c6dd9f78c6f Mon Sep 17 00:00:00 2001 From: Chaojie Date: Mon, 20 Nov 2023 20:21:12 +0800 Subject: [PATCH 009/197] [`flake8-bandit`] Implement `django-raw-sql` (`S611`) (#8651) See: https://github.com/astral-sh/ruff/issues/1646. --- .../test/fixtures/flake8_bandit/S611.py | 13 ++++ .../src/checkers/ast/analyze/expression.rs | 3 + crates/ruff_linter/src/codes.rs | 1 + .../src/rules/flake8_bandit/mod.rs | 1 + .../flake8_bandit/rules/django_raw_sql.rs | 58 ++++++++++++++++++ .../src/rules/flake8_bandit/rules/mod.rs | 2 + ...s__flake8_bandit__tests__S611_S611.py.snap | 60 +++++++++++++++++++ ruff.schema.json | 1 + 8 files changed, 139 insertions(+) create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S611.py create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/rules/django_raw_sql.rs create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S611_S611.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S611.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S611.py new file mode 100644 index 0000000000000..ee4230273582f --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S611.py @@ -0,0 +1,13 @@ +from django.db.models.expressions import RawSQL +from django.contrib.auth.models import User + +User.objects.annotate(val=RawSQL('secure', [])) +User.objects.annotate(val=RawSQL('%secure' % 'nos', [])) +User.objects.annotate(val=RawSQL('{}secure'.format('no'), [])) +raw = '"username") AS "val" FROM "auth_user" WHERE "username"="admin" --' +User.objects.annotate(val=RawSQL(raw, [])) +raw = '"username") AS "val" FROM "auth_user"' \ + ' WHERE "username"="admin" OR 1=%s --' +User.objects.annotate(val=RawSQL(raw, [0])) +User.objects.annotate(val=RawSQL(sql='{}secure'.format('no'), params=[])) +User.objects.annotate(val=RawSQL(params=[], sql='{}secure'.format('no'))) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 8ce687e0f6a73..313218cca2ded 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -612,6 +612,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { ]) { flake8_bandit::rules::shell_injection(checker, call); } + if checker.enabled(Rule::DjangoRawSql) { + flake8_bandit::rules::django_raw_sql(checker, call); + } if checker.enabled(Rule::UnnecessaryGeneratorList) { flake8_comprehensions::rules::unnecessary_generator_list( checker, expr, func, args, keywords, diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index 5e23a2e13887e..759ccc54ac49e 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -632,6 +632,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Flake8Bandit, "607") => (RuleGroup::Stable, rules::flake8_bandit::rules::StartProcessWithPartialPath), (Flake8Bandit, "608") => (RuleGroup::Stable, rules::flake8_bandit::rules::HardcodedSQLExpression), (Flake8Bandit, "609") => (RuleGroup::Stable, rules::flake8_bandit::rules::UnixCommandWildcardInjection), + (Flake8Bandit, "611") => (RuleGroup::Preview, rules::flake8_bandit::rules::DjangoRawSql), (Flake8Bandit, "612") => (RuleGroup::Stable, rules::flake8_bandit::rules::LoggingConfigInsecureListen), (Flake8Bandit, "701") => (RuleGroup::Stable, rules::flake8_bandit::rules::Jinja2AutoescapeFalse), (Flake8Bandit, "702") => (RuleGroup::Preview, rules::flake8_bandit::rules::MakoTemplates), diff --git a/crates/ruff_linter/src/rules/flake8_bandit/mod.rs b/crates/ruff_linter/src/rules/flake8_bandit/mod.rs index 3ad7a8e421b41..feb2dcb507651 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/mod.rs @@ -50,6 +50,7 @@ mod tests { #[test_case(Rule::UnixCommandWildcardInjection, Path::new("S609.py"))] #[test_case(Rule::UnsafeYAMLLoad, Path::new("S506.py"))] #[test_case(Rule::WeakCryptographicKey, Path::new("S505.py"))] + #[test_case(Rule::DjangoRawSql, Path::new("S611.py"))] fn rules(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/django_raw_sql.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/django_raw_sql.rs new file mode 100644 index 0000000000000..1491894d5b3ee --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/django_raw_sql.rs @@ -0,0 +1,58 @@ +use ruff_diagnostics::{Diagnostic, Violation}; +use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::{self as ast, Expr}; +use ruff_text_size::Ranged; + +use crate::checkers::ast::Checker; + +/// ## What it does +/// Checks for uses of Django's `RawSQL` function. +/// +/// ## Why is this bad? +/// Django's `RawSQL` function can be used to execute arbitrary SQL queries, +/// which can in turn lead to SQL injection vulnerabilities. +/// +/// ## Example +/// ```python +/// from django.db.models.expressions import RawSQL +/// from django.contrib.auth.models import User +/// +/// User.objects.annotate(val=("%secure" % "nos", [])) +/// ``` +/// +/// ## References +/// - [Django documentation: SQL injection protection](https://docs.djangoproject.com/en/dev/topics/security/#sql-injection-protection) +/// - [Common Weakness Enumeration: CWE-89](https://cwe.mitre.org/data/definitions/89.html) +#[violation] +pub struct DjangoRawSql; + +impl Violation for DjangoRawSql { + #[derive_message_formats] + fn message(&self) -> String { + format!("Use of `RawSQL` can lead to SQL injection vulnerabilities") + } +} + +/// S611 +pub(crate) fn django_raw_sql(checker: &mut Checker, call: &ast::ExprCall) { + if checker + .semantic() + .resolve_call_path(&call.func) + .is_some_and(|call_path| { + matches!( + call_path.as_slice(), + ["django", "db", "models", "expressions", "RawSQL"] + ) + }) + { + if !call + .arguments + .find_argument("sql", 0) + .is_some_and(Expr::is_string_literal_expr) + { + checker + .diagnostics + .push(Diagnostic::new(DjangoRawSql, call.func.range())); + } + } +} diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs index b1ebad53e41ca..b7a655366876f 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs @@ -1,5 +1,6 @@ pub(crate) use assert_used::*; pub(crate) use bad_file_permissions::*; +pub(crate) use django_raw_sql::*; pub(crate) use exec_used::*; pub(crate) use flask_debug_true::*; pub(crate) use hardcoded_bind_all_interfaces::*; @@ -27,6 +28,7 @@ pub(crate) use weak_cryptographic_key::*; mod assert_used; mod bad_file_permissions; +mod django_raw_sql; mod exec_used; mod flask_debug_true; mod hardcoded_bind_all_interfaces; diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S611_S611.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S611_S611.py.snap new file mode 100644 index 0000000000000..026360e756ff1 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S611_S611.py.snap @@ -0,0 +1,60 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S611.py:5:27: S611 Use of `RawSQL` can lead to SQL injection vulnerabilities + | +4 | User.objects.annotate(val=RawSQL('secure', [])) +5 | User.objects.annotate(val=RawSQL('%secure' % 'nos', [])) + | ^^^^^^ S611 +6 | User.objects.annotate(val=RawSQL('{}secure'.format('no'), [])) +7 | raw = '"username") AS "val" FROM "auth_user" WHERE "username"="admin" --' + | + +S611.py:6:27: S611 Use of `RawSQL` can lead to SQL injection vulnerabilities + | +4 | User.objects.annotate(val=RawSQL('secure', [])) +5 | User.objects.annotate(val=RawSQL('%secure' % 'nos', [])) +6 | User.objects.annotate(val=RawSQL('{}secure'.format('no'), [])) + | ^^^^^^ S611 +7 | raw = '"username") AS "val" FROM "auth_user" WHERE "username"="admin" --' +8 | User.objects.annotate(val=RawSQL(raw, [])) + | + +S611.py:8:27: S611 Use of `RawSQL` can lead to SQL injection vulnerabilities + | + 6 | User.objects.annotate(val=RawSQL('{}secure'.format('no'), [])) + 7 | raw = '"username") AS "val" FROM "auth_user" WHERE "username"="admin" --' + 8 | User.objects.annotate(val=RawSQL(raw, [])) + | ^^^^^^ S611 + 9 | raw = '"username") AS "val" FROM "auth_user"' \ +10 | ' WHERE "username"="admin" OR 1=%s --' + | + +S611.py:11:27: S611 Use of `RawSQL` can lead to SQL injection vulnerabilities + | + 9 | raw = '"username") AS "val" FROM "auth_user"' \ +10 | ' WHERE "username"="admin" OR 1=%s --' +11 | User.objects.annotate(val=RawSQL(raw, [0])) + | ^^^^^^ S611 +12 | User.objects.annotate(val=RawSQL(sql='{}secure'.format('no'), params=[])) +13 | User.objects.annotate(val=RawSQL(params=[], sql='{}secure'.format('no'))) + | + +S611.py:12:27: S611 Use of `RawSQL` can lead to SQL injection vulnerabilities + | +10 | ' WHERE "username"="admin" OR 1=%s --' +11 | User.objects.annotate(val=RawSQL(raw, [0])) +12 | User.objects.annotate(val=RawSQL(sql='{}secure'.format('no'), params=[])) + | ^^^^^^ S611 +13 | User.objects.annotate(val=RawSQL(params=[], sql='{}secure'.format('no'))) + | + +S611.py:13:27: S611 Use of `RawSQL` can lead to SQL injection vulnerabilities + | +11 | User.objects.annotate(val=RawSQL(raw, [0])) +12 | User.objects.annotate(val=RawSQL(sql='{}secure'.format('no'), params=[])) +13 | User.objects.annotate(val=RawSQL(params=[], sql='{}secure'.format('no'))) + | ^^^^^^ S611 + | + + diff --git a/ruff.schema.json b/ruff.schema.json index a3c30890c6f16..8ac638a4c11d1 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -3396,6 +3396,7 @@ "S608", "S609", "S61", + "S611", "S612", "S7", "S70", From 10d937c1a17854a253643d837abd47f1da0c2309 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 20 Nov 2023 04:28:52 -0800 Subject: [PATCH 010/197] [`pep8-naming`] Avoid `N806` errors for type alias statements (#8785) Allow, e.g.: ```python def func(): type MyInt = int ``` (We already allowed `MyInt: TypeAlias = int`.) Closes https://github.com/astral-sh/ruff/issues/8773. --- .../resources/test/fixtures/pep8_naming/N806.py | 2 ++ crates/ruff_linter/src/rules/pep8_naming/helpers.rs | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py b/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py index 0a9a95954c73c..e509a27e12bc5 100644 --- a/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py +++ b/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py @@ -25,6 +25,8 @@ def assign(): IntOrStr: TypeAlias = int | str + type MyInt = int + def aug_assign(rank, world_size): global CURRENT_PORT diff --git a/crates/ruff_linter/src/rules/pep8_naming/helpers.rs b/crates/ruff_linter/src/rules/pep8_naming/helpers.rs index 6d09971253201..24fcb6d92dbb3 100644 --- a/crates/ruff_linter/src/rules/pep8_naming/helpers.rs +++ b/crates/ruff_linter/src/rules/pep8_naming/helpers.rs @@ -63,10 +63,13 @@ pub(super) fn is_type_var_assignment(stmt: &Stmt, semantic: &SemanticModel) -> b /// Returns `true` if the statement is an assignment to a `TypeAlias`. pub(super) fn is_type_alias_assignment(stmt: &Stmt, semantic: &SemanticModel) -> bool { - let Stmt::AnnAssign(ast::StmtAnnAssign { annotation, .. }) = stmt else { - return false; - }; - semantic.match_typing_expr(annotation, "TypeAlias") + match stmt { + Stmt::AnnAssign(ast::StmtAnnAssign { annotation, .. }) => { + semantic.match_typing_expr(annotation, "TypeAlias") + } + Stmt::TypeAlias(_) => true, + _ => false, + } } pub(super) fn is_typed_dict_class(arguments: Option<&Arguments>, semantic: &SemanticModel) -> bool { From aec80dc3abc602375c0218a2500f6ade192fab9b Mon Sep 17 00:00:00 2001 From: T-256 <132141463+T-256@users.noreply.github.com> Date: Mon, 20 Nov 2023 21:51:51 +0330 Subject: [PATCH 011/197] Ruff ecosystem: pass no-preview cli arg by default (#8775) Addresses https://github.com/astral-sh/ruff/pull/8489#issuecomment-1793513411 That issues still exist on formatter, but since `black` doesn't support `no-preview` cli arg, I didn't include it in this PR. --------- Co-authored-by: Zanie --- .github/workflows/ci.yaml | 2 ++ python/ruff-ecosystem/ruff_ecosystem/projects.py | 13 +++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 07281de43f486..3f8c3d3a1a15c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -44,6 +44,7 @@ jobs: - "!crates/ruff_shrinking/**" - scripts/* - .github/workflows/ci.yaml + - python/** formatter: - Cargo.toml @@ -58,6 +59,7 @@ jobs: - crates/ruff_python_parser/** - crates/ruff_dev/** - scripts/* + - python/** - .github/workflows/ci.yaml cargo-fmt: diff --git a/python/ruff-ecosystem/ruff_ecosystem/projects.py b/python/ruff-ecosystem/ruff_ecosystem/projects.py index d4764c34bf040..d4fb64e804ed9 100644 --- a/python/ruff-ecosystem/ruff_ecosystem/projects.py +++ b/python/ruff-ecosystem/ruff_ecosystem/projects.py @@ -71,7 +71,12 @@ class CheckOptions(CommandOptions): max_lines_per_rule: int | None = 50 def to_ruff_args(self) -> list[str]: - args = ["check", "--no-cache", "--exit-zero"] + args = [ + "check", + "--no-cache", + "--exit-zero", + f"--{'' if self.preview else 'no-'}preview", + ] if self.select: args.extend(["--select", self.select]) if self.ignore: @@ -80,8 +85,6 @@ def to_ruff_args(self) -> list[str]: args.extend(["--exclude", self.exclude]) if self.show_fixes: args.extend(["--show-fixes", "--ecosystem-ci"]) - if self.preview: - args.append("--preview") return args @@ -95,11 +98,9 @@ class FormatOptions(CommandOptions): exclude: str = "" def to_ruff_args(self) -> list[str]: - args = ["format"] + args = ["format", f"--{'' if self.preview else 'no-'}preview"] if self.exclude: args.extend(["--exclude", self.exclude]) - if self.preview: - args.append("--preview") return args def to_black_args(self) -> list[str]: From e30635941140a3ad9418f3b940a8f5507ddb7f1a Mon Sep 17 00:00:00 2001 From: Iipin <52832022+Iipin@users.noreply.github.com> Date: Mon, 20 Nov 2023 20:29:48 +0100 Subject: [PATCH 012/197] Mark `pydantic_settings.BaseSettings` as having default copy semantics (#8793) ## Summary In 2.0, Pydantic has moved the `BaseSettings` class to a separate package called `pydantic-settings` (https://docs.pydantic.dev/2.4/migration/#basesettings-has-moved-to-pydantic-settings), which results in a false positive on `RUF012` (`mutable-class-default`). A simple fix for that would be adding `pydantic_settings.BaseSettings` base to the `has_default_copy_semantics` helper, which I've done in this PR. Related issue: #5308 ## Test Plan `cargo test` --- .../resources/test/fixtures/ruff/RUF012.py | 11 +++++++++++ crates/ruff_linter/src/rules/ruff/rules/helpers.rs | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF012.py b/crates/ruff_linter/resources/test/fixtures/ruff/RUF012.py index ef58e45df1cb4..aa9d54d8b7bdd 100644 --- a/crates/ruff_linter/resources/test/fixtures/ruff/RUF012.py +++ b/crates/ruff_linter/resources/test/fixtures/ruff/RUF012.py @@ -48,3 +48,14 @@ class E(Struct): without_annotation = [] class_variable: ClassVar[list[int]] = [] final_variable: Final[list[int]] = [] + + +from pydantic_settings import BaseSettings + + +class F(BaseSettings): + mutable_default: list[int] = [] + immutable_annotation: Sequence[int] = [] + without_annotation = [] + class_variable: ClassVar[list[int]] = [] + final_variable: Final[list[int]] = [] diff --git a/crates/ruff_linter/src/rules/ruff/rules/helpers.rs b/crates/ruff_linter/src/rules/ruff/rules/helpers.rs index 78caf8d18fb5d..6cf01db9db998 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/helpers.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/helpers.rs @@ -65,7 +65,9 @@ pub(super) fn has_default_copy_semantics( semantic.resolve_call_path(expr).is_some_and(|call_path| { matches!( call_path.as_slice(), - ["pydantic", "BaseModel" | "BaseSettings"] | ["msgspec", "Struct"] + ["pydantic", "BaseModel" | "BaseSettings"] + | ["pydantic_settings", "BaseSettings"] + | ["msgspec", "Struct"] ) }) }) From 6ca2aaa245ca9f298c3d7e59c89d4fb2432dd951 Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Tue, 21 Nov 2023 19:37:18 +0800 Subject: [PATCH 013/197] Update Arch Linux package URL in installation.md (#8802) The old URL returns 404 now. --- docs/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 919289d14b854..a822bdf4b0230 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -27,7 +27,7 @@ For **Conda** users, Ruff is also available as [`ruff`](https://anaconda.org/con conda install -c conda-forge ruff ``` -For **Arch Linux** users, Ruff is also available as [`ruff`](https://archlinux.org/packages/community/x86_64/ruff/) +For **Arch Linux** users, Ruff is also available as [`ruff`](https://archlinux.org/packages/extra/x86_64/ruff/) on the official repositories: ```shell From bf729e7a773428daf1dbc8900593b26ee972fc3e Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Wed, 22 Nov 2023 00:52:28 +1300 Subject: [PATCH 014/197] fix: mark `__main__` as first-party import (#8805) ## Summary Fixes #8750. `import __main__` is now considered a first-party import, and is grouped accordingly by the linter and formatter. ## Test Plan Added a test based off code supplied in the linked issue. --- .../test/fixtures/isort/main_first_party.py | 11 +++++++ .../ruff_linter/src/rules/isort/categorize.rs | 5 +++ crates/ruff_linter/src/rules/isort/mod.rs | 24 ++++++++++++++ ...__tests__sections_main_first_party.py.snap | 31 +++++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 crates/ruff_linter/resources/test/fixtures/isort/main_first_party.py create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__sections_main_first_party.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/isort/main_first_party.py b/crates/ruff_linter/resources/test/fixtures/isort/main_first_party.py new file mode 100644 index 0000000000000..ba224527c3b9a --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/isort/main_first_party.py @@ -0,0 +1,11 @@ +import os + +import __main__ +import third_party + +import first_party + +os.a +third_party.a +__main__.a +first_party.a diff --git a/crates/ruff_linter/src/rules/isort/categorize.rs b/crates/ruff_linter/src/rules/isort/categorize.rs index 6c086bfb2f7e2..8ab090645ab62 100644 --- a/crates/ruff_linter/src/rules/isort/categorize.rs +++ b/crates/ruff_linter/src/rules/isort/categorize.rs @@ -106,6 +106,11 @@ pub(crate) fn categorize<'a>( &ImportSection::Known(ImportType::FirstParty), Reason::SourceMatch(src), ) + } else if matches!(level, None | Some(0)) && module_name == "__main__" { + ( + &ImportSection::Known(ImportType::FirstParty), + Reason::KnownFirstParty, + ) } else { ( &ImportSection::Known(ImportType::ThirdParty), diff --git a/crates/ruff_linter/src/rules/isort/mod.rs b/crates/ruff_linter/src/rules/isort/mod.rs index 73380ca4eefd0..10a3f7b1d974a 100644 --- a/crates/ruff_linter/src/rules/isort/mod.rs +++ b/crates/ruff_linter/src/rules/isort/mod.rs @@ -1033,6 +1033,30 @@ mod tests { Ok(()) } + #[test_case(Path::new("main_first_party.py"))] + fn main_is_first_party(path: &Path) -> Result<()> { + let snapshot = format!("sections_{}", path.to_string_lossy()); + let diagnostics = test_path( + Path::new("isort").join(path).as_path(), + &LinterSettings { + src: vec![test_resource_path("fixtures/isort")], + isort: super::settings::Settings { + known_modules: KnownModules::new( + vec![pattern("first_party")], + vec![], + vec![], + vec![], + FxHashMap::default(), + ), + ..super::settings::Settings::default() + }, + ..LinterSettings::for_rule(Rule::UnsortedImports) + }, + )?; + assert_messages!(snapshot, diagnostics); + Ok(()) + } + #[test] fn detect_same_package() -> Result<()> { let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__sections_main_first_party.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__sections_main_first_party.py.snap new file mode 100644 index 0000000000000..404ad962cb670 --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__sections_main_first_party.py.snap @@ -0,0 +1,31 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- +main_first_party.py:1:1: I001 [*] Import block is un-sorted or un-formatted + | + 1 | / import os + 2 | | + 3 | | import __main__ + 4 | | import third_party + 5 | | + 6 | | import first_party + 7 | | + 8 | | os.a + | |_^ I001 + 9 | third_party.a +10 | __main__.a + | + = help: Organize imports + +ℹ Safe fix +1 1 | import os +2 2 | +3 |-import __main__ +4 3 | import third_party +5 4 | + 5 |+import __main__ +6 6 | import first_party +7 7 | +8 8 | os.a + + From 6fb64788877908799d0f614d83839693f4d0e082 Mon Sep 17 00:00:00 2001 From: maltevesper Date: Wed, 22 Nov 2023 00:53:42 +1300 Subject: [PATCH 015/197] [`flake8-simplify`] Omit select context managers from `SIM117` (#8801) Semantically it makes sense to put certain contextmanagers into separate with statements. Currently asyncio.timeout and its relatives in anyio and trio are exempt from SIM117. Closes https://github.com/astral-sh/ruff/issues/8606 ## Summary Exempt asyncio.timeout and related functions from SIM117 (Collapse with statements where possible). See https://github.com/astral-sh/ruff/issues/8606 for more. ## Test Plan Extended the insta tests. --- .../test/fixtures/flake8_simplify/SIM117.py | 29 ++++++++++++ .../rules/flake8_simplify/rules/ast_with.rs | 44 +++++++++++++++++++ ...ke8_simplify__tests__SIM117_SIM117.py.snap | 23 ++++++++++ 3 files changed, 96 insertions(+) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM117.py b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM117.py index c3c64044a2aac..43c8c8a12b4ab 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM117.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM117.py @@ -134,3 +134,32 @@ def method1(self) -> T: f" something { my_dict["key"] } something else " f"foo {f"bar {x}"} baz" + +# Allow cascading for some statements. +import anyio +import asyncio +import trio + +async with asyncio.timeout(1): + async with A() as a: + pass + +async with A(): + async with asyncio.timeout(1): + pass + +async with asyncio.timeout(1): + async with asyncio.timeout_at(1): + async with anyio.CancelScope(): + async with anyio.fail_after(1): + async with anyio.move_on_after(1): + async with trio.fail_after(1): + async with trio.fail_at(1): + async with trio.move_on_after(1): + async with trio.move_on_at(1): + pass + +# Do not supress combination, if a context manager is already combined with another. +async with asyncio.timeout(1), A(): + async with B(): + pass diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_with.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_with.rs index e3dedd26a477c..fd1afd9d468db 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_with.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_with.rs @@ -1,3 +1,4 @@ +use ast::Expr; use log::error; use ruff_diagnostics::{Diagnostic, Fix}; @@ -24,6 +25,13 @@ use super::fix_with; /// will minimize the indentation depth of the code, making it more /// readable. /// +/// The following context managers are exempt when used as standalone +/// statements: +/// +/// - `anyio`.{`CancelScope`, `fail_after`, `move_on_after`} +/// - `asyncio`.{`timeout`, `timeout_at`} +/// - `trio`.{`fail_after`, `fail_at`, `move_on_after`, `move_on_at`} +/// /// ## Example /// ```python /// with A() as a: @@ -73,6 +81,38 @@ fn next_with(body: &[Stmt]) -> Option<(bool, &[WithItem], &[Stmt])> { Some((*is_async, items, body)) } +/// Check if `with_items` contains a single item which should not necessarily be +/// grouped with other items. +/// +/// For example: +/// ```python +/// async with asyncio.timeout(1): +/// with resource1(), resource2(): +/// ... +/// ``` +fn explicit_with_items(checker: &mut Checker, with_items: &[WithItem]) -> bool { + let [with_item] = with_items else { + return false; + }; + let Expr::Call(expr_call) = &with_item.context_expr else { + return false; + }; + checker + .semantic() + .resolve_call_path(&expr_call.func) + .is_some_and(|call_path| { + matches!( + call_path.as_slice(), + ["asyncio", "timeout" | "timeout_at"] + | ["anyio", "CancelScope" | "fail_after" | "move_on_after"] + | [ + "trio", + "fail_after" | "fail_at" | "move_on_after" | "move_on_at" + ] + ) + }) +} + /// SIM117 pub(crate) fn multiple_with_statements( checker: &mut Checker, @@ -111,6 +151,10 @@ pub(crate) fn multiple_with_statements( return; } + if explicit_with_items(checker, &with_stmt.items) || explicit_with_items(checker, items) { + return; + } + let Some(colon) = items.last().and_then(|item| { SimpleTokenizer::starts_at(item.end(), checker.locator().contents()) .skip_trivia() diff --git a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM117_SIM117.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM117_SIM117.py.snap index 5b71ad0883a2a..21af88e707913 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM117_SIM117.py.snap +++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM117_SIM117.py.snap @@ -316,5 +316,28 @@ SIM117.py:126:1: SIM117 [*] Use a single `with` statement with multiple contexts 135 134 | 136 |- f"foo {f"bar {x}"} baz" 135 |+ f"foo {f"bar {x}"} baz" +137 136 | +138 137 | # Allow cascading for some statements. +139 138 | import anyio + +SIM117.py:163:1: SIM117 [*] Use a single `with` statement with multiple contexts instead of nested `with` statements + | +162 | # Do not supress combination, if a context manager is already combined with another. +163 | / async with asyncio.timeout(1), A(): +164 | | async with B(): + | |___________________^ SIM117 +165 | pass + | + = help: Combine `with` statements + +ℹ Unsafe fix +160 160 | pass +161 161 | +162 162 | # Do not supress combination, if a context manager is already combined with another. +163 |-async with asyncio.timeout(1), A(): +164 |- async with B(): +165 |- pass + 163 |+async with asyncio.timeout(1), A(), B(): + 164 |+ pass From b61ce7fa46979dc2ecc138fa9bfff8e82bc2bbf7 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 21 Nov 2023 11:59:22 +0000 Subject: [PATCH 016/197] Replace generated reference to MkDocs (#8806) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6f940ce73b91d..2d4ecb9b449fb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -295,7 +295,7 @@ To preview any changes to the documentation locally: ```shell # For contributors. - mkdocs serve -f mkdocs.generated.yml + mkdocs serve -f mkdocs.public.yml # For members of the Astral org, which has access to MkDocs Insiders via sponsorship. mkdocs serve -f mkdocs.insiders.yml From d9151b1948ff4ea4e5ab764c58388d1477ca5aa5 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Tue, 21 Nov 2023 11:34:21 -0600 Subject: [PATCH 017/197] Update `ruff check` and `ruff format` to default to the current directory (#8791) Closes https://github.com/astral-sh/ruff/issues/7347 Closes #3970 via use of `include` We could update examples in our documentation, but I worry since we do not have versioned documentation users on older versions would be confused. Instead, I'll open an issue to track updating use of `ruff check .` in the documentation sometime in the future. --- .../resources/test/fixtures/include-test/a.py | 0 .../resources/test/fixtures/include-test/b.py | 0 .../fixtures/include-test/nested-project/e.py | 0 .../nested-project/pyproject.toml | 2 + .../test/fixtures/include-test/pyproject.toml | 2 + .../fixtures/include-test/subdirectory/c.py | 0 .../fixtures/include-test/subdirectory/d.py | 0 crates/ruff_cli/src/args.rs | 2 + crates/ruff_cli/src/commands/format.rs | 9 +- crates/ruff_cli/src/lib.rs | 40 ++++--- crates/ruff_cli/tests/format.rs | 47 ++++++++ crates/ruff_cli/tests/integration_test.rs | 52 +++++++++ crates/ruff_cli/tests/resolve_files.rs | 101 ++++++++++++++++++ docs/configuration.md | 45 +++++++- docs/formatter.md | 4 + docs/linter.md | 4 + 16 files changed, 286 insertions(+), 22 deletions(-) create mode 100644 crates/ruff_cli/resources/test/fixtures/include-test/a.py create mode 100644 crates/ruff_cli/resources/test/fixtures/include-test/b.py create mode 100644 crates/ruff_cli/resources/test/fixtures/include-test/nested-project/e.py create mode 100644 crates/ruff_cli/resources/test/fixtures/include-test/nested-project/pyproject.toml create mode 100644 crates/ruff_cli/resources/test/fixtures/include-test/pyproject.toml create mode 100644 crates/ruff_cli/resources/test/fixtures/include-test/subdirectory/c.py create mode 100644 crates/ruff_cli/resources/test/fixtures/include-test/subdirectory/d.py create mode 100644 crates/ruff_cli/tests/resolve_files.rs diff --git a/crates/ruff_cli/resources/test/fixtures/include-test/a.py b/crates/ruff_cli/resources/test/fixtures/include-test/a.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/crates/ruff_cli/resources/test/fixtures/include-test/b.py b/crates/ruff_cli/resources/test/fixtures/include-test/b.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/crates/ruff_cli/resources/test/fixtures/include-test/nested-project/e.py b/crates/ruff_cli/resources/test/fixtures/include-test/nested-project/e.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/crates/ruff_cli/resources/test/fixtures/include-test/nested-project/pyproject.toml b/crates/ruff_cli/resources/test/fixtures/include-test/nested-project/pyproject.toml new file mode 100644 index 0000000000000..acbc6447e5fad --- /dev/null +++ b/crates/ruff_cli/resources/test/fixtures/include-test/nested-project/pyproject.toml @@ -0,0 +1,2 @@ +[tool.ruff] +select = [] diff --git a/crates/ruff_cli/resources/test/fixtures/include-test/pyproject.toml b/crates/ruff_cli/resources/test/fixtures/include-test/pyproject.toml new file mode 100644 index 0000000000000..fadb2359fba35 --- /dev/null +++ b/crates/ruff_cli/resources/test/fixtures/include-test/pyproject.toml @@ -0,0 +1,2 @@ +[tool.ruff] +include = ["a.py", "subdirectory/c.py"] \ No newline at end of file diff --git a/crates/ruff_cli/resources/test/fixtures/include-test/subdirectory/c.py b/crates/ruff_cli/resources/test/fixtures/include-test/subdirectory/c.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/crates/ruff_cli/resources/test/fixtures/include-test/subdirectory/d.py b/crates/ruff_cli/resources/test/fixtures/include-test/subdirectory/d.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/crates/ruff_cli/src/args.rs b/crates/ruff_cli/src/args.rs index d14c0a965870c..6c5ed14456ab9 100644 --- a/crates/ruff_cli/src/args.rs +++ b/crates/ruff_cli/src/args.rs @@ -88,6 +88,7 @@ pub enum Command { #[allow(clippy::struct_excessive_bools)] pub struct CheckCommand { /// List of files or directories to check. + #[clap(help = "List of files or directories to check [default: .]")] pub files: Vec, /// Apply fixes to resolve lint violations. /// Use `--no-fix` to disable or `--unsafe-fixes` to include unsafe fixes. @@ -363,6 +364,7 @@ pub struct CheckCommand { #[allow(clippy::struct_excessive_bools)] pub struct FormatCommand { /// List of files or directories to format. + #[clap(help = "List of files or directories to format [default: .]")] pub files: Vec, /// Avoid writing any formatted files back; instead, exit with a non-zero status code if any /// files would have been modified, and zero otherwise. diff --git a/crates/ruff_cli/src/commands/format.rs b/crates/ruff_cli/src/commands/format.rs index 1b2e431b8ecb4..697c412163cf8 100644 --- a/crates/ruff_cli/src/commands/format.rs +++ b/crates/ruff_cli/src/commands/format.rs @@ -34,7 +34,7 @@ use crate::args::{CliOverrides, FormatArguments}; use crate::cache::{Cache, FileCacheKey, PackageCacheMap, PackageCaches}; use crate::panic::{catch_unwind, PanicError}; use crate::resolve::resolve; -use crate::ExitStatus; +use crate::{resolve_default_files, ExitStatus}; #[derive(Debug, Copy, Clone, is_macro::Is)] pub(crate) enum FormatMode { @@ -60,7 +60,7 @@ impl FormatMode { /// Format a set of files, and return the exit status. pub(crate) fn format( - cli: &FormatArguments, + cli: FormatArguments, overrides: &CliOverrides, log_level: LogLevel, ) -> Result { @@ -70,8 +70,9 @@ pub(crate) fn format( overrides, cli.stdin_filename.as_deref(), )?; - let mode = FormatMode::from_cli(cli); - let (paths, resolver) = python_files_in_path(&cli.files, &pyproject_config, overrides)?; + let mode = FormatMode::from_cli(&cli); + let files = resolve_default_files(cli.files, false); + let (paths, resolver) = python_files_in_path(&files, &pyproject_config, overrides)?; if paths.is_empty() { warn_user_once!("No Python files found under the given path(s)"); diff --git a/crates/ruff_cli/src/lib.rs b/crates/ruff_cli/src/lib.rs index 4cb0db0c8bb9e..f8f99505b3c91 100644 --- a/crates/ruff_cli/src/lib.rs +++ b/crates/ruff_cli/src/lib.rs @@ -101,6 +101,19 @@ fn is_stdin(files: &[PathBuf], stdin_filename: Option<&Path>) -> bool { file == Path::new("-") } +/// Returns the default set of files if none are provided, otherwise returns `None`. +fn resolve_default_files(files: Vec, is_stdin: bool) -> Vec { + if files.is_empty() { + if is_stdin { + vec![Path::new("-").to_path_buf()] + } else { + vec![Path::new(".").to_path_buf()] + } + } else { + files + } +} + /// Get the actual value of the `format` desired from either `output_format` /// or `format`, and warn the user if they're using the deprecated form. fn resolve_help_output_format(output_format: HelpFormat, format: Option) -> HelpFormat { @@ -196,7 +209,7 @@ fn format(args: FormatCommand, log_level: LogLevel) -> Result { if is_stdin(&cli.files, cli.stdin_filename.as_deref()) { commands::format_stdin::format_stdin(&cli, &overrides) } else { - commands::format::format(&cli, &overrides, log_level) + commands::format::format(cli, &overrides, log_level) } } @@ -222,17 +235,15 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result { }; let stderr_writer = Box::new(BufWriter::new(io::stderr())); + let is_stdin = is_stdin(&cli.files, cli.stdin_filename.as_deref()); + let files = resolve_default_files(cli.files, is_stdin); + if cli.show_settings { - commands::show_settings::show_settings( - &cli.files, - &pyproject_config, - &overrides, - &mut writer, - )?; + commands::show_settings::show_settings(&files, &pyproject_config, &overrides, &mut writer)?; return Ok(ExitStatus::Success); } if cli.show_files { - commands::show_files::show_files(&cli.files, &pyproject_config, &overrides, &mut writer)?; + commands::show_files::show_files(&files, &pyproject_config, &overrides, &mut writer)?; return Ok(ExitStatus::Success); } @@ -295,8 +306,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result { if !fix_mode.is_generate() { warn_user!("--fix is incompatible with --add-noqa."); } - let modifications = - commands::add_noqa::add_noqa(&cli.files, &pyproject_config, &overrides)?; + let modifications = commands::add_noqa::add_noqa(&files, &pyproject_config, &overrides)?; if modifications > 0 && log_level >= LogLevel::Default { let s = if modifications == 1 { "" } else { "s" }; #[allow(clippy::print_stderr)] @@ -323,7 +333,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result { // Configure the file watcher. let (tx, rx) = channel(); let mut watcher = recommended_watcher(tx)?; - for file in &cli.files { + for file in &files { watcher.watch(file, RecursiveMode::Recursive)?; } if let Some(file) = pyproject_config.path.as_ref() { @@ -335,7 +345,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result { printer.write_to_user("Starting linter in watch mode...\n"); let messages = commands::check::check( - &cli.files, + &files, &pyproject_config, &overrides, cache.into(), @@ -368,7 +378,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result { printer.write_to_user("File change detected...\n"); let messages = commands::check::check( - &cli.files, + &files, &pyproject_config, &overrides, cache.into(), @@ -382,8 +392,6 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result { } } } else { - let is_stdin = is_stdin(&cli.files, cli.stdin_filename.as_deref()); - // Generate lint violations. let diagnostics = if is_stdin { commands::check_stdin::check_stdin( @@ -395,7 +403,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result { )? } else { commands::check::check( - &cli.files, + &files, &pyproject_config, &overrides, cache.into(), diff --git a/crates/ruff_cli/tests/format.rs b/crates/ruff_cli/tests/format.rs index c5c399563330a..79a7cf942d6b2 100644 --- a/crates/ruff_cli/tests/format.rs +++ b/crates/ruff_cli/tests/format.rs @@ -43,6 +43,53 @@ if condition: "###); } +#[test] +fn default_files() -> Result<()> { + let tempdir = TempDir::new()?; + fs::write( + tempdir.path().join("foo.py"), + r#" +foo = "needs formatting" +"#, + )?; + fs::write( + tempdir.path().join("bar.py"), + r#" +bar = "needs formatting" +"#, + )?; + + assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) + .args(["format", "--isolated", "--no-cache", "--check"]).current_dir(tempdir.path()), @r###" + success: false + exit_code: 1 + ----- stdout ----- + Would reformat: bar.py + Would reformat: foo.py + 2 files would be reformatted + + ----- stderr ----- + "###); + + Ok(()) +} + +#[test] +fn format_warn_stdin_filename_with_files() { + assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) + .args(["format", "--stdin-filename", "foo.py"]) + .arg("foo.py") + .pass_stdin("foo = 1"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + foo = 1 + + ----- stderr ----- + warning: Ignoring file foo.py in favor of standard input. + "###); +} + #[test] fn format_options() -> Result<()> { let tempdir = TempDir::new()?; diff --git a/crates/ruff_cli/tests/integration_test.rs b/crates/ruff_cli/tests/integration_test.rs index 59c372aac1806..bcba6b255bc14 100644 --- a/crates/ruff_cli/tests/integration_test.rs +++ b/crates/ruff_cli/tests/integration_test.rs @@ -74,6 +74,57 @@ fn stdin_filename() { "###); } +#[test] +fn check_default_files() -> Result<()> { + let tempdir = TempDir::new()?; + fs::write( + tempdir.path().join("foo.py"), + r#" +import foo # unused import +"#, + )?; + fs::write( + tempdir.path().join("bar.py"), + r#" +import bar # unused import +"#, + )?; + + assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) + .args(["check", "--isolated", "--no-cache", "--select", "F401"]).current_dir(tempdir.path()), @r###" + success: false + exit_code: 1 + ----- stdout ----- + bar.py:2:8: F401 [*] `bar` imported but unused + foo.py:2:8: F401 [*] `foo` imported but unused + Found 2 errors. + [*] 2 fixable with the `--fix` option. + + ----- stderr ----- + "###); + + Ok(()) +} + +#[test] +fn check_warn_stdin_filename_with_files() { + assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) + .args(STDIN_BASE_OPTIONS) + .args(["--stdin-filename", "F401.py"]) + .arg("foo.py") + .pass_stdin("import os\n"), @r###" + success: false + exit_code: 1 + ----- stdout ----- + F401.py:1:8: F401 [*] `os` imported but unused + Found 1 error. + [*] 1 fixable with the `--fix` option. + + ----- stderr ----- + warning: Ignoring file foo.py in favor of standard input. + "###); +} + /// Raise `TCH` errors in `.py` files ... #[test] fn stdin_source_type_py() { @@ -320,6 +371,7 @@ fn stdin_fix_jupyter() { Found 2 errors (2 fixed, 0 remaining). "###); } + #[test] fn stdin_override_parser_ipynb() { let args = ["--extension", "py:ipynb", "--stdin-filename", "Jupyter.py"]; diff --git a/crates/ruff_cli/tests/resolve_files.rs b/crates/ruff_cli/tests/resolve_files.rs new file mode 100644 index 0000000000000..b9f75a8760b2a --- /dev/null +++ b/crates/ruff_cli/tests/resolve_files.rs @@ -0,0 +1,101 @@ +#![cfg(not(target_family = "wasm"))] + +use std::path::Path; +use std::process::Command; +use std::str; + +use insta_cmd::{assert_cmd_snapshot, get_cargo_bin}; +const BIN_NAME: &str = "ruff"; + +#[cfg(not(target_os = "windows"))] +const TEST_FILTERS: &[(&str, &str)] = &[(".*/resources/test/fixtures/", "[BASEPATH]/")]; +#[cfg(target_os = "windows")] +const TEST_FILTERS: &[(&str, &str)] = &[ + (r".*\\resources\\test\\fixtures\\", "[BASEPATH]\\"), + (r"\\", "/"), +]; + +#[test] +fn check_project_include_defaults() { + // Defaults to checking the current working directory + // + // The test directory includes: + // - A pyproject.toml which specifies an include + // - A nested pyproject.toml which has a Ruff section + // + // The nested project should all be checked instead of respecting the parent includes + + insta::with_settings!({ + filters => TEST_FILTERS.to_vec() + }, { + assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) + .args(["check", "--show-files"]).current_dir(Path::new("./resources/test/fixtures/include-test")), @r###" + success: true + exit_code: 0 + ----- stdout ----- + [BASEPATH]/include-test/a.py + [BASEPATH]/include-test/nested-project/e.py + [BASEPATH]/include-test/nested-project/pyproject.toml + [BASEPATH]/include-test/subdirectory/c.py + + ----- stderr ----- + "###); + }); +} + +#[test] +fn check_project_respects_direct_paths() { + // Given a direct path not included in the project `includes`, it should be checked + + insta::with_settings!({ + filters => TEST_FILTERS.to_vec() + }, { + assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) + .args(["check", "--show-files", "b.py"]).current_dir(Path::new("./resources/test/fixtures/include-test")), @r###" + success: true + exit_code: 0 + ----- stdout ----- + [BASEPATH]/include-test/b.py + + ----- stderr ----- + "###); + }); +} + +#[test] +fn check_project_respects_subdirectory_includes() { + // Given a direct path to a subdirectory, the include should be respected + + insta::with_settings!({ + filters => TEST_FILTERS.to_vec() + }, { + assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) + .args(["check", "--show-files", "subdirectory"]).current_dir(Path::new("./resources/test/fixtures/include-test")), @r###" + success: true + exit_code: 0 + ----- stdout ----- + [BASEPATH]/include-test/subdirectory/c.py + + ----- stderr ----- + "###); + }); +} + +#[test] +fn check_project_from_project_subdirectory_respects_includes() { + // Run from a project subdirectory, the include specified in the parent directory should be respected + + insta::with_settings!({ + filters => TEST_FILTERS.to_vec() + }, { + assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) + .args(["check", "--show-files"]).current_dir(Path::new("./resources/test/fixtures/include-test/subdirectory")), @r###" + success: true + exit_code: 0 + ----- stdout ----- + [BASEPATH]/include-test/subdirectory/c.py + + ----- stderr ----- + "###); + }); +} diff --git a/docs/configuration.md b/docs/configuration.md index bc950ad3ac314..85071a439f072 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -299,6 +299,47 @@ By default, Ruff will also skip any files that are omitted via `.ignore`, `.giti Files that are passed to `ruff` directly are always analyzed, regardless of the above criteria. For example, `ruff check /path/to/excluded/file.py` will always lint `file.py`. +### Default inclusions + +By default, Ruff will discover files matching `*.py`, `*.ipy`, or `pyproject.toml`. + +To lint or format files with additional file extensions, use the [`extend-include`](settings.md#extend-include) setting. + +=== "pyproject.toml" + + ```toml + [tool.ruff.lint] + extend-include = ["*.ipynb"] + ``` + +=== "ruff.toml" + + ```toml + [lint] + extend-include = ["*.ipynb"] + ``` + +You can also change the default selection using the [`include`](settings.md#include) setting. + + +=== "pyproject.toml" + + ```toml + [tool.ruff.lint] + include = ["pyproject.toml", "src/**/*.py", "scripts/**/*.py"] + ``` + +=== "ruff.toml" + + ```toml + [lint] + include = ["pyproject.toml", "src/**/*.py", "scripts/**/*.py"] + ``` + +!!! warning + Paths provided to `include` _must_ match files. For example, `include = ["src"]` will fail since it +matches a directory. + ## Jupyter Notebook discovery Ruff has built-in support for [Jupyter Notebooks](https://jupyter.org/). @@ -422,7 +463,7 @@ Run Ruff on the given files or directories (default) Usage: ruff check [OPTIONS] [FILES]... Arguments: - [FILES]... List of files or directories to check + [FILES]... List of files or directories to check [default: .] Options: --fix @@ -518,7 +559,7 @@ Run the Ruff formatter on the given files or directories Usage: ruff format [OPTIONS] [FILES]... Arguments: - [FILES]... List of files or directories to format + [FILES]... List of files or directories to format [default: .] Options: --check diff --git a/docs/formatter.md b/docs/formatter.md index caa7459e55b3d..bbbc944c00f76 100644 --- a/docs/formatter.md +++ b/docs/formatter.md @@ -19,6 +19,10 @@ and instead exit with a non-zero status code upon detecting any unformatted file For the full list of supported options, run `ruff format --help`. +!!! note + As of Ruff v0.1.7 the `ruff format` command uses the current working directory (`.`) as the default path to format. + See [the file discovery documentation](configuration.md#python-file-discovery) for details. + ## Philosophy The initial goal of the Ruff formatter is _not_ to innovate on code style, but rather, to innovate diff --git a/docs/linter.md b/docs/linter.md index 71c5d04ef20aa..01d258d98ccc4 100644 --- a/docs/linter.md +++ b/docs/linter.md @@ -18,6 +18,10 @@ ruff check . --watch # Lint all files in the current directory, and re-lint on For the full list of supported options, run `ruff check --help`. +!!! note + As of Ruff v0.1.7 the `ruff check` command uses the current working directory (`.`) as the default path to check. + See [the file discovery documentation](configuration.md#python-file-discovery) for details. + ## Rule selection The set of enabled rules is controlled via the [`select`](settings.md#select), From 5373759f6277907ca89133412995b49e75420e2d Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 21 Nov 2023 19:30:48 +0000 Subject: [PATCH 018/197] Respect dictionary unpacking in `NamedTuple` assignments (#8810) Closes https://github.com/astral-sh/ruff/issues/8803. --- .../test/fixtures/pyflakes/F821_23.py | 7 +++ crates/ruff_linter/src/checkers/ast/mod.rs | 59 +++++++++++++------ crates/ruff_linter/src/rules/pyflakes/mod.rs | 1 + ...les__pyflakes__tests__F821_F821_23.py.snap | 4 ++ 4 files changed, 52 insertions(+), 19 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/pyflakes/F821_23.py create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_23.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/pyflakes/F821_23.py b/crates/ruff_linter/resources/test/fixtures/pyflakes/F821_23.py new file mode 100644 index 0000000000000..456b9d1a7abd0 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/pyflakes/F821_23.py @@ -0,0 +1,7 @@ +"""Test for type annotation parsing in `NamedTuple`.""" + +import typing + +User = typing.NamedTuple('User', **{'name': str, 'password': bytes}) +User = typing.NamedTuple('User', name=str, password=bytes) +User = typing.NamedTuple('User', [('name', str), ('password', bytes)]) diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 20b9ea2756b43..0a6ee16b15354 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -1014,33 +1014,54 @@ where if let Some(arg) = args.next() { self.visit_non_type_definition(arg); } + for arg in args { - if let Expr::List(ast::ExprList { elts, .. }) - | Expr::Tuple(ast::ExprTuple { elts, .. }) = arg - { - for elt in elts { - match elt { - Expr::List(ast::ExprList { elts, .. }) - | Expr::Tuple(ast::ExprTuple { elts, .. }) - if elts.len() == 2 => - { - self.visit_non_type_definition(&elts[0]); - self.visit_type_definition(&elts[1]); - } - _ => { - self.visit_non_type_definition(elt); + match arg { + // Ex) NamedTuple("a", [("a", int)]) + Expr::List(ast::ExprList { elts, .. }) + | Expr::Tuple(ast::ExprTuple { elts, .. }) => { + for elt in elts { + match elt { + Expr::List(ast::ExprList { elts, .. }) + | Expr::Tuple(ast::ExprTuple { elts, .. }) + if elts.len() == 2 => + { + self.visit_non_type_definition(&elts[0]); + self.visit_type_definition(&elts[1]); + } + _ => { + self.visit_non_type_definition(elt); + } } } } - } else { - self.visit_non_type_definition(arg); + _ => self.visit_non_type_definition(arg), } } - // Ex) NamedTuple("a", a=int) for keyword in keywords { - let Keyword { value, .. } = keyword; - self.visit_type_definition(value); + let Keyword { arg, value, .. } = keyword; + match (arg.as_ref(), value) { + // Ex) NamedTuple("a", **{"a": int}) + (None, Expr::Dict(ast::ExprDict { keys, values, .. })) => { + for (key, value) in keys.iter().zip(values) { + if let Some(key) = key.as_ref() { + self.visit_non_type_definition(key); + self.visit_type_definition(value); + } else { + self.visit_non_type_definition(value); + } + } + } + // Ex) NamedTuple("a", **obj) + (None, _) => { + self.visit_non_type_definition(value); + } + // Ex) NamedTuple("a", a=int) + _ => { + self.visit_type_definition(value); + } + } } } Some(typing::Callable::TypedDict) => { diff --git a/crates/ruff_linter/src/rules/pyflakes/mod.rs b/crates/ruff_linter/src/rules/pyflakes/mod.rs index 9f105649915cd..435755ce9fe42 100644 --- a/crates/ruff_linter/src/rules/pyflakes/mod.rs +++ b/crates/ruff_linter/src/rules/pyflakes/mod.rs @@ -140,6 +140,7 @@ mod tests { #[test_case(Rule::UndefinedName, Path::new("F821_20.py"))] #[test_case(Rule::UndefinedName, Path::new("F821_21.py"))] #[test_case(Rule::UndefinedName, Path::new("F821_22.ipynb"))] + #[test_case(Rule::UndefinedName, Path::new("F821_23.py"))] #[test_case(Rule::UndefinedExport, Path::new("F822_0.py"))] #[test_case(Rule::UndefinedExport, Path::new("F822_1.py"))] #[test_case(Rule::UndefinedExport, Path::new("F822_2.py"))] diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_23.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_23.py.snap new file mode 100644 index 0000000000000..d0b409f39ee0b --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F821_F821_23.py.snap @@ -0,0 +1,4 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/mod.rs +--- + From 5ce6299e2289ed0126d9ef7f75a65e2b6ec25da3 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Tue, 21 Nov 2023 15:35:42 -0600 Subject: [PATCH 019/197] Avoid `PERF101` if there's an append in loop body (#8809) ## Summary Avoid `PERF101` if there's an append in loop body ## Test Plan Add new test cases for this pattern. fixes: #8746 --- .../test/fixtures/perflint/PERF101.py | 13 +++++++ .../src/checkers/ast/analyze/statement.rs | 2 +- .../perflint/rules/unnecessary_list_cast.rs | 36 ++++++++++++++++++- ...__perflint__tests__PERF101_PERF101.py.snap | 21 +++++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/perflint/PERF101.py b/crates/ruff_linter/resources/test/fixtures/perflint/PERF101.py index 6123e6d6526bf..fbef6a7b2a709 100644 --- a/crates/ruff_linter/resources/test/fixtures/perflint/PERF101.py +++ b/crates/ruff_linter/resources/test/fixtures/perflint/PERF101.py @@ -50,3 +50,16 @@ for i in itertools.product(foo_int): # Ok pass + +for i in list(foo_list): # Ok + foo_list.append(i + 1) + +for i in list(foo_list): # PERF101 + # Make sure we match the correct list + other_list.append(i + 1) + +for i in list(foo_tuple): # Ok + foo_tuple.append(i + 1) + +for i in list(foo_set): # Ok + foo_set.append(i + 1) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 0ad8dc16e5777..48343b3825c7c 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -1269,7 +1269,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { perflint::rules::manual_dict_comprehension(checker, target, body); } if checker.enabled(Rule::UnnecessaryListCast) { - perflint::rules::unnecessary_list_cast(checker, iter); + perflint::rules::unnecessary_list_cast(checker, iter, body); } if !is_async { if checker.enabled(Rule::ReimplementedBuiltin) { diff --git a/crates/ruff_linter/src/rules/perflint/rules/unnecessary_list_cast.rs b/crates/ruff_linter/src/rules/perflint/rules/unnecessary_list_cast.rs index 9769eed8d71e3..93321cf6b070c 100644 --- a/crates/ruff_linter/src/rules/perflint/rules/unnecessary_list_cast.rs +++ b/crates/ruff_linter/src/rules/perflint/rules/unnecessary_list_cast.rs @@ -49,7 +49,7 @@ impl AlwaysFixableViolation for UnnecessaryListCast { } /// PERF101 -pub(crate) fn unnecessary_list_cast(checker: &mut Checker, iter: &Expr) { +pub(crate) fn unnecessary_list_cast(checker: &mut Checker, iter: &Expr, body: &[Stmt]) { let Expr::Call(ast::ExprCall { func, arguments: @@ -98,6 +98,18 @@ pub(crate) fn unnecessary_list_cast(checker: &mut Checker, iter: &Expr) { range: iterable_range, .. }) => { + // If the variable is being appended to, don't suggest removing the cast: + // + // ```python + // items = ["foo", "bar"] + // for item in list(items): + // items.append("baz") + // ``` + // + // Here, removing the `list()` cast would change the behavior of the code. + if body.iter().any(|stmt| match_append(stmt, id)) { + return; + } let scope = checker.semantic().current_scope(); if let Some(binding_id) = scope.get(id) { let binding = checker.semantic().binding(binding_id); @@ -128,6 +140,28 @@ pub(crate) fn unnecessary_list_cast(checker: &mut Checker, iter: &Expr) { } } +/// Check if a statement is an `append` call to a given identifier. +/// +/// For example, `foo.append(bar)` would return `true` if `id` is `foo`. +fn match_append(stmt: &Stmt, id: &str) -> bool { + let Some(ast::StmtExpr { value, .. }) = stmt.as_expr_stmt() else { + return false; + }; + let Some(ast::ExprCall { func, .. }) = value.as_call_expr() else { + return false; + }; + let Some(ast::ExprAttribute { value, attr, .. }) = func.as_attribute_expr() else { + return false; + }; + if attr != "append" { + return false; + } + let Some(ast::ExprName { id: target_id, .. }) = value.as_name_expr() else { + return false; + }; + target_id == id +} + /// Generate a [`Fix`] to remove a `list` cast from an expression. fn remove_cast(list_range: TextRange, iterable_range: TextRange) -> Fix { Fix::safe_edits( diff --git a/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF101_PERF101.py.snap b/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF101_PERF101.py.snap index 645b5e5177784..1b4b456af3f15 100644 --- a/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF101_PERF101.py.snap +++ b/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF101_PERF101.py.snap @@ -180,4 +180,25 @@ PERF101.py:34:10: PERF101 [*] Do not cast an iterable to `list` before iterating 38 36 | 39 37 | for i in list(foo_dict): # Ok +PERF101.py:57:10: PERF101 [*] Do not cast an iterable to `list` before iterating over it + | +55 | foo_list.append(i + 1) +56 | +57 | for i in list(foo_list): # PERF101 + | ^^^^^^^^^^^^^^ PERF101 +58 | # Make sure we match the correct list +59 | other_list.append(i + 1) + | + = help: Remove `list()` cast + +ℹ Safe fix +54 54 | for i in list(foo_list): # Ok +55 55 | foo_list.append(i + 1) +56 56 | +57 |-for i in list(foo_list): # PERF101 + 57 |+for i in foo_list: # PERF101 +58 58 | # Make sure we match the correct list +59 59 | other_list.append(i + 1) +60 60 | + From f1ed0f27c297870f91ad55056c3d5314f5a813df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jelmer=20Vernoo=C4=B3?= Date: Tue, 21 Nov 2023 23:36:15 +0000 Subject: [PATCH 020/197] isort: Add support for the ``from-first`` setting (#8663) # Summary This setting behaves similarly to the ``from_first`` setting in isort upstream, and sorts "from X import Y" type imports before straight imports. Like the other PR I added, happy to refactor if this is better in another form. Fixes #8662 # Test plan I've added a unit test, and ran this on a large codebase that relies on this setting in isort to verify it doesn't have unexpected side effects. --- .../test/fixtures/isort/from_first.py | 5 ++ crates/ruff_linter/src/rules/isort/mod.rs | 60 +++++++++++++++++-- crates/ruff_linter/src/rules/isort/order.rs | 18 ++++-- .../ruff_linter/src/rules/isort/settings.rs | 2 + ...sort__tests__from_first_from_first.py.snap | 4 ++ crates/ruff_workspace/src/options.rs | 28 +++++++++ ruff.schema.json | 7 +++ 7 files changed, 113 insertions(+), 11 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/isort/from_first.py create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__from_first_from_first.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/isort/from_first.py b/crates/ruff_linter/resources/test/fixtures/isort/from_first.py new file mode 100644 index 0000000000000..a15a573d28215 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/isort/from_first.py @@ -0,0 +1,5 @@ +from __future__ import blah + +from os import path + +import os diff --git a/crates/ruff_linter/src/rules/isort/mod.rs b/crates/ruff_linter/src/rules/isort/mod.rs index 10a3f7b1d974a..5fce5a86acfc8 100644 --- a/crates/ruff_linter/src/rules/isort/mod.rs +++ b/crates/ruff_linter/src/rules/isort/mod.rs @@ -145,6 +145,15 @@ fn format_import_block( target_version: PythonVersion, settings: &Settings, ) -> String { + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + enum LineInsertion { + /// A blank line should be inserted as soon as the next import is + /// of a different type (i.e., direct vs. `from`). + Necessary, + /// A blank line has already been inserted. + Inserted, + } + // Categorize by type (e.g., first-party vs. third-party). let mut block_by_type = categorize_imports( block, @@ -182,13 +191,24 @@ fn format_import_block( pending_lines_before = false; } - let mut lines_inserted = false; - let mut has_direct_import = false; + let mut line_insertion = None; let mut is_first_statement = true; let lines_between_types = settings.lines_between_types; for import in imports { match import { Import((alias, comments)) => { + // Add a blank lines between direct and from imports. + if settings.from_first + && lines_between_types > 0 + && line_insertion == Some(LineInsertion::Necessary) + { + for _ in 0..lines_between_types { + output.push_str(&stylist.line_ending()); + } + + line_insertion = Some(LineInsertion::Inserted); + } + output.push_str(&format::format_import( &alias, &comments, @@ -196,17 +216,22 @@ fn format_import_block( stylist, )); - has_direct_import = true; + if !settings.from_first { + line_insertion = Some(LineInsertion::Necessary); + } } ImportFrom((import_from, comments, trailing_comma, aliases)) => { - // Add a blank lines between direct and from imports - if lines_between_types > 0 && has_direct_import && !lines_inserted { + // Add a blank lines between direct and from imports. + if !settings.from_first + && lines_between_types > 0 + && line_insertion == Some(LineInsertion::Necessary) + { for _ in 0..lines_between_types { output.push_str(&stylist.line_ending()); } - lines_inserted = true; + line_insertion = Some(LineInsertion::Inserted); } output.push_str(&format::format_import_from( @@ -221,6 +246,10 @@ fn format_import_block( settings.split_on_trailing_comma && matches!(trailing_comma, TrailingComma::Present), )); + + if settings.from_first { + line_insertion = Some(LineInsertion::Necessary); + } } } is_first_statement = false; @@ -819,6 +848,25 @@ mod tests { Ok(()) } + #[test_case(Path::new("from_first.py"))] + fn from_first(path: &Path) -> Result<()> { + let snapshot = format!("from_first_{}", path.to_string_lossy()); + let diagnostics = test_path( + Path::new("isort").join(path).as_path(), + &LinterSettings { + isort: super::settings::Settings { + from_first: true, + lines_between_types: 1, + ..super::settings::Settings::default() + }, + src: vec![test_resource_path("fixtures/isort")], + ..LinterSettings::for_rule(Rule::UnsortedImports) + }, + )?; + assert_messages!(snapshot, diagnostics); + Ok(()) + } + #[test_case(Path::new("relative_imports_order.py"))] fn closest_to_furthest(path: &Path) -> Result<()> { let snapshot = format!("closest_to_furthest_{}", path.to_string_lossy()); diff --git a/crates/ruff_linter/src/rules/isort/order.rs b/crates/ruff_linter/src/rules/isort/order.rs index 06002fd3ebb9b..1d7102b3cae35 100644 --- a/crates/ruff_linter/src/rules/isort/order.rs +++ b/crates/ruff_linter/src/rules/isort/order.rs @@ -82,11 +82,19 @@ pub(crate) fn order_imports<'a>( settings, ) }); - ordered_straight_imports - .into_iter() - .map(Import) - .chain(ordered_from_imports.into_iter().map(ImportFrom)) - .collect() + if settings.from_first { + ordered_from_imports + .into_iter() + .map(ImportFrom) + .chain(ordered_straight_imports.into_iter().map(Import)) + .collect() + } else { + ordered_straight_imports + .into_iter() + .map(Import) + .chain(ordered_from_imports.into_iter().map(ImportFrom)) + .collect() + } }; ordered_imports diff --git a/crates/ruff_linter/src/rules/isort/settings.rs b/crates/ruff_linter/src/rules/isort/settings.rs index 6e27a2debf4ee..d4937520fa7aa 100644 --- a/crates/ruff_linter/src/rules/isort/settings.rs +++ b/crates/ruff_linter/src/rules/isort/settings.rs @@ -57,6 +57,7 @@ pub struct Settings { pub forced_separate: Vec, pub section_order: Vec, pub no_sections: bool, + pub from_first: bool, } impl Default for Settings { @@ -84,6 +85,7 @@ impl Default for Settings { forced_separate: Vec::new(), section_order: ImportType::iter().map(ImportSection::Known).collect(), no_sections: false, + from_first: false, } } } diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__from_first_from_first.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__from_first_from_first.py.snap new file mode 100644 index 0000000000000..ed369f0fd61f0 --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__from_first_from_first.py.snap @@ -0,0 +1,4 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- + diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index 5967186b444a9..fff62ddd6ff33 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -2021,6 +2021,32 @@ pub struct IsortOptions { )] pub detect_same_package: Option, + /// Whether to place `import from` imports before straight imports when sorting. + /// + /// For example, by default, imports will be sorted such that straight imports appear + /// before `import from` imports, as in: + /// ```python + /// import os + /// import sys + /// from typing import List + /// ``` + /// + /// Setting `from-first = true` will instead sort such that `import from` imports appear + /// before straight imports, as in: + /// ```python + /// from typing import List + /// import os + /// import sys + /// ``` + #[option( + default = r#"false"#, + value_type = "bool", + example = r#" + from-first = true + "# + )] + pub from_first: Option, + // Tables are required to go last. /// A list of mappings from section names to modules. /// By default custom sections are output last, but this can be overridden with `section-order`. @@ -2098,6 +2124,7 @@ impl IsortOptions { .map_err(isort::settings::SettingsError::InvalidExtraStandardLibrary)? .unwrap_or_default(); let no_lines_before = self.no_lines_before.unwrap_or_default(); + let from_first = self.from_first.unwrap_or_default(); let sections = self.sections.unwrap_or_default(); // Verify that `sections` doesn't contain any built-in sections. @@ -2206,6 +2233,7 @@ impl IsortOptions { forced_separate: Vec::from_iter(self.forced_separate.unwrap_or_default()), section_order, no_sections, + from_first, }) } } diff --git a/ruff.schema.json b/ruff.schema.json index 8ac638a4c11d1..57613064df667 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -1440,6 +1440,13 @@ "type": "string" } }, + "from-first": { + "description": "Whether to place `import from` imports before straight imports when sorting.\n\nFor example, by default, imports will be sorted such that straight imports appear before `import from` imports, as in: ```python import os import sys from typing import List ```\n\nSetting `from-first = true` will instead sort such that `import from` imports appear before straight imports, as in: ```python from typing import List import os import sys ```", + "type": [ + "boolean", + "null" + ] + }, "known-first-party": { "description": "A list of modules to consider first-party, regardless of whether they can be identified as such via introspection of the local filesystem.\n\nSupports glob patterns. For more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax).", "type": [ From 948094e691afd282cfac482e8eb3d476b8c18c4b Mon Sep 17 00:00:00 2001 From: Adrian Date: Wed, 22 Nov 2023 00:44:23 +0100 Subject: [PATCH 021/197] [`pylint`] Add `allow-dunder-method-names` setting for `bad-dunder-method-name` (`PLW3201`) (#8812) closes #8732 I noticed that the reference to the setting in the rule docs doesn't work, but there seem to be something wrong with pylint settings in general in the docs - the "For related settings, see ...." is also missing there. --- .../fixtures/pylint/bad_dunder_method_name.py | 6 +++++- crates/ruff_linter/src/rules/pylint/mod.rs | 11 ++++++++++- .../rules/pylint/rules/bad_dunder_method_name.rs | 15 ++++++++++++++- crates/ruff_linter/src/rules/pylint/settings.rs | 3 +++ crates/ruff_workspace/src/options.rs | 12 ++++++++++++ ruff.schema.json | 11 +++++++++++ 6 files changed, 55 insertions(+), 3 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/bad_dunder_method_name.py b/crates/ruff_linter/resources/test/fixtures/pylint/bad_dunder_method_name.py index 760951260e24c..5032f42ff1d3a 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/bad_dunder_method_name.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/bad_dunder_method_name.py @@ -50,7 +50,7 @@ def __doc__(self): return "Docstring" # Added in Python 3.12 - def __buffer__(self): + def __buffer__(self): return memoryview(b'') def __release_buffer__(self, buf): @@ -83,6 +83,10 @@ def _missing_(cls, value): def _(self): pass + # Allow custom dunder names (via setting). + def __special_custom_magic__(self): + pass + def __foo_bar__(): # this is not checked by the [bad-dunder-name] rule ... diff --git a/crates/ruff_linter/src/rules/pylint/mod.rs b/crates/ruff_linter/src/rules/pylint/mod.rs index 2c4e28ca363e6..e2f272619b2ce 100644 --- a/crates/ruff_linter/src/rules/pylint/mod.rs +++ b/crates/ruff_linter/src/rules/pylint/mod.rs @@ -9,6 +9,7 @@ mod tests { use anyhow::Result; use regex::Regex; + use rustc_hash::FxHashSet; use test_case::test_case; use crate::assert_messages; @@ -157,7 +158,15 @@ mod tests { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let diagnostics = test_path( Path::new("pylint").join(path).as_path(), - &LinterSettings::for_rule(rule_code), + &LinterSettings { + pylint: pylint::settings::Settings { + allow_dunder_method_names: FxHashSet::from_iter([ + "__special_custom_magic__".to_string() + ]), + ..pylint::settings::Settings::default() + }, + ..LinterSettings::for_rule(rule_code) + }, )?; assert_messages!(snapshot, diagnostics); Ok(()) diff --git a/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs b/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs index 752c3a67351ee..87c14839cfc69 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs @@ -22,6 +22,9 @@ use crate::checkers::ast::Checker; /// one underscore (e.g., `_str_`), but ignores known dunder methods (like /// `__init__`), as well as methods that are marked with `@override`. /// +/// Additional dunder methods names can be allowed via the +/// [`pylint.allow-dunder-method-names`] setting. +/// /// ## Example /// ```python /// class Foo: @@ -35,6 +38,9 @@ use crate::checkers::ast::Checker; /// def __init__(self): /// ... /// ``` +/// +/// ## Options +/// - `pylint.allow-dunder-method-names` #[violation] pub struct BadDunderMethodName { name: String, @@ -54,7 +60,14 @@ pub(crate) fn bad_dunder_method_name(checker: &mut Checker, class_body: &[Stmt]) .iter() .filter_map(ruff_python_ast::Stmt::as_function_def_stmt) .filter(|method| { - if is_known_dunder_method(&method.name) || matches!(method.name.as_str(), "_") { + if is_known_dunder_method(&method.name) + || checker + .settings + .pylint + .allow_dunder_method_names + .contains(method.name.as_str()) + || matches!(method.name.as_str(), "_") + { return false; } method.name.starts_with('_') && method.name.ends_with('_') diff --git a/crates/ruff_linter/src/rules/pylint/settings.rs b/crates/ruff_linter/src/rules/pylint/settings.rs index 4925211952ebb..cb9846b11e056 100644 --- a/crates/ruff_linter/src/rules/pylint/settings.rs +++ b/crates/ruff_linter/src/rules/pylint/settings.rs @@ -1,5 +1,6 @@ //! Settings for the `pylint` plugin. +use rustc_hash::FxHashSet; use serde::{Deserialize, Serialize}; use ruff_macros::CacheKey; @@ -36,6 +37,7 @@ impl ConstantType { #[derive(Debug, CacheKey)] pub struct Settings { pub allow_magic_value_types: Vec, + pub allow_dunder_method_names: FxHashSet, pub max_args: usize, pub max_returns: usize, pub max_bool_expr: usize, @@ -48,6 +50,7 @@ impl Default for Settings { fn default() -> Self { Self { allow_magic_value_types: vec![ConstantType::Str, ConstantType::Bytes], + allow_dunder_method_names: FxHashSet::default(), max_args: 5, max_returns: 6, max_bool_expr: 5, diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index fff62ddd6ff33..6d8569dca4bd1 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -2573,6 +2573,17 @@ pub struct PylintOptions { )] pub allow_magic_value_types: Option>, + /// Dunder methods name to allow, in addition to the default set from the + /// Python standard library (see: `PLW3201`). + #[option( + default = r#"[]"#, + value_type = r#"list[str]"#, + example = r#" + allow-dunder-method-names = ["__tablename__", "__table_args__"] + "# + )] + pub allow_dunder_method_names: Option>, + /// Maximum number of branches allowed for a function or method body (see: /// `PLR0912`). #[option(default = r"12", value_type = "int", example = r"max-branches = 12")] @@ -2614,6 +2625,7 @@ impl PylintOptions { allow_magic_value_types: self .allow_magic_value_types .unwrap_or(defaults.allow_magic_value_types), + allow_dunder_method_names: self.allow_dunder_method_names.unwrap_or_default(), max_args: self.max_args.unwrap_or(defaults.max_args), max_bool_expr: self.max_bool_expr.unwrap_or(defaults.max_bool_expr), max_returns: self.max_returns.unwrap_or(defaults.max_returns), diff --git a/ruff.schema.json b/ruff.schema.json index 57613064df667..c4acb767cd585 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -2307,6 +2307,17 @@ "PylintOptions": { "type": "object", "properties": { + "allow-dunder-method-names": { + "description": "Dunder methods name to allow, in addition to the default set from the Python standard library (see: `PLW3201`).", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "uniqueItems": true + }, "allow-magic-value-types": { "description": "Constant types to ignore when used as \"magic values\" (see: `PLR2004`).", "type": [ From 359a68d18f9666a3477f81b4ac3a295893eeff3d Mon Sep 17 00:00:00 2001 From: Alan Du Date: Tue, 21 Nov 2023 19:32:01 -0500 Subject: [PATCH 022/197] Factor out a builder to handle common integration test arguments (#8733) ## Summary This refactors the `ruff_cli` integration tests to create a new `RuffCheck` struct -- this holds options to configure the "common case" flags that we want to pass to Ruff (e.g. `--no-cache`, `--isolated`, etc). This helps reduce the boilerplate and (IMO) makes it more obvious what the core logic of each test is by keeping only the "interesting" parameters. ## Test Plan `cargo test` --- crates/ruff_cli/tests/format.rs | 2 +- crates/ruff_cli/tests/integration_test.rs | 648 ++++++++++------------ 2 files changed, 283 insertions(+), 367 deletions(-) diff --git a/crates/ruff_cli/tests/format.rs b/crates/ruff_cli/tests/format.rs index 79a7cf942d6b2..e9970645d7b67 100644 --- a/crates/ruff_cli/tests/format.rs +++ b/crates/ruff_cli/tests/format.rs @@ -77,7 +77,7 @@ bar = "needs formatting" #[test] fn format_warn_stdin_filename_with_files() { assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(["format", "--stdin-filename", "foo.py"]) + .args(["format", "--isolated", "--stdin-filename", "foo.py"]) .arg("foo.py") .pass_stdin("foo = 1"), @r###" success: true diff --git a/crates/ruff_cli/tests/integration_test.rs b/crates/ruff_cli/tests/integration_test.rs index bcba6b255bc14..37c18551c2dbc 100644 --- a/crates/ruff_cli/tests/integration_test.rs +++ b/crates/ruff_cli/tests/integration_test.rs @@ -5,7 +5,6 @@ use std::fs; use std::fs::Permissions; #[cfg(unix)] use std::os::unix::fs::{OpenOptionsExt, PermissionsExt}; -#[cfg(unix)] use std::path::Path; use std::process::Command; use std::str; @@ -26,12 +25,84 @@ use ruff_cli::args::Args; use ruff_cli::run; const BIN_NAME: &str = "ruff"; -const STDIN_BASE_OPTIONS: &[&str] = &["--isolated", "--no-cache", "-", "--output-format", "text"]; + +fn ruff_cmd() -> Command { + Command::new(get_cargo_bin(BIN_NAME)) +} + +/// Builder for `ruff check` commands. +#[derive(Debug)] +struct RuffCheck<'a> { + output_format: &'a str, + config: Option<&'a Path>, + filename: Option<&'a str>, + args: Vec<&'a str>, +} + +impl<'a> Default for RuffCheck<'a> { + fn default() -> RuffCheck<'a> { + RuffCheck { + output_format: "text", + config: None, + filename: None, + args: vec![], + } + } +} + +impl<'a> RuffCheck<'a> { + /// Set the `--config` option. + #[must_use] + fn config(mut self, config: &'a Path) -> Self { + self.config = Some(config); + self + } + + /// Set the `--output-format` option. + #[must_use] + fn output_format(mut self, format: &'a str) -> Self { + self.output_format = format; + self + } + + /// Set the input file to pass to `ruff check`. + #[must_use] + fn filename(mut self, filename: &'a str) -> Self { + self.filename = Some(filename); + self + } + + /// Set the list of positional arguments. + #[must_use] + fn args(mut self, args: impl IntoIterator) -> Self { + self.args = args.into_iter().collect(); + self + } + + /// Generate a [`Command`] for the `ruff check` command. + fn build(self) -> Command { + let mut cmd = ruff_cmd(); + cmd.args(["--output-format", self.output_format, "--no-cache"]); + if let Some(path) = self.config { + cmd.arg("--config"); + cmd.arg(path); + } else { + cmd.arg("--isolated"); + } + if let Some(filename) = self.filename { + cmd.arg(filename); + } else { + cmd.arg("-"); + } + cmd.args(self.args); + cmd + } +} #[test] fn stdin_success() { - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) + let mut cmd = RuffCheck::default().args([]).build(); + assert_cmd_snapshot!(cmd .pass_stdin(""), @r###" success: true exit_code: 0 @@ -43,8 +114,8 @@ fn stdin_success() { #[test] fn stdin_error() { - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) + let mut cmd = RuffCheck::default().args([]).build(); + assert_cmd_snapshot!(cmd .pass_stdin("import os\n"), @r###" success: false exit_code: 1 @@ -59,9 +130,10 @@ fn stdin_error() { #[test] fn stdin_filename() { - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) + let mut cmd = RuffCheck::default() .args(["--stdin-filename", "F401.py"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("import os\n"), @r###" success: false exit_code: 1 @@ -108,10 +180,11 @@ import bar # unused import #[test] fn check_warn_stdin_filename_with_files() { - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) + let mut cmd = RuffCheck::default() .args(["--stdin-filename", "F401.py"]) - .arg("foo.py") + .filename("foo.py") + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("import os\n"), @r###" success: false exit_code: 1 @@ -128,9 +201,10 @@ fn check_warn_stdin_filename_with_files() { /// Raise `TCH` errors in `.py` files ... #[test] fn stdin_source_type_py() { - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) + let mut cmd = RuffCheck::default() .args(["--stdin-filename", "TCH.py"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("import os\n"), @r###" success: false exit_code: 1 @@ -146,10 +220,10 @@ fn stdin_source_type_py() { /// ... but not in `.pyi` files. #[test] fn stdin_source_type_pyi() { - let args = ["--stdin-filename", "TCH.pyi", "--select", "TCH"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default() + .args(["--stdin-filename", "TCH.pyi", "--select", "TCH"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("import os\n"), @r###" success: true exit_code: 0 @@ -162,35 +236,26 @@ fn stdin_source_type_pyi() { #[cfg(unix)] #[test] fn stdin_json() { - let args = [ - "-", - "--isolated", - "--no-cache", - "--output-format", - "json", - "--stdin-filename", - "F401.py", - ]; - let directory = path_dedot::CWD.to_str().unwrap(); let binding = Path::new(directory).join("F401.py"); let file_path = binding.display(); + let mut cmd = RuffCheck::default() + .output_format("json") + .args(["--stdin-filename", "F401.py"]) + .build(); + insta::with_settings!({filters => vec![ (file_path.to_string().as_str(), "/path/to/F401.py"), ]}, { - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(args) - .pass_stdin("import os\n")); + assert_cmd_snapshot!(cmd.pass_stdin("import os\n")); }); } #[test] fn stdin_fix_py() { - let args = ["--fix"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default().args(["--fix"]).build(); + assert_cmd_snapshot!(cmd .pass_stdin("import os\nimport sys\n\nprint(sys.version)\n"), @r###" success: true exit_code: 0 @@ -206,10 +271,10 @@ fn stdin_fix_py() { #[test] fn stdin_fix_jupyter() { - let args = ["--fix", "--stdin-filename", "Jupyter.ipynb"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default() + .args(["--fix", "--stdin-filename", "Jupyter.ipynb"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin(r#"{ "cells": [ { @@ -374,10 +439,10 @@ fn stdin_fix_jupyter() { #[test] fn stdin_override_parser_ipynb() { - let args = ["--extension", "py:ipynb", "--stdin-filename", "Jupyter.py"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default() + .args(["--extension", "py:ipynb", "--stdin-filename", "Jupyter.py"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin(r#"{ "cells": [ { @@ -471,9 +536,15 @@ fn stdin_override_parser_ipynb() { #[test] fn stdin_override_parser_py() { - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(["--extension", "ipynb:python", "--stdin-filename", "F401.ipynb"]) + let mut cmd = RuffCheck::default() + .args([ + "--extension", + "ipynb:python", + "--stdin-filename", + "F401.ipynb", + ]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("import os\n"), @r###" success: false exit_code: 1 @@ -488,10 +559,8 @@ fn stdin_override_parser_py() { #[test] fn stdin_fix_when_not_fixable_should_still_print_contents() { - let args = ["--fix"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default().args(["--fix"]).build(); + assert_cmd_snapshot!(cmd .pass_stdin("import os\nimport sys\n\nif (1, 2):\n print(sys.version)\n"), @r###" success: false exit_code: 1 @@ -509,10 +578,8 @@ fn stdin_fix_when_not_fixable_should_still_print_contents() { #[test] fn stdin_fix_when_no_issues_should_still_print_contents() { - let args = ["--fix"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default().args(["--fix"]).build(); + assert_cmd_snapshot!(cmd .pass_stdin("import sys\n\nprint(sys.version)\n"), @r###" success: true exit_code: 0 @@ -527,9 +594,8 @@ fn stdin_fix_when_no_issues_should_still_print_contents() { #[test] fn stdin_format_jupyter() { - let args = ["format", "--stdin-filename", "Jupyter.ipynb", "--isolated"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(args) + assert_cmd_snapshot!(ruff_cmd() + .args(["format", "--stdin-filename", "Jupyter.ipynb", "--isolated"]) .pass_stdin(r#"{ "cells": [ { @@ -655,10 +721,8 @@ fn stdin_format_jupyter() { #[test] fn show_source() { - let args = ["--show-source"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default().args(["--show-source"]).build(); + assert_cmd_snapshot!(cmd .pass_stdin("l = 1"), @r###" success: false exit_code: 1 @@ -677,11 +741,11 @@ fn show_source() { #[test] fn explain_status_codes_f401() { - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)).args(["--explain", "F401"])); + assert_cmd_snapshot!(ruff_cmd().args(["--explain", "F401"])); } #[test] fn explain_status_codes_ruf404() { - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)).args(["--explain", "RUF404"]), @r###" + assert_cmd_snapshot!(ruff_cmd().args(["--explain", "RUF404"]), @r###" success: false exit_code: 2 ----- stdout ----- @@ -695,10 +759,10 @@ fn explain_status_codes_ruf404() { #[test] fn show_statistics() { - let args = ["--select", "F401", "--statistics"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default() + .args(["--select", "F401", "--statistics"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("import sys\nimport os\n\nprint(os.getuid())\n"), @r###" success: false exit_code: 1 @@ -712,10 +776,8 @@ fn show_statistics() { #[test] fn nursery_prefix() { // `--select E` should detect E741, but not E225, which is in the nursery. - let args = ["--select", "E"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default().args(["--select", "E"]).build(); + assert_cmd_snapshot!(cmd .pass_stdin("I=42\n"), @r###" success: false exit_code: 1 @@ -730,10 +792,8 @@ fn nursery_prefix() { #[test] fn nursery_all() { // `--select ALL` should detect E741, but not E225, which is in the nursery. - let args = ["--select", "ALL"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default().args(["--select", "ALL"]).build(); + assert_cmd_snapshot!(cmd .pass_stdin("I=42\n"), @r###" success: false exit_code: 1 @@ -751,10 +811,8 @@ fn nursery_all() { #[test] fn nursery_direct() { // `--select E225` should detect E225. - let args = ["--select", "E225"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default().args(["--select", "E225"]).build(); + assert_cmd_snapshot!(cmd .pass_stdin("I=42\n"), @r###" success: false exit_code: 1 @@ -770,10 +828,8 @@ fn nursery_direct() { #[test] fn nursery_group_selector() { // Only nursery rules should be detected e.g. E225 and a warning should be displayed - let args = ["--select", "NURSERY"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default().args(["--select", "NURSERY"]).build(); + assert_cmd_snapshot!(cmd .pass_stdin("I=42\n"), @r###" success: false exit_code: 1 @@ -790,10 +846,10 @@ fn nursery_group_selector() { #[test] fn nursery_group_selector_preview_enabled() { // Only nursery rules should be detected e.g. E225 and a warning should be displayed - let args = ["--select", "NURSERY", "--preview"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default() + .args(["--select", "NURSERY", "--preview"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("I=42\n"), @r###" success: false exit_code: 1 @@ -811,10 +867,10 @@ fn nursery_group_selector_preview_enabled() { #[test] fn preview_enabled_prefix() { // E741 and E225 (preview) should both be detected - let args = ["--select", "E", "--preview"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default() + .args(["--select", "E", "--preview"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("I=42\n"), @r###" success: false exit_code: 1 @@ -830,10 +886,10 @@ fn preview_enabled_prefix() { #[test] fn preview_enabled_all() { - let args = ["--select", "ALL", "--preview"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default() + .args(["--select", "ALL", "--preview"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("I=42\n"), @r###" success: false exit_code: 1 @@ -854,10 +910,10 @@ fn preview_enabled_all() { #[test] fn preview_enabled_direct() { // E225 should be detected without warning - let args = ["--select", "E225", "--preview"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default() + .args(["--select", "E225", "--preview"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("I=42\n"), @r###" success: false exit_code: 1 @@ -873,10 +929,8 @@ fn preview_enabled_direct() { #[test] fn preview_disabled_direct() { // FURB145 is preview not nursery so selecting should be empty - let args = ["--select", "FURB145"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default().args(["--select", "FURB145"]).build(); + assert_cmd_snapshot!(cmd .pass_stdin("a = l[:]\n"), @r###" success: true exit_code: 0 @@ -890,10 +944,8 @@ fn preview_disabled_direct() { #[test] fn preview_disabled_prefix_empty() { // Warns that the selection is empty since all of the CPY rules are in preview - let args = ["--select", "CPY"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default().args(["--select", "CPY"]).build(); + assert_cmd_snapshot!(cmd .pass_stdin("I=42\n"), @r###" success: true exit_code: 0 @@ -907,10 +959,8 @@ fn preview_disabled_prefix_empty() { #[test] fn preview_disabled_does_not_warn_for_empty_ignore_selections() { // Does not warn that the selection is empty since the user is not trying to enable the rule - let args = ["--ignore", "CPY"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default().args(["--ignore", "CPY"]).build(); + assert_cmd_snapshot!(cmd .pass_stdin("I=42\n"), @r###" success: false exit_code: 1 @@ -925,10 +975,8 @@ fn preview_disabled_does_not_warn_for_empty_ignore_selections() { #[test] fn preview_disabled_does_not_warn_for_empty_fixable_selections() { // Does not warn that the selection is empty since the user is not trying to enable the rule - let args = ["--fixable", "CPY"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default().args(["--fixable", "CPY"]).build(); + assert_cmd_snapshot!(cmd .pass_stdin("I=42\n"), @r###" success: false exit_code: 1 @@ -943,10 +991,10 @@ fn preview_disabled_does_not_warn_for_empty_fixable_selections() { #[test] fn preview_group_selector() { // `--select PREVIEW` should error (selector was removed) - let args = ["--select", "PREVIEW", "--preview"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default() + .args(["--select", "PREVIEW", "--preview"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("I=42\n"), @r###" success: false exit_code: 2 @@ -962,10 +1010,10 @@ fn preview_group_selector() { #[test] fn preview_enabled_group_ignore() { // `--select E --ignore PREVIEW` should detect E741 and E225, which is in preview but "E" is more specific. - let args = ["--select", "E", "--ignore", "PREVIEW", "--preview"]; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(STDIN_BASE_OPTIONS) - .args(args) + let mut cmd = RuffCheck::default() + .args(["--select", "E", "--ignore", "PREVIEW", "--preview"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("I=42\n"), @r###" success: false exit_code: 2 @@ -1017,9 +1065,11 @@ fn unreadable_dir() -> Result<()> { // We (currently?) have to use a subcommand to check exit status (currently wrong) and logging // output // TODO(konstin): This should be a failure, but we currently can't track that - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(["--no-cache", "--isolated"]) - .arg(&unreadable_dir), @r###" + let mut cmd = RuffCheck::default() + .filename(unreadable_dir.to_str().unwrap()) + .args([]) + .build(); + assert_cmd_snapshot!(cmd, @r###" success: true exit_code: 0 ----- stdout ----- @@ -1050,18 +1100,12 @@ fn check_input_from_argfile() -> Result<()> { )?; // Generate the args with the argfile notation - let args = vec![ - "check".to_string(), - "--no-cache".to_string(), - "--isolated".to_string(), - format!("@{}", &input_file_path.display()), - ]; - + let argfile = format!("@{}", &input_file_path.display()); + let mut cmd = RuffCheck::default().filename(argfile.as_ref()).build(); insta::with_settings!({filters => vec![ (file_a_path.display().to_string().as_str(), "/path/to/a.py"), ]}, { - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(args) + assert_cmd_snapshot!(cmd .pass_stdin(""), @r###" success: false exit_code: 1 @@ -1079,15 +1123,10 @@ fn check_input_from_argfile() -> Result<()> { #[test] fn check_hints_hidden_unsafe_fixes() { - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args([ - "-", - "--output-format=text", - "--isolated", - "--select", - "F601,UP034", - "--no-cache", - ]) + let mut cmd = RuffCheck::default() + .args(["--select", "F601,UP034"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), @r###" success: false @@ -1104,8 +1143,8 @@ fn check_hints_hidden_unsafe_fixes() { #[test] fn check_hints_hidden_unsafe_fixes_with_no_safe_fixes() { - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(["-", "--output-format", "text", "--no-cache", "--isolated", "--select", "F601"]) + let mut cmd = RuffCheck::default().args(["--select", "F601"]).build(); + assert_cmd_snapshot!(cmd .pass_stdin("x = {'a': 1, 'a': 1}\n"), @r###" success: false @@ -1121,16 +1160,10 @@ fn check_hints_hidden_unsafe_fixes_with_no_safe_fixes() { #[test] fn check_shows_unsafe_fixes_with_opt_in() { - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args([ - "-", - "--output-format=text", - "--isolated", - "--select", - "F601,UP034", - "--no-cache", - "--unsafe-fixes", - ]) + let mut cmd = RuffCheck::default() + .args(["--select", "F601,UP034", "--unsafe-fixes"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), @r###" success: false @@ -1147,20 +1180,12 @@ fn check_shows_unsafe_fixes_with_opt_in() { #[test] fn fix_applies_safe_fixes_by_default() { - assert_cmd_snapshot!( - Command::new(get_cargo_bin(BIN_NAME)) - .args([ - "-", - "--output-format", - "text", - "--isolated", - "--no-cache", - "--select", - "F601,UP034", - "--fix", - ]) - .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), - @r###" + let mut cmd = RuffCheck::default() + .args(["--select", "F601,UP034", "--fix"]) + .build(); + assert_cmd_snapshot!(cmd + .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), + @r###" success: false exit_code: 1 ----- stdout ----- @@ -1176,21 +1201,12 @@ fn fix_applies_safe_fixes_by_default() { #[test] fn fix_applies_unsafe_fixes_with_opt_in() { - assert_cmd_snapshot!( - Command::new(get_cargo_bin(BIN_NAME)) - .args([ - "-", - "--output-format", - "text", - "--isolated", - "--no-cache", - "--select", - "F601,UP034", - "--fix", - "--unsafe-fixes", - ]) - .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), - @r###" + let mut cmd = RuffCheck::default() + .args(["--select", "F601,UP034", "--fix", "--unsafe-fixes"]) + .build(); + assert_cmd_snapshot!(cmd + .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), + @r###" success: true exit_code: 0 ----- stdout ----- @@ -1204,20 +1220,12 @@ fn fix_applies_unsafe_fixes_with_opt_in() { #[test] fn fix_does_not_apply_display_only_fixes() { - assert_cmd_snapshot!( - Command::new(get_cargo_bin(BIN_NAME)) - .args([ - "-", - "--output-format", - "text", - "--isolated", - "--no-cache", - "--select", - "B006", - "--fix", - ]) - .pass_stdin("def add_to_list(item, some_list=[]): ..."), - @r###" + let mut cmd = RuffCheck::default() + .args(["--select", "B006", "--fix"]) + .build(); + assert_cmd_snapshot!(cmd + .pass_stdin("def add_to_list(item, some_list=[]): ..."), + @r###" success: false exit_code: 1 ----- stdout ----- @@ -1230,21 +1238,12 @@ fn fix_does_not_apply_display_only_fixes() { #[test] fn fix_does_not_apply_display_only_fixes_with_unsafe_fixes_enabled() { - assert_cmd_snapshot!( - Command::new(get_cargo_bin(BIN_NAME)) - .args([ - "-", - "--output-format", - "text", - "--isolated", - "--no-cache", - "--select", - "B006", - "--fix", - "--unsafe-fixes", - ]) - .pass_stdin("def add_to_list(item, some_list=[]): ..."), - @r###" + let mut cmd = RuffCheck::default() + .args(["--select", "B006", "--fix", "--unsafe-fixes"]) + .build(); + assert_cmd_snapshot!(cmd + .pass_stdin("def add_to_list(item, some_list=[]): ..."), + @r###" success: false exit_code: 1 ----- stdout ----- @@ -1257,20 +1256,12 @@ fn fix_does_not_apply_display_only_fixes_with_unsafe_fixes_enabled() { #[test] fn fix_only_unsafe_fixes_available() { - assert_cmd_snapshot!( - Command::new(get_cargo_bin(BIN_NAME)) - .args([ - "-", - "--output-format", - "text", - "--isolated", - "--no-cache", - "--select", - "F601", - "--fix", - ]) - .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), - @r###" + let mut cmd = RuffCheck::default() + .args(["--select", "F601", "--fix"]) + .build(); + assert_cmd_snapshot!(cmd + .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), + @r###" success: false exit_code: 1 ----- stdout ----- @@ -1286,20 +1277,12 @@ fn fix_only_unsafe_fixes_available() { #[test] fn fix_only_flag_applies_safe_fixes_by_default() { - assert_cmd_snapshot!( - Command::new(get_cargo_bin(BIN_NAME)) - .args([ - "-", - "--output-format", - "text", - "--isolated", - "--no-cache", - "--select", - "F601,UP034", - "--fix-only", - ]) - .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), - @r###" + let mut cmd = RuffCheck::default() + .args(["--select", "F601,UP034", "--fix-only"]) + .build(); + assert_cmd_snapshot!(cmd + .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), + @r###" success: true exit_code: 0 ----- stdout ----- @@ -1313,21 +1296,12 @@ fn fix_only_flag_applies_safe_fixes_by_default() { #[test] fn fix_only_flag_applies_unsafe_fixes_with_opt_in() { - assert_cmd_snapshot!( - Command::new(get_cargo_bin(BIN_NAME)) - .args([ - "-", - "--output-format", - "text", - "--isolated", - "--no-cache", - "--select", - "F601,UP034", - "--fix-only", - "--unsafe-fixes", - ]) - .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), - @r###" + let mut cmd = RuffCheck::default() + .args(["--select", "F601,UP034", "--fix-only", "--unsafe-fixes"]) + .build(); + assert_cmd_snapshot!(cmd + .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), + @r###" success: true exit_code: 0 ----- stdout ----- @@ -1341,18 +1315,10 @@ fn fix_only_flag_applies_unsafe_fixes_with_opt_in() { #[test] fn diff_shows_safe_fixes_by_default() { - assert_cmd_snapshot!( - Command::new(get_cargo_bin(BIN_NAME)) - .args([ - "-", - "--output-format", - "text", - "--isolated", - "--no-cache", - "--select", - "F601,UP034", - "--diff", - ]) + let mut cmd = RuffCheck::default() + .args(["--select", "F601,UP034", "--diff"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), @r###" success: false @@ -1372,21 +1338,12 @@ fn diff_shows_safe_fixes_by_default() { #[test] fn diff_shows_unsafe_fixes_with_opt_in() { - assert_cmd_snapshot!( - Command::new(get_cargo_bin(BIN_NAME)) - .args([ - "-", - "--output-format", - "text", - "--isolated", - "--no-cache", - "--select", - "F601,UP034", - "--diff", - "--unsafe-fixes", - ]) - .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), - @r###" + let mut cmd = RuffCheck::default() + .args(["--select", "F601,UP034", "--diff", "--unsafe-fixes"]) + .build(); + assert_cmd_snapshot!(cmd + .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), + @r###" success: false exit_code: 1 ----- stdout ----- @@ -1405,21 +1362,12 @@ fn diff_shows_unsafe_fixes_with_opt_in() { #[test] fn diff_does_not_show_display_only_fixes_with_unsafe_fixes_enabled() { - assert_cmd_snapshot!( - Command::new(get_cargo_bin(BIN_NAME)) - .args([ - "-", - "--output-format", - "text", - "--isolated", - "--no-cache", - "--select", - "B006", - "--diff", - "--unsafe-fixes", - ]) - .pass_stdin("def add_to_list(item, some_list=[]): ..."), - @r###" + let mut cmd = RuffCheck::default() + .args(["--select", "B006", "--diff", "--unsafe-fixes"]) + .build(); + assert_cmd_snapshot!(cmd + .pass_stdin("def add_to_list(item, some_list=[]): ..."), + @r###" success: true exit_code: 0 ----- stdout ----- @@ -1430,18 +1378,10 @@ fn diff_does_not_show_display_only_fixes_with_unsafe_fixes_enabled() { #[test] fn diff_only_unsafe_fixes_available() { - assert_cmd_snapshot!( - Command::new(get_cargo_bin(BIN_NAME)) - .args([ - "-", - "--output-format", - "text", - "--isolated", - "--no-cache", - "--select", - "F601", - "--diff", - ]) + let mut cmd = RuffCheck::default() + .args(["--select", "F601", "--diff"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), @r###" success: true @@ -1466,17 +1406,11 @@ extend-unsafe-fixes = ["UP034"] "#, )?; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(["check", "--config"]) - .arg(&ruff_toml) - .arg("-") - .args([ - "--output-format", - "text", - "--no-cache", - "--select", - "F601,UP034", - ]) + let mut cmd = RuffCheck::default() + .config(&ruff_toml) + .args(["--select", "F601,UP034"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), @r###" success: false @@ -1505,17 +1439,11 @@ extend-safe-fixes = ["F601"] "#, )?; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(["check", "--config"]) - .arg(&ruff_toml) - .arg("-") - .args([ - "--output-format", - "text", - "--no-cache", - "--select", - "F601,UP034", - ]) + let mut cmd = RuffCheck::default() + .config(&ruff_toml) + .args(["--select", "F601,UP034"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), @r###" success: false @@ -1546,17 +1474,11 @@ extend-safe-fixes = ["UP034"] "#, )?; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(["check", "--config"]) - .arg(&ruff_toml) - .arg("-") - .args([ - "--output-format", - "text", - "--no-cache", - "--select", - "F601,UP034", - ]) + let mut cmd = RuffCheck::default() + .config(&ruff_toml) + .args(["--select", "F601,UP034"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), @r###" success: false @@ -1588,17 +1510,11 @@ extend-safe-fixes = ["UP03"] "#, )?; - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(["check", "--config"]) - .arg(&ruff_toml) - .arg("-") - .args([ - "--output-format", - "text", - "--no-cache", - "--select", - "F601,UP018,UP034,UP038", - ]) + let mut cmd = RuffCheck::default() + .config(&ruff_toml) + .args(["--select", "F601,UP018,UP034,UP038"]) + .build(); + assert_cmd_snapshot!(cmd .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\nprint(str('foo'))\nisinstance(x, (int, str))\n"), @r###" success: false @@ -1643,12 +1559,12 @@ def log(x, base) -> float: "#; // If we only select the prefix, then everything passes - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(["check", "-", "--config"]) - .arg(&ruff_toml) - .args(["--output-format", "text", "--no-cache", "--select", "D41"]) - .pass_stdin(stdin), - @r###" + let mut cmd = RuffCheck::default() + .config(&ruff_toml) + .args(["--select", "D41"]) + .build(); + assert_cmd_snapshot!(cmd + .pass_stdin(stdin), @r###" success: true exit_code: 0 ----- stdout ----- @@ -1658,12 +1574,12 @@ def log(x, base) -> float: ); // But if we select the exact code, we get an error - assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) - .args(["check", "-", "--config"]) - .arg(&ruff_toml) - .args(["--output-format", "text", "--no-cache", "--select", "D417"]) - .pass_stdin(stdin), - @r###" + let mut cmd = RuffCheck::default() + .config(&ruff_toml) + .args(["--select", "D417"]) + .build(); + assert_cmd_snapshot!(cmd + .pass_stdin(stdin), @r###" success: false exit_code: 1 ----- stdout ----- From 63a87dda63ec6caf808d1c411f96a674678b3551 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Wed, 22 Nov 2023 09:21:28 -0600 Subject: [PATCH 023/197] Move notebook cell logic in separate file (#8813) Small refactor to move cell related logic to it's own file. --- crates/ruff_notebook/src/cell.rs | 170 +++++++++++++++++++++++++++ crates/ruff_notebook/src/lib.rs | 1 + crates/ruff_notebook/src/notebook.rs | 168 -------------------------- 3 files changed, 171 insertions(+), 168 deletions(-) create mode 100644 crates/ruff_notebook/src/cell.rs diff --git a/crates/ruff_notebook/src/cell.rs b/crates/ruff_notebook/src/cell.rs new file mode 100644 index 0000000000000..2251df13311d9 --- /dev/null +++ b/crates/ruff_notebook/src/cell.rs @@ -0,0 +1,170 @@ +use std::fmt; + +use crate::schema::{Cell, SourceValue}; + +impl fmt::Display for SourceValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SourceValue::String(string) => f.write_str(string), + SourceValue::StringArray(string_array) => { + for string in string_array { + f.write_str(string)?; + } + Ok(()) + } + } + } +} + +impl Cell { + /// Return the [`SourceValue`] of the cell. + pub(crate) fn source(&self) -> &SourceValue { + match self { + Cell::Code(cell) => &cell.source, + Cell::Markdown(cell) => &cell.source, + Cell::Raw(cell) => &cell.source, + } + } + + /// Update the [`SourceValue`] of the cell. + pub(crate) fn set_source(&mut self, source: SourceValue) { + match self { + Cell::Code(cell) => cell.source = source, + Cell::Markdown(cell) => cell.source = source, + Cell::Raw(cell) => cell.source = source, + } + } + + /// Return `true` if it's a valid code cell. + /// + /// A valid code cell is a cell where the cell type is [`Cell::Code`] and the + /// source doesn't contain a cell magic. + pub(crate) fn is_valid_code_cell(&self) -> bool { + let source = match self { + Cell::Code(cell) => &cell.source, + _ => return false, + }; + // Ignore cells containing cell magic as they act on the entire cell + // as compared to line magic which acts on a single line. + !match source { + SourceValue::String(string) => Self::is_magic_cell(string.lines()), + SourceValue::StringArray(string_array) => { + Self::is_magic_cell(string_array.iter().map(String::as_str)) + } + } + } + + /// Returns `true` if a cell should be ignored due to the use of cell magics. + fn is_magic_cell<'a>(lines: impl Iterator) -> bool { + let mut lines = lines.peekable(); + + // Detect automatic line magics (automagic), which aren't supported by the parser. If a line + // magic uses automagic, Jupyter doesn't allow following it with non-magic lines anyway, so + // we aren't missing out on any valid Python code. + // + // For example, this is valid: + // ```jupyter + // cat /path/to/file + // cat /path/to/file + // ``` + // + // But this is invalid: + // ```jupyter + // cat /path/to/file + // x = 1 + // ``` + // + // See: https://ipython.readthedocs.io/en/stable/interactive/magics.html + if lines + .peek() + .and_then(|line| line.split_whitespace().next()) + .is_some_and(|token| { + matches!( + token, + "alias" + | "alias_magic" + | "autoawait" + | "autocall" + | "automagic" + | "bookmark" + | "cd" + | "code_wrap" + | "colors" + | "conda" + | "config" + | "debug" + | "dhist" + | "dirs" + | "doctest_mode" + | "edit" + | "env" + | "gui" + | "history" + | "killbgscripts" + | "load" + | "load_ext" + | "loadpy" + | "logoff" + | "logon" + | "logstart" + | "logstate" + | "logstop" + | "lsmagic" + | "macro" + | "magic" + | "mamba" + | "matplotlib" + | "micromamba" + | "notebook" + | "page" + | "pastebin" + | "pdb" + | "pdef" + | "pdoc" + | "pfile" + | "pinfo" + | "pinfo2" + | "pip" + | "popd" + | "pprint" + | "precision" + | "prun" + | "psearch" + | "psource" + | "pushd" + | "pwd" + | "pycat" + | "pylab" + | "quickref" + | "recall" + | "rehashx" + | "reload_ext" + | "rerun" + | "reset" + | "reset_selective" + | "run" + | "save" + | "sc" + | "set_env" + | "sx" + | "system" + | "tb" + | "time" + | "timeit" + | "unalias" + | "unload_ext" + | "who" + | "who_ls" + | "whos" + | "xdel" + | "xmode" + ) + }) + { + return true; + } + + // Detect cell magics (which operate on multiple lines). + lines.any(|line| line.trim_start().starts_with("%%")) + } +} diff --git a/crates/ruff_notebook/src/lib.rs b/crates/ruff_notebook/src/lib.rs index 0d0bb5dc0a9e0..03271682f85ab 100644 --- a/crates/ruff_notebook/src/lib.rs +++ b/crates/ruff_notebook/src/lib.rs @@ -4,6 +4,7 @@ pub use index::*; pub use notebook::*; pub use schema::*; +mod cell; mod index; mod notebook; mod schema; diff --git a/crates/ruff_notebook/src/notebook.rs b/crates/ruff_notebook/src/notebook.rs index 61994e7702648..3deb08be83708 100644 --- a/crates/ruff_notebook/src/notebook.rs +++ b/crates/ruff_notebook/src/notebook.rs @@ -1,5 +1,4 @@ use std::cmp::Ordering; -use std::fmt::Display; use std::fs::File; use std::io::{BufReader, Cursor, Read, Seek, SeekFrom, Write}; use std::path::Path; @@ -35,173 +34,6 @@ pub fn round_trip(path: &Path) -> anyhow::Result { Ok(String::from_utf8(writer)?) } -impl Display for SourceValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - SourceValue::String(string) => f.write_str(string), - SourceValue::StringArray(string_array) => { - for string in string_array { - f.write_str(string)?; - } - Ok(()) - } - } - } -} - -impl Cell { - /// Return the [`SourceValue`] of the cell. - fn source(&self) -> &SourceValue { - match self { - Cell::Code(cell) => &cell.source, - Cell::Markdown(cell) => &cell.source, - Cell::Raw(cell) => &cell.source, - } - } - - /// Update the [`SourceValue`] of the cell. - fn set_source(&mut self, source: SourceValue) { - match self { - Cell::Code(cell) => cell.source = source, - Cell::Markdown(cell) => cell.source = source, - Cell::Raw(cell) => cell.source = source, - } - } - - /// Return `true` if it's a valid code cell. - /// - /// A valid code cell is a cell where the cell type is [`Cell::Code`] and the - /// source doesn't contain a cell magic. - fn is_valid_code_cell(&self) -> bool { - let source = match self { - Cell::Code(cell) => &cell.source, - _ => return false, - }; - // Ignore cells containing cell magic as they act on the entire cell - // as compared to line magic which acts on a single line. - !match source { - SourceValue::String(string) => Self::is_magic_cell(string.lines()), - SourceValue::StringArray(string_array) => { - Self::is_magic_cell(string_array.iter().map(String::as_str)) - } - } - } - - /// Returns `true` if a cell should be ignored due to the use of cell magics. - fn is_magic_cell<'a>(lines: impl Iterator) -> bool { - let mut lines = lines.peekable(); - - // Detect automatic line magics (automagic), which aren't supported by the parser. If a line - // magic uses automagic, Jupyter doesn't allow following it with non-magic lines anyway, so - // we aren't missing out on any valid Python code. - // - // For example, this is valid: - // ```jupyter - // cat /path/to/file - // cat /path/to/file - // ``` - // - // But this is invalid: - // ```jupyter - // cat /path/to/file - // x = 1 - // ``` - // - // See: https://ipython.readthedocs.io/en/stable/interactive/magics.html - if lines - .peek() - .and_then(|line| line.split_whitespace().next()) - .is_some_and(|token| { - matches!( - token, - "alias" - | "alias_magic" - | "autoawait" - | "autocall" - | "automagic" - | "bookmark" - | "cd" - | "code_wrap" - | "colors" - | "conda" - | "config" - | "debug" - | "dhist" - | "dirs" - | "doctest_mode" - | "edit" - | "env" - | "gui" - | "history" - | "killbgscripts" - | "load" - | "load_ext" - | "loadpy" - | "logoff" - | "logon" - | "logstart" - | "logstate" - | "logstop" - | "lsmagic" - | "macro" - | "magic" - | "mamba" - | "matplotlib" - | "micromamba" - | "notebook" - | "page" - | "pastebin" - | "pdb" - | "pdef" - | "pdoc" - | "pfile" - | "pinfo" - | "pinfo2" - | "pip" - | "popd" - | "pprint" - | "precision" - | "prun" - | "psearch" - | "psource" - | "pushd" - | "pwd" - | "pycat" - | "pylab" - | "quickref" - | "recall" - | "rehashx" - | "reload_ext" - | "rerun" - | "reset" - | "reset_selective" - | "run" - | "save" - | "sc" - | "set_env" - | "sx" - | "system" - | "tb" - | "time" - | "timeit" - | "unalias" - | "unload_ext" - | "who" - | "who_ls" - | "whos" - | "xdel" - | "xmode" - ) - }) - { - return true; - } - - // Detect cell magics (which operate on multiple lines). - lines.any(|line| line.trim_start().starts_with("%%")) - } -} - /// An error that can occur while deserializing a Jupyter Notebook. #[derive(Error, Debug)] pub enum NotebookError { From 0cb438dd65dc1fd93afe0ce6fac3bf11bd3b9a14 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Wed, 22 Nov 2023 09:26:25 -0600 Subject: [PATCH 024/197] Avoid `D100` for Jupyter Notebooks (#8816) This PR avoids triggering `D100` for Jupyter Notebooks. Part of #8669 --- .../test/fixtures/pydocstyle/D100.ipynb | 43 +++++++++++++++++++ .../ruff_linter/src/rules/pydocstyle/mod.rs | 1 + .../src/rules/pydocstyle/rules/not_missing.rs | 3 ++ ...s__pydocstyle__tests__D100_D100.ipynb.snap | 4 ++ 4 files changed, 51 insertions(+) create mode 100644 crates/ruff_linter/resources/test/fixtures/pydocstyle/D100.ipynb create mode 100644 crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D100_D100.ipynb.snap diff --git a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D100.ipynb b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D100.ipynb new file mode 100644 index 0000000000000..b060eda1eac3b --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D100.ipynb @@ -0,0 +1,43 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "33faf7ad-a3fd-4ac4-a0c3-52e507ed49df", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello world!\n" + ] + } + ], + "source": [ + "print(\"Hello world!\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (ruff-playground)", + "language": "python", + "name": "ruff-playground" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/crates/ruff_linter/src/rules/pydocstyle/mod.rs b/crates/ruff_linter/src/rules/pydocstyle/mod.rs index fad6a274a41af..205d16abd615f 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/mod.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/mod.rs @@ -62,6 +62,7 @@ mod tests { #[test_case(Rule::UndocumentedPublicMethod, Path::new("D.py"))] #[test_case(Rule::UndocumentedPublicMethod, Path::new("setter.py"))] #[test_case(Rule::UndocumentedPublicModule, Path::new("D.py"))] + #[test_case(Rule::UndocumentedPublicModule, Path::new("D100.ipynb"))] #[test_case( Rule::UndocumentedPublicModule, Path::new("_unrelated/pkg/D100_pub.py") diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/not_missing.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/not_missing.rs index 9288f3ff3731b..312bf596a4237 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/not_missing.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/not_missing.rs @@ -534,6 +534,9 @@ pub(crate) fn not_missing( kind: ModuleKind::Module, .. }) => { + if checker.source_type.is_ipynb() { + return true; + } if checker.enabled(Rule::UndocumentedPublicModule) { checker.diagnostics.push(Diagnostic::new( UndocumentedPublicModule, diff --git a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D100_D100.ipynb.snap b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D100_D100.ipynb.snap new file mode 100644 index 0000000000000..724d6e7d20ae3 --- /dev/null +++ b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D100_D100.ipynb.snap @@ -0,0 +1,4 @@ +--- +source: crates/ruff_linter/src/rules/pydocstyle/mod.rs +--- + From 727e389cac222e64c6f89ea1341f99ee54109b9d Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Wed, 22 Nov 2023 09:27:00 -0600 Subject: [PATCH 025/197] Add `CellOffsets` abstraction (#8814) Refactor `Notebook::cell_offsets` to use an abstract struct for storing the cell offsets. This will allow us to add useful methods on it. --- crates/ruff_linter/src/checkers/imports.rs | 6 ++-- crates/ruff_linter/src/linter.rs | 4 ++- crates/ruff_linter/src/rules/isort/block.rs | 10 ++---- crates/ruff_notebook/src/cell.rs | 34 +++++++++++++++++++++ crates/ruff_notebook/src/lib.rs | 1 + crates/ruff_notebook/src/notebook.rs | 11 ++++--- 6 files changed, 50 insertions(+), 16 deletions(-) diff --git a/crates/ruff_linter/src/checkers/imports.rs b/crates/ruff_linter/src/checkers/imports.rs index 22cbe662f5c8b..5ecb477d85e29 100644 --- a/crates/ruff_linter/src/checkers/imports.rs +++ b/crates/ruff_linter/src/checkers/imports.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use std::path::Path; use ruff_diagnostics::Diagnostic; +use ruff_notebook::CellOffsets; use ruff_python_ast::helpers::to_module_path; use ruff_python_ast::imports::{ImportMap, ModuleImport}; use ruff_python_ast::statement_visitor::StatementVisitor; @@ -17,7 +18,6 @@ use crate::registry::Rule; use crate::rules::isort; use crate::rules::isort::block::{Block, BlockBuilder}; use crate::settings::LinterSettings; -use crate::source_kind::SourceKind; fn extract_import_map(path: &Path, package: Option<&Path>, blocks: &[&Block]) -> Option { let Some(package) = package else { @@ -85,13 +85,13 @@ pub(crate) fn check_imports( stylist: &Stylist, path: &Path, package: Option<&Path>, - source_kind: &SourceKind, source_type: PySourceType, + cell_offsets: Option<&CellOffsets>, ) -> (Vec, Option) { // Extract all import blocks from the AST. let tracker = { let mut tracker = - BlockBuilder::new(locator, directives, source_type.is_stub(), source_kind); + BlockBuilder::new(locator, directives, source_type.is_stub(), cell_offsets); tracker.visit_body(python_ast); tracker }; diff --git a/crates/ruff_linter/src/linter.rs b/crates/ruff_linter/src/linter.rs index 328c6142aeb40..8ebac983ec963 100644 --- a/crates/ruff_linter/src/linter.rs +++ b/crates/ruff_linter/src/linter.rs @@ -9,6 +9,7 @@ use log::error; use rustc_hash::FxHashMap; use ruff_diagnostics::Diagnostic; +use ruff_notebook::Notebook; use ruff_python_ast::imports::ImportMap; use ruff_python_ast::PySourceType; use ruff_python_codegen::Stylist; @@ -149,6 +150,7 @@ pub fn check_path( source_type.is_ipynb(), ) { Ok(python_ast) => { + let cell_offsets = source_kind.as_ipy_notebook().map(Notebook::cell_offsets); if use_ast { diagnostics.extend(check_ast( &python_ast, @@ -173,8 +175,8 @@ pub fn check_path( stylist, path, package, - source_kind, source_type, + cell_offsets, ); imports = module_imports; diagnostics.extend(import_diagnostics); diff --git a/crates/ruff_linter/src/rules/isort/block.rs b/crates/ruff_linter/src/rules/isort/block.rs index 4f24a1c1d2c88..8389fa86a2732 100644 --- a/crates/ruff_linter/src/rules/isort/block.rs +++ b/crates/ruff_linter/src/rules/isort/block.rs @@ -1,7 +1,7 @@ use std::iter::Peekable; use std::slice; -use ruff_notebook::Notebook; +use ruff_notebook::CellOffsets; use ruff_python_ast::statement_visitor::StatementVisitor; use ruff_python_ast::{self as ast, ElifElseClause, ExceptHandler, MatchCase, Stmt}; use ruff_source_file::Locator; @@ -9,7 +9,6 @@ use ruff_text_size::{Ranged, TextRange, TextSize}; use crate::directives::IsortDirectives; use crate::rules::isort::helpers; -use crate::source_kind::SourceKind; /// A block of imports within a Python module. #[derive(Debug, Default)] @@ -43,7 +42,7 @@ impl<'a> BlockBuilder<'a> { locator: &'a Locator<'a>, directives: &'a IsortDirectives, is_stub: bool, - source_kind: &'a SourceKind, + cell_offsets: Option<&'a CellOffsets>, ) -> Self { Self { locator, @@ -52,10 +51,7 @@ impl<'a> BlockBuilder<'a> { splits: directives.splits.iter().peekable(), exclusions: &directives.exclusions, nested: false, - cell_offsets: source_kind - .as_ipy_notebook() - .map(Notebook::cell_offsets) - .map(|offsets| offsets.iter().peekable()), + cell_offsets: cell_offsets.map(|offsets| offsets.iter().peekable()), } } diff --git a/crates/ruff_notebook/src/cell.rs b/crates/ruff_notebook/src/cell.rs index 2251df13311d9..c992febd89395 100644 --- a/crates/ruff_notebook/src/cell.rs +++ b/crates/ruff_notebook/src/cell.rs @@ -1,4 +1,7 @@ use std::fmt; +use std::ops::{Deref, DerefMut}; + +use ruff_text_size::TextSize; use crate::schema::{Cell, SourceValue}; @@ -168,3 +171,34 @@ impl Cell { lines.any(|line| line.trim_start().starts_with("%%")) } } + +/// Cell offsets are used to keep track of the start and end offsets of each +/// cell in the concatenated source code. +#[derive(Clone, Debug, Default, PartialEq)] +pub struct CellOffsets(Vec); + +impl CellOffsets { + /// Create a new [`CellOffsets`] with the given capacity. + pub(crate) fn with_capacity(capacity: usize) -> Self { + Self(Vec::with_capacity(capacity)) + } + + /// Push a new offset to the end of the [`CellOffsets`]. + pub(crate) fn push(&mut self, offset: TextSize) { + self.0.push(offset); + } +} + +impl Deref for CellOffsets { + type Target = [TextSize]; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for CellOffsets { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} diff --git a/crates/ruff_notebook/src/lib.rs b/crates/ruff_notebook/src/lib.rs index 03271682f85ab..e95c483a2f5f0 100644 --- a/crates/ruff_notebook/src/lib.rs +++ b/crates/ruff_notebook/src/lib.rs @@ -1,5 +1,6 @@ //! Utils for reading and writing jupyter notebooks +pub use cell::*; pub use index::*; pub use notebook::*; pub use schema::*; diff --git a/crates/ruff_notebook/src/notebook.rs b/crates/ruff_notebook/src/notebook.rs index 3deb08be83708..a6714fa12b496 100644 --- a/crates/ruff_notebook/src/notebook.rs +++ b/crates/ruff_notebook/src/notebook.rs @@ -15,6 +15,7 @@ use ruff_diagnostics::{SourceMap, SourceMarker}; use ruff_source_file::{NewlineWithTrailingNewline, OneIndexed, UniversalNewlineIterator}; use ruff_text_size::TextSize; +use crate::cell::CellOffsets; use crate::index::NotebookIndex; use crate::schema::{Cell, RawNotebook, SortAlphabetically, SourceValue}; @@ -65,7 +66,7 @@ pub struct Notebook { raw: RawNotebook, /// The offsets of each cell in the concatenated source code. This includes /// the first and last character offsets as well. - cell_offsets: Vec, + cell_offsets: CellOffsets, /// The cell index of all valid code cells in the notebook. valid_code_cells: Vec, /// Flag to indicate if the JSON string of the notebook has a trailing newline. @@ -128,7 +129,7 @@ impl Notebook { let mut contents = Vec::with_capacity(valid_code_cells.len()); let mut current_offset = TextSize::from(0); - let mut cell_offsets = Vec::with_capacity(valid_code_cells.len()); + let mut cell_offsets = CellOffsets::with_capacity(valid_code_cells.len()); cell_offsets.push(TextSize::from(0)); for &idx in &valid_code_cells { @@ -324,9 +325,9 @@ impl Notebook { self.index.take().unwrap_or_else(|| self.build_index()) } - /// Return the cell offsets for the concatenated source code corresponding + /// Return the [`CellOffsets`] for the concatenated source code corresponding /// the Jupyter notebook. - pub fn cell_offsets(&self) -> &[TextSize] { + pub fn cell_offsets(&self) -> &CellOffsets { &self.cell_offsets } @@ -503,7 +504,7 @@ print("after empty cells") } ); assert_eq!( - notebook.cell_offsets(), + notebook.cell_offsets().as_ref(), &[ 0.into(), 90.into(), From 5b726f70f49497cfcf49bd808be827056eac05e8 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Wed, 22 Nov 2023 09:33:23 -0600 Subject: [PATCH 026/197] Avoid `B015`,`B018` for last expression in a cell (#8815) ## Summary This PR updates `B015` and `B018` to ignore last top-level expressions in each cell of a Jupyter Notebook. Part of #8669 ## Test Plan Add test cases for both rules and update the snapshots. --- .../test/fixtures/flake8_bugbear/B015.ipynb | 149 ++++++++++++++++++ .../test/fixtures/flake8_bugbear/B018.ipynb | 149 ++++++++++++++++++ crates/ruff_linter/src/checkers/ast/mod.rs | 12 ++ crates/ruff_linter/src/linter.rs | 1 + .../src/rules/flake8_bugbear/helpers.rs | 28 ++++ .../src/rules/flake8_bugbear/mod.rs | 3 + .../rules/useless_comparison.rs | 15 ++ .../rules/useless_expression.rs | 15 ++ ...lake8_bugbear__tests__B015_B015.ipynb.snap | 34 ++++ ...lake8_bugbear__tests__B018_B018.ipynb.snap | 34 ++++ crates/ruff_notebook/src/cell.rs | 15 +- 11 files changed, 454 insertions(+), 1 deletion(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B015.ipynb create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B018.ipynb create mode 100644 crates/ruff_linter/src/rules/flake8_bugbear/helpers.rs create mode 100644 crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B015_B015.ipynb.snap create mode 100644 crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B018_B018.ipynb.snap diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B015.ipynb b/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B015.ipynb new file mode 100644 index 0000000000000..1a1446b60d54c --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B015.ipynb @@ -0,0 +1,149 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "33faf7ad-a3fd-4ac4-a0c3-52e507ed49df", + "metadata": {}, + "outputs": [], + "source": [ + "x = 1" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "481fb4bf-c1b9-47da-927f-3cfdfe4b49ec", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Simple case\n", + "x == 1" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2f0c65a5-0a0e-4080-afce-5a8ed0d706df", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Only skip the last expression\n", + "x == 1 # B018\n", + "x == 1" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "5a3fd75d-26d9-44f7-b013-1684aabfd0ae", + "metadata": {}, + "outputs": [], + "source": [ + "# Nested expressions isn't relevant\n", + "if True:\n", + " x == 1" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "e00e1afa-b76c-4774-be2a-7223641579e4", + "metadata": {}, + "outputs": [], + "source": [ + "# Semicolons shouldn't affect the output\n", + "x == 1;" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "05eab5b9-e2ba-4954-8ef3-b035a79573fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Semicolons with multiple expressions\n", + "x == 1; x == 1" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "9cbbddc5-83fc-4fdb-81ab-53a3912ae898", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Comments, newlines and whitespace\n", + "x == 1 # comment\n", + "\n", + "# another comment" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (ruff-playground)", + "language": "python", + "name": "ruff-playground" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B018.ipynb b/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B018.ipynb new file mode 100644 index 0000000000000..35c501611c89f --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bugbear/B018.ipynb @@ -0,0 +1,149 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "33faf7ad-a3fd-4ac4-a0c3-52e507ed49df", + "metadata": {}, + "outputs": [], + "source": [ + "x = 1" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "481fb4bf-c1b9-47da-927f-3cfdfe4b49ec", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Simple case\n", + "x" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2f0c65a5-0a0e-4080-afce-5a8ed0d706df", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Only skip the last expression\n", + "x # B018\n", + "x" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "5a3fd75d-26d9-44f7-b013-1684aabfd0ae", + "metadata": {}, + "outputs": [], + "source": [ + "# Nested expressions isn't relevant\n", + "if True:\n", + " x" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "e00e1afa-b76c-4774-be2a-7223641579e4", + "metadata": {}, + "outputs": [], + "source": [ + "# Semicolons shouldn't affect the output\n", + "x;" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "05eab5b9-e2ba-4954-8ef3-b035a79573fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Semicolons with multiple expressions\n", + "x; x" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "9cbbddc5-83fc-4fdb-81ab-53a3912ae898", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Comments, newlines and whitespace\n", + "x # comment\n", + "\n", + "# another comment" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (ruff-playground)", + "language": "python", + "name": "ruff-playground" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 0a6ee16b15354..231687f66c23b 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -37,6 +37,7 @@ use ruff_python_ast::{ use ruff_text_size::{Ranged, TextRange, TextSize}; use ruff_diagnostics::{Diagnostic, IsolationLevel}; +use ruff_notebook::CellOffsets; use ruff_python_ast::all::{extract_all_names, DunderAllFlags}; use ruff_python_ast::helpers::{ collect_import_from_member, extract_handled_exceptions, to_module_path, @@ -78,6 +79,8 @@ pub(crate) struct Checker<'a> { module_path: Option<&'a [String]>, /// The [`PySourceType`] of the current file. pub(crate) source_type: PySourceType, + /// The [`CellOffsets`] for the current file, if it's a Jupyter notebook. + cell_offsets: Option<&'a CellOffsets>, /// The [`flags::Noqa`] for the current analysis (i.e., whether to respect suppression /// comments). noqa: flags::Noqa, @@ -120,6 +123,7 @@ impl<'a> Checker<'a> { indexer: &'a Indexer, importer: Importer<'a>, source_type: PySourceType, + cell_offsets: Option<&'a CellOffsets>, ) -> Checker<'a> { Checker { settings, @@ -137,6 +141,7 @@ impl<'a> Checker<'a> { deferred: Deferred::default(), diagnostics: Vec::default(), flake8_bugbear_seen: Vec::default(), + cell_offsets, } } } @@ -225,6 +230,11 @@ impl<'a> Checker<'a> { self.package } + /// The [`CellOffsets`] for the current file, if it's a Jupyter notebook. + pub(crate) const fn cell_offsets(&self) -> Option<&'a CellOffsets> { + self.cell_offsets + } + /// Returns whether the given rule should be checked. #[inline] pub(crate) const fn enabled(&self, rule: Rule) -> bool { @@ -1942,6 +1952,7 @@ pub(crate) fn check_ast( path: &Path, package: Option<&Path>, source_type: PySourceType, + cell_offsets: Option<&CellOffsets>, ) -> Vec { let module_path = package.and_then(|package| to_module_path(package, path)); let module = Module { @@ -1970,6 +1981,7 @@ pub(crate) fn check_ast( indexer, Importer::new(python_ast, locator, stylist), source_type, + cell_offsets, ); checker.bind_builtins(); diff --git a/crates/ruff_linter/src/linter.rs b/crates/ruff_linter/src/linter.rs index 8ebac983ec963..d14ef022217b2 100644 --- a/crates/ruff_linter/src/linter.rs +++ b/crates/ruff_linter/src/linter.rs @@ -163,6 +163,7 @@ pub fn check_path( path, package, source_type, + cell_offsets, )); } if use_imports { diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/helpers.rs b/crates/ruff_linter/src/rules/flake8_bugbear/helpers.rs new file mode 100644 index 0000000000000..2745153c86b34 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bugbear/helpers.rs @@ -0,0 +1,28 @@ +use ruff_notebook::CellOffsets; +use ruff_python_semantic::SemanticModel; +use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer}; +use ruff_source_file::Locator; +use ruff_text_size::{Ranged, TextRange}; + +/// Return `true` if the statement containing the current expression is the last +/// top-level expression in the cell. This assumes that the source is a Jupyter +/// Notebook. +pub(super) fn at_last_top_level_expression_in_cell( + semantic: &SemanticModel, + locator: &Locator, + cell_offsets: Option<&CellOffsets>, +) -> bool { + if !semantic.at_top_level() { + return false; + } + let current_statement_end = semantic.current_statement().end(); + cell_offsets + .and_then(|cell_offsets| cell_offsets.containing_range(current_statement_end)) + .is_some_and(|cell_range| { + SimpleTokenizer::new( + locator.contents(), + TextRange::new(current_statement_end, cell_range.end()), + ) + .all(|token| token.kind() == SimpleTokenKind::Semi || token.kind().is_trivia()) + }) +} diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/mod.rs b/crates/ruff_linter/src/rules/flake8_bugbear/mod.rs index e31681ca43a5b..43f9aef102c9c 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/mod.rs @@ -1,4 +1,5 @@ //! Rules from [flake8-bugbear](https://pypi.org/project/flake8-bugbear/). +pub(crate) mod helpers; pub(crate) mod rules; pub mod settings; @@ -54,8 +55,10 @@ mod tests { #[test_case(Rule::UnreliableCallableCheck, Path::new("B004.py"))] #[test_case(Rule::UnusedLoopControlVariable, Path::new("B007.py"))] #[test_case(Rule::UselessComparison, Path::new("B015.py"))] + #[test_case(Rule::UselessComparison, Path::new("B015.ipynb"))] #[test_case(Rule::UselessContextlibSuppress, Path::new("B022.py"))] #[test_case(Rule::UselessExpression, Path::new("B018.py"))] + #[test_case(Rule::UselessExpression, Path::new("B018.ipynb"))] fn rules(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/useless_comparison.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/useless_comparison.rs index d5f62107d46e0..373ef37732b6e 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/useless_comparison.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/useless_comparison.rs @@ -5,6 +5,8 @@ use ruff_text_size::Ranged; use crate::checkers::ast::Checker; +use super::super::helpers::at_last_top_level_expression_in_cell; + /// ## What it does /// Checks for useless comparisons. /// @@ -41,6 +43,19 @@ impl Violation for UselessComparison { /// B015 pub(crate) fn useless_comparison(checker: &mut Checker, expr: &Expr) { if expr.is_compare_expr() { + // For Jupyter Notebooks, ignore the last top-level expression for each cell. + // This is because it's common to have a cell that ends with an expression + // to display it's value. + if checker.source_type.is_ipynb() + && at_last_top_level_expression_in_cell( + checker.semantic(), + checker.locator(), + checker.cell_offsets(), + ) + { + return; + } + checker .diagnostics .push(Diagnostic::new(UselessComparison, expr.range())); diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/useless_expression.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/useless_expression.rs index 65da45af782c9..5c4f22c46c7f3 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/useless_expression.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/useless_expression.rs @@ -6,6 +6,8 @@ use ruff_text_size::Ranged; use crate::checkers::ast::Checker; +use super::super::helpers::at_last_top_level_expression_in_cell; + /// ## What it does /// Checks for useless expressions. /// @@ -59,6 +61,19 @@ pub(crate) fn useless_expression(checker: &mut Checker, value: &Expr) { return; } + // For Jupyter Notebooks, ignore the last top-level expression for each cell. + // This is because it's common to have a cell that ends with an expression + // to display it's value. + if checker.source_type.is_ipynb() + && at_last_top_level_expression_in_cell( + checker.semantic(), + checker.locator(), + checker.cell_offsets(), + ) + { + return; + } + // Ignore statements that have side effects. if contains_effect(value, |id| checker.semantic().is_builtin(id)) { // Flag attributes as useless expressions, even if they're attached to calls or other diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B015_B015.ipynb.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B015_B015.ipynb.snap new file mode 100644 index 0000000000000..acdae1edf4f29 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B015_B015.ipynb.snap @@ -0,0 +1,34 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs +--- +B015.ipynb:5:1: B015 Pointless comparison. Did you mean to assign a value? Otherwise, prepend `assert` or remove it. + | +3 | x == 1 +4 | # Only skip the last expression +5 | x == 1 # B018 + | ^^^^^^ B015 +6 | x == 1 +7 | # Nested expressions isn't relevant + | + +B015.ipynb:9:5: B015 Pointless comparison. Did you mean to assign a value? Otherwise, prepend `assert` or remove it. + | + 7 | # Nested expressions isn't relevant + 8 | if True: + 9 | x == 1 + | ^^^^^^ B015 +10 | # Semicolons shouldn't affect the output +11 | x == 1; + | + +B015.ipynb:13:1: B015 Pointless comparison. Did you mean to assign a value? Otherwise, prepend `assert` or remove it. + | +11 | x == 1; +12 | # Semicolons with multiple expressions +13 | x == 1; x == 1 + | ^^^^^^ B015 +14 | # Comments, newlines and whitespace +15 | x == 1 # comment + | + + diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B018_B018.ipynb.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B018_B018.ipynb.snap new file mode 100644 index 0000000000000..41211ffcaef49 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B018_B018.ipynb.snap @@ -0,0 +1,34 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs +--- +B018.ipynb:5:1: B018 Found useless expression. Either assign it to a variable or remove it. + | +3 | x +4 | # Only skip the last expression +5 | x # B018 + | ^ B018 +6 | x +7 | # Nested expressions isn't relevant + | + +B018.ipynb:9:5: B018 Found useless expression. Either assign it to a variable or remove it. + | + 7 | # Nested expressions isn't relevant + 8 | if True: + 9 | x + | ^ B018 +10 | # Semicolons shouldn't affect the output +11 | x; + | + +B018.ipynb:13:1: B018 Found useless expression. Either assign it to a variable or remove it. + | +11 | x; +12 | # Semicolons with multiple expressions +13 | x; x + | ^ B018 +14 | # Comments, newlines and whitespace +15 | x # comment + | + + diff --git a/crates/ruff_notebook/src/cell.rs b/crates/ruff_notebook/src/cell.rs index c992febd89395..1d039e7a67483 100644 --- a/crates/ruff_notebook/src/cell.rs +++ b/crates/ruff_notebook/src/cell.rs @@ -1,7 +1,9 @@ use std::fmt; use std::ops::{Deref, DerefMut}; -use ruff_text_size::TextSize; +use itertools::Itertools; + +use ruff_text_size::{TextRange, TextSize}; use crate::schema::{Cell, SourceValue}; @@ -187,6 +189,17 @@ impl CellOffsets { pub(crate) fn push(&mut self, offset: TextSize) { self.0.push(offset); } + + /// Returns the range of the cell containing the given offset, if any. + pub fn containing_range(&self, offset: TextSize) -> Option { + self.iter().tuple_windows().find_map(|(start, end)| { + if *start <= offset && offset < *end { + Some(TextRange::new(*start, *end)) + } else { + None + } + }) + } } impl Deref for CellOffsets { From 8365d2e0fd465edd38fbc378569c1a22dbac4379 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Thu, 23 Nov 2023 07:40:57 -0600 Subject: [PATCH 027/197] Avoid `E703` for last expression in a cell (#8821) ## Summary This PR updates the `E703` rule to avoid flagging any semicolons if they're present after the last expression in a notebook cell. These are intended to hide the cell output. Part of #8669 ## Test Plan Add test notebook and update the snapshots. --- .../test/fixtures/pycodestyle/E703.ipynb | 94 +++++++++++++++++++ crates/ruff_linter/src/checkers/tokens.rs | 16 +++- crates/ruff_linter/src/linter.rs | 3 +- .../ruff_linter/src/rules/pycodestyle/mod.rs | 1 + .../pycodestyle/rules/compound_statements.rs | 67 ++++++++++--- ...__pycodestyle__tests__E703_E703.ipynb.snap | 46 +++++++++ 6 files changed, 212 insertions(+), 15 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/pycodestyle/E703.ipynb create mode 100644 crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E703_E703.ipynb.snap diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E703.ipynb b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E703.ipynb new file mode 100644 index 0000000000000..97606b62f3792 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E703.ipynb @@ -0,0 +1,94 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "33faf7ad-a3fd-4ac4-a0c3-52e507ed49df", + "metadata": {}, + "outputs": [], + "source": [ + "x = 1" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "481fb4bf-c1b9-47da-927f-3cfdfe4b49ec", + "metadata": {}, + "outputs": [], + "source": [ + "# Simple case\n", + "x;" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2f0c65a5-0a0e-4080-afce-5a8ed0d706df", + "metadata": {}, + "outputs": [], + "source": [ + "# Only skip the last expression\n", + "x; # E703\n", + "x;" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "5a3fd75d-26d9-44f7-b013-1684aabfd0ae", + "metadata": {}, + "outputs": [], + "source": [ + "# Nested expressions isn't relevant\n", + "if True:\n", + " x;" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "05eab5b9-e2ba-4954-8ef3-b035a79573fe", + "metadata": {}, + "outputs": [], + "source": [ + "# Semicolons with multiple expressions\n", + "x; x;" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "9cbbddc5-83fc-4fdb-81ab-53a3912ae898", + "metadata": {}, + "outputs": [], + "source": [ + "# Comments, newlines and whitespace\n", + "x; # comment\n", + "\n", + "# another comment" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (ruff-playground)", + "language": "python", + "name": "ruff-playground" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/crates/ruff_linter/src/checkers/tokens.rs b/crates/ruff_linter/src/checkers/tokens.rs index b0f563c23b91f..e9d23ed91c626 100644 --- a/crates/ruff_linter/src/checkers/tokens.rs +++ b/crates/ruff_linter/src/checkers/tokens.rs @@ -2,6 +2,8 @@ use std::path::Path; +use ruff_notebook::CellOffsets; +use ruff_python_ast::PySourceType; use ruff_python_parser::lexer::LexResult; use ruff_python_parser::Tok; @@ -25,7 +27,8 @@ pub(crate) fn check_tokens( locator: &Locator, indexer: &Indexer, settings: &LinterSettings, - is_stub: bool, + source_type: PySourceType, + cell_offsets: Option<&CellOffsets>, ) -> Vec { let mut diagnostics: Vec = vec![]; @@ -112,7 +115,14 @@ pub(crate) fn check_tokens( Rule::MultipleStatementsOnOneLineSemicolon, Rule::UselessSemicolon, ]) { - pycodestyle::rules::compound_statements(&mut diagnostics, tokens, locator, indexer); + pycodestyle::rules::compound_statements( + &mut diagnostics, + tokens, + locator, + indexer, + source_type, + cell_offsets, + ); } if settings.rules.enabled(Rule::AvoidableEscapedQuote) && settings.flake8_quotes.avoid_escape { @@ -156,7 +166,7 @@ pub(crate) fn check_tokens( pyupgrade::rules::extraneous_parentheses(&mut diagnostics, tokens, locator); } - if is_stub && settings.rules.enabled(Rule::TypeCommentInStub) { + if source_type.is_stub() && settings.rules.enabled(Rule::TypeCommentInStub) { flake8_pyi::rules::type_comment_in_stub(&mut diagnostics, locator, indexer); } diff --git a/crates/ruff_linter/src/linter.rs b/crates/ruff_linter/src/linter.rs index d14ef022217b2..f6382e8b30349 100644 --- a/crates/ruff_linter/src/linter.rs +++ b/crates/ruff_linter/src/linter.rs @@ -108,7 +108,8 @@ pub fn check_path( locator, indexer, settings, - source_type.is_stub(), + source_type, + source_kind.as_ipy_notebook().map(Notebook::cell_offsets), )); } diff --git a/crates/ruff_linter/src/rules/pycodestyle/mod.rs b/crates/ruff_linter/src/rules/pycodestyle/mod.rs index 583e696a36b0c..112be16261155 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/mod.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/mod.rs @@ -53,6 +53,7 @@ mod tests { #[test_case(Rule::TrueFalseComparison, Path::new("E712.py"))] #[test_case(Rule::TypeComparison, Path::new("E721.py"))] #[test_case(Rule::UselessSemicolon, Path::new("E70.py"))] + #[test_case(Rule::UselessSemicolon, Path::new("E703.ipynb"))] fn rules(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/compound_statements.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/compound_statements.rs index 6dcdd19c8b4ec..2b7434dd23c17 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/compound_statements.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/compound_statements.rs @@ -1,6 +1,8 @@ +use ruff_notebook::CellOffsets; +use ruff_python_ast::PySourceType; use ruff_python_parser::lexer::LexResult; use ruff_python_parser::Tok; -use ruff_text_size::TextRange; +use ruff_text_size::{TextRange, TextSize}; use ruff_diagnostics::{AlwaysFixableViolation, Violation}; use ruff_diagnostics::{Diagnostic, Edit, Fix}; @@ -101,6 +103,8 @@ pub(crate) fn compound_statements( lxr: &[LexResult], locator: &Locator, indexer: &Indexer, + source_type: PySourceType, + cell_offsets: Option<&CellOffsets>, ) { // Track the last seen instance of a variety of tokens. let mut colon = None; @@ -127,7 +131,13 @@ pub(crate) fn compound_statements( let mut sqb_count = 0u32; let mut brace_count = 0u32; - for &(ref tok, range) in lxr.iter().flatten() { + // Track indentation. + let mut indent = 0u32; + + // Keep the token iterator to perform lookaheads. + let mut tokens = lxr.iter().flatten(); + + while let Some(&(ref tok, range)) = tokens.next() { match tok { Tok::Lpar => { par_count = par_count.saturating_add(1); @@ -153,6 +163,12 @@ pub(crate) fn compound_statements( continue; } } + Tok::Indent => { + indent = indent.saturating_add(1); + } + Tok::Dedent => { + indent = indent.saturating_sub(1); + } _ => {} } @@ -163,15 +179,24 @@ pub(crate) fn compound_statements( match tok { Tok::Newline => { if let Some((start, end)) = semi { - let mut diagnostic = - Diagnostic::new(UselessSemicolon, TextRange::new(start, end)); - diagnostic.set_fix(Fix::safe_edit(Edit::deletion( - indexer - .preceded_by_continuations(start, locator) - .unwrap_or(start), - end, - ))); - diagnostics.push(diagnostic); + if !(source_type.is_ipynb() + && indent == 0 + && cell_offsets + .and_then(|cell_offsets| cell_offsets.containing_range(range.start())) + .is_some_and(|cell_range| { + !has_non_trivia_tokens_till(tokens.clone(), cell_range.end()) + })) + { + let mut diagnostic = + Diagnostic::new(UselessSemicolon, TextRange::new(start, end)); + diagnostic.set_fix(Fix::safe_edit(Edit::deletion( + indexer + .preceded_by_continuations(start, locator) + .unwrap_or(start), + end, + ))); + diagnostics.push(diagnostic); + } } // Reset. @@ -309,3 +334,23 @@ pub(crate) fn compound_statements( }; } } + +/// Returns `true` if there are any non-trivia tokens from the given token +/// iterator till the given end offset. +fn has_non_trivia_tokens_till<'a>( + tokens: impl Iterator, + cell_end: TextSize, +) -> bool { + for &(ref tok, tok_range) in tokens { + if tok_range.start() >= cell_end { + return false; + } + if !matches!( + tok, + Tok::Newline | Tok::Comment(_) | Tok::EndOfFile | Tok::NonLogicalNewline + ) { + return true; + } + } + false +} diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E703_E703.ipynb.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E703_E703.ipynb.snap new file mode 100644 index 0000000000000..068f245637b5c --- /dev/null +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E703_E703.ipynb.snap @@ -0,0 +1,46 @@ +--- +source: crates/ruff_linter/src/rules/pycodestyle/mod.rs +--- +E703.ipynb:5:2: E703 [*] Statement ends with an unnecessary semicolon + | +3 | x; +4 | # Only skip the last expression +5 | x; # E703 + | ^ E703 +6 | x; +7 | # Nested expressions isn't relevant + | + = help: Remove unnecessary semicolon + +ℹ Safe fix +2 2 | # Simple case +3 3 | x; +4 4 | # Only skip the last expression +5 |-x; # E703 + 5 |+x # E703 +6 6 | x; +7 7 | # Nested expressions isn't relevant +8 8 | if True: + +E703.ipynb:9:6: E703 [*] Statement ends with an unnecessary semicolon + | + 7 | # Nested expressions isn't relevant + 8 | if True: + 9 | x; + | ^ E703 +10 | # Semicolons with multiple expressions +11 | x; x; + | + = help: Remove unnecessary semicolon + +ℹ Safe fix +6 6 | x; +7 7 | # Nested expressions isn't relevant +8 8 | if True: +9 |- x; + 9 |+ x +10 10 | # Semicolons with multiple expressions +11 11 | x; x; +12 12 | # Comments, newlines and whitespace + + From 852a8f4a4fa71622332cc2e72eb96fd6f8b0391e Mon Sep 17 00:00:00 2001 From: Samuel Cormier-Iijima Date: Fri, 24 Nov 2023 10:24:57 -0500 Subject: [PATCH 028/197] [PIE796] don't report when using ellipses for enum values in stub files (#8825) ## Summary Just ignores ellipses as enum values inside stub files. Fixes #8818. --- .../test/fixtures/flake8_pie/PIE796.py | 6 ++++++ .../test/fixtures/flake8_pie/PIE796.pyi | 7 +++++++ crates/ruff_linter/src/rules/flake8_pie/mod.rs | 1 + .../rules/flake8_pie/rules/non_unique_enums.rs | 12 ++++++++++-- ...es__flake8_pie__tests__PIE796_PIE796.py.snap | 17 +++++++++++++++++ ...s__flake8_pie__tests__PIE796_PIE796.pyi.snap | 4 ++++ crates/ruff_python_ast/src/comparable.rs | 4 ++-- 7 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE796.pyi create mode 100644 crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE796_PIE796.pyi.snap diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE796.py b/crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE796.py index 227ae8acc27b0..585e38b4d1b0c 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE796.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE796.py @@ -64,3 +64,9 @@ class FakeEnum10(enum.Enum): A = enum.auto() B = enum.auto() C = enum.auto() + + +class FakeEnum10(enum.Enum): + A = ... + B = ... # PIE796 + C = ... # PIE796 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE796.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE796.pyi new file mode 100644 index 0000000000000..ccfb75a2846a6 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE796.pyi @@ -0,0 +1,7 @@ +import enum + + +class FakeEnum1(enum.Enum): + A = ... + B = ... + C = ... diff --git a/crates/ruff_linter/src/rules/flake8_pie/mod.rs b/crates/ruff_linter/src/rules/flake8_pie/mod.rs index 238c239add39e..046b43b097aae 100644 --- a/crates/ruff_linter/src/rules/flake8_pie/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_pie/mod.rs @@ -21,6 +21,7 @@ mod tests { #[test_case(Rule::UnnecessarySpread, Path::new("PIE800.py"))] #[test_case(Rule::ReimplementedContainerBuiltin, Path::new("PIE807.py"))] #[test_case(Rule::NonUniqueEnums, Path::new("PIE796.py"))] + #[test_case(Rule::NonUniqueEnums, Path::new("PIE796.pyi"))] fn rules(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/flake8_pie/rules/non_unique_enums.rs b/crates/ruff_linter/src/rules/flake8_pie/rules/non_unique_enums.rs index 6a0e62b47c307..36f54f444f88d 100644 --- a/crates/ruff_linter/src/rules/flake8_pie/rules/non_unique_enums.rs +++ b/crates/ruff_linter/src/rules/flake8_pie/rules/non_unique_enums.rs @@ -4,7 +4,7 @@ use ruff_diagnostics::Diagnostic; use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::comparable::ComparableExpr; -use ruff_python_ast::{self as ast, Expr, Stmt}; +use ruff_python_ast::{self as ast, Expr, PySourceType, Stmt}; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -84,7 +84,15 @@ pub(crate) fn non_unique_enums(checker: &mut Checker, parent: &Stmt, body: &[Stm } } - if !seen_targets.insert(ComparableExpr::from(value)) { + let comparable = ComparableExpr::from(value); + + if checker.source_type == PySourceType::Stub + && comparable == ComparableExpr::EllipsisLiteral + { + continue; + } + + if !seen_targets.insert(comparable) { let diagnostic = Diagnostic::new( NonUniqueEnums { value: checker.generator().expr(value), diff --git a/crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE796_PIE796.py.snap b/crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE796_PIE796.py.snap index df58500ba5ef4..e10325ed1b541 100644 --- a/crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE796_PIE796.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE796_PIE796.py.snap @@ -57,4 +57,21 @@ PIE796.py:54:5: PIE796 Enum contains duplicate value: `2` | ^^^^^ PIE796 | +PIE796.py:71:5: PIE796 Enum contains duplicate value: `...` + | +69 | class FakeEnum10(enum.Enum): +70 | A = ... +71 | B = ... # PIE796 + | ^^^^^^^ PIE796 +72 | C = ... # PIE796 + | + +PIE796.py:72:5: PIE796 Enum contains duplicate value: `...` + | +70 | A = ... +71 | B = ... # PIE796 +72 | C = ... # PIE796 + | ^^^^^^^ PIE796 + | + diff --git a/crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE796_PIE796.pyi.snap b/crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE796_PIE796.pyi.snap new file mode 100644 index 0000000000000..5c6e954faaa5a --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE796_PIE796.pyi.snap @@ -0,0 +1,4 @@ +--- +source: crates/ruff_linter/src/rules/flake8_pie/mod.rs +--- + diff --git a/crates/ruff_python_ast/src/comparable.rs b/crates/ruff_python_ast/src/comparable.rs index 208b97d05505e..dbbe6e75a351c 100644 --- a/crates/ruff_python_ast/src/comparable.rs +++ b/crates/ruff_python_ast/src/comparable.rs @@ -766,7 +766,7 @@ pub enum ComparableExpr<'a> { NumberLiteral(ExprNumberLiteral<'a>), BoolLiteral(ExprBoolLiteral<'a>), NoneLiteral, - EllispsisLiteral, + EllipsisLiteral, Attribute(ExprAttribute<'a>), Subscript(ExprSubscript<'a>), Starred(ExprStarred<'a>), @@ -964,7 +964,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> { Self::BoolLiteral(ExprBoolLiteral { value }) } ast::Expr::NoneLiteral(_) => Self::NoneLiteral, - ast::Expr::EllipsisLiteral(_) => Self::EllispsisLiteral, + ast::Expr::EllipsisLiteral(_) => Self::EllipsisLiteral, ast::Expr::Attribute(ast::ExprAttribute { value, attr, From 2590aa30ae4857cdb9e3e7ec64c52715de517fe2 Mon Sep 17 00:00:00 2001 From: Chaojie Date: Sat, 25 Nov 2023 01:46:06 +0800 Subject: [PATCH 029/197] [flake8-bandit] Implement tarfile-unsafe-members (S202) (#8829) See: https://github.com/astral-sh/ruff/issues/1646. Bandit origin: https://github.com/PyCQA/bandit/blob/main/bandit/plugins/tarfile_unsafe_members.py --- .../test/fixtures/flake8_bandit/S202.py | 65 ++++++++++++++++ .../src/checkers/ast/analyze/expression.rs | 3 + crates/ruff_linter/src/codes.rs | 1 + .../src/rules/flake8_bandit/mod.rs | 1 + .../src/rules/flake8_bandit/rules/mod.rs | 2 + .../rules/tarfile_unsafe_members.rs | 75 +++++++++++++++++++ ...s__flake8_bandit__tests__S202_S202.py.snap | 49 ++++++++++++ ruff.schema.json | 1 + 8 files changed, 197 insertions(+) create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S202.py create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/rules/tarfile_unsafe_members.rs create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S202_S202.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S202.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S202.py new file mode 100644 index 0000000000000..bba1deda4ab36 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S202.py @@ -0,0 +1,65 @@ +import sys +import tarfile +import tempfile + + +def unsafe_archive_handler(filename): + tar = tarfile.open(filename) + tar.extractall(path=tempfile.mkdtemp()) + tar.close() + + +def managed_members_archive_handler(filename): + tar = tarfile.open(filename) + tar.extractall(path=tempfile.mkdtemp(), members=members_filter(tar)) + tar.close() + + +def list_members_archive_handler(filename): + tar = tarfile.open(filename) + tar.extractall(path=tempfile.mkdtemp(), members=[]) + tar.close() + + +def provided_members_archive_handler(filename): + tar = tarfile.open(filename) + tarfile.extractall(path=tempfile.mkdtemp(), members=tar) + tar.close() + + +def filter_data(filename): + tar = tarfile.open(filename) + tarfile.extractall(path=tempfile.mkdtemp(), filter="data") + tar.close() + + +def filter_fully_trusted(filename): + tar = tarfile.open(filename) + tarfile.extractall(path=tempfile.mkdtemp(), filter="fully_trusted") + tar.close() + + +def filter_tar(filename): + tar = tarfile.open(filename) + tarfile.extractall(path=tempfile.mkdtemp(), filter="tar") + tar.close() + + +def members_filter(tarfile): + result = [] + for member in tarfile.getmembers(): + if '../' in member.name: + print('Member name container directory traversal sequence') + continue + elif (member.issym() or member.islnk()) and ('../' in member.linkname): + print('Symlink to external resource') + continue + result.append(member) + return result + + +if __name__ == "__main__": + if len(sys.argv) > 1: + filename = sys.argv[1] + unsafe_archive_handler(filename) + managed_members_archive_handler(filename) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 313218cca2ded..f418fbf1212d5 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -615,6 +615,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::DjangoRawSql) { flake8_bandit::rules::django_raw_sql(checker, call); } + if checker.enabled(Rule::TarfileUnsafeMembers) { + flake8_bandit::rules::tarfile_unsafe_members(checker, call); + } if checker.enabled(Rule::UnnecessaryGeneratorList) { flake8_comprehensions::rules::unnecessary_generator_list( checker, expr, func, args, keywords, diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index 759ccc54ac49e..1e04278e0f15b 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -595,6 +595,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Flake8Bandit, "112") => (RuleGroup::Stable, rules::flake8_bandit::rules::TryExceptContinue), (Flake8Bandit, "113") => (RuleGroup::Stable, rules::flake8_bandit::rules::RequestWithoutTimeout), (Flake8Bandit, "201") => (RuleGroup::Preview, rules::flake8_bandit::rules::FlaskDebugTrue), + (Flake8Bandit, "202") => (RuleGroup::Preview, rules::flake8_bandit::rules::TarfileUnsafeMembers), (Flake8Bandit, "301") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousPickleUsage), (Flake8Bandit, "302") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousMarshalUsage), (Flake8Bandit, "303") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousInsecureHashUsage), diff --git a/crates/ruff_linter/src/rules/flake8_bandit/mod.rs b/crates/ruff_linter/src/rules/flake8_bandit/mod.rs index feb2dcb507651..ce041669f1782 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/mod.rs @@ -51,6 +51,7 @@ mod tests { #[test_case(Rule::UnsafeYAMLLoad, Path::new("S506.py"))] #[test_case(Rule::WeakCryptographicKey, Path::new("S505.py"))] #[test_case(Rule::DjangoRawSql, Path::new("S611.py"))] + #[test_case(Rule::TarfileUnsafeMembers, Path::new("S202.py"))] fn rules(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs index b7a655366876f..ee1de347d6152 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs @@ -21,6 +21,7 @@ pub(crate) use snmp_insecure_version::*; pub(crate) use snmp_weak_cryptography::*; pub(crate) use ssh_no_host_key_verification::*; pub(crate) use suspicious_function_call::*; +pub(crate) use tarfile_unsafe_members::*; pub(crate) use try_except_continue::*; pub(crate) use try_except_pass::*; pub(crate) use unsafe_yaml_load::*; @@ -49,6 +50,7 @@ mod snmp_insecure_version; mod snmp_weak_cryptography; mod ssh_no_host_key_verification; mod suspicious_function_call; +mod tarfile_unsafe_members; mod try_except_continue; mod try_except_pass; mod unsafe_yaml_load; diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/tarfile_unsafe_members.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/tarfile_unsafe_members.rs new file mode 100644 index 0000000000000..1fd35e3c7ad35 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/tarfile_unsafe_members.rs @@ -0,0 +1,75 @@ +use crate::checkers::ast::Checker; +use ruff_diagnostics::Diagnostic; +use ruff_diagnostics::Violation; +use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::{self as ast}; +use ruff_text_size::Ranged; + +/// ## What it does +/// Checks for uses of `tarfile.extractall`. +/// +/// ## Why is this bad? +/// +/// Extracting archives from untrusted sources without prior inspection is +/// a security risk, as maliciously crafted archives may contain files that +/// will be written outside of the target directory. For example, the archive +/// could include files with absolute paths (e.g., `/etc/passwd`), or relative +/// paths with parent directory references (e.g., `../etc/passwd`). +/// +/// On Python 3.12 and later, use `filter='data'` to prevent the most dangerous +/// security issues (see: [PEP 706]). On earlier versions, set the `members` +/// argument to a trusted subset of the archive's members. +/// +/// ## Example +/// ```python +/// import tarfile +/// import tempfile +/// +/// tar = tarfile.open(filename) +/// tar.extractall(path=tempfile.mkdtemp()) +/// tar.close() +/// ``` +/// +/// ## References +/// - [Common Weakness Enumeration: CWE-22](https://cwe.mitre.org/data/definitions/22.html) +/// - [Python Documentation: `TarFile.extractall`](https://docs.python.org/3/library/tarfile.html#tarfile.TarFile.extractall) +/// - [Python Documentation: Extraction filters](https://docs.python.org/3/library/tarfile.html#tarfile-extraction-filter) +/// +/// [PEP 706]: https://peps.python.org/pep-0706/#backporting-forward-compatibility +#[violation] +pub struct TarfileUnsafeMembers; + +impl Violation for TarfileUnsafeMembers { + #[derive_message_formats] + fn message(&self) -> String { + format!("Uses of `tarfile.extractall()`") + } +} + +/// S202 +pub(crate) fn tarfile_unsafe_members(checker: &mut Checker, call: &ast::ExprCall) { + if !call + .func + .as_attribute_expr() + .is_some_and(|attr| attr.attr.as_str() == "extractall") + { + return; + } + + if call + .arguments + .find_keyword("filter") + .and_then(|keyword| keyword.value.as_string_literal_expr()) + .is_some_and(|value| matches!(value.value.as_str(), "data" | "tar")) + { + return; + } + + if !checker.semantic().seen(&["tarfile"]) { + return; + } + + checker + .diagnostics + .push(Diagnostic::new(TarfileUnsafeMembers, call.func.range())); +} diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S202_S202.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S202_S202.py.snap new file mode 100644 index 0000000000000..fb951d05d1d44 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S202_S202.py.snap @@ -0,0 +1,49 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S202.py:8:5: S202 Uses of `tarfile.extractall()` + | +6 | def unsafe_archive_handler(filename): +7 | tar = tarfile.open(filename) +8 | tar.extractall(path=tempfile.mkdtemp()) + | ^^^^^^^^^^^^^^ S202 +9 | tar.close() + | + +S202.py:14:5: S202 Uses of `tarfile.extractall()` + | +12 | def managed_members_archive_handler(filename): +13 | tar = tarfile.open(filename) +14 | tar.extractall(path=tempfile.mkdtemp(), members=members_filter(tar)) + | ^^^^^^^^^^^^^^ S202 +15 | tar.close() + | + +S202.py:20:5: S202 Uses of `tarfile.extractall()` + | +18 | def list_members_archive_handler(filename): +19 | tar = tarfile.open(filename) +20 | tar.extractall(path=tempfile.mkdtemp(), members=[]) + | ^^^^^^^^^^^^^^ S202 +21 | tar.close() + | + +S202.py:26:5: S202 Uses of `tarfile.extractall()` + | +24 | def provided_members_archive_handler(filename): +25 | tar = tarfile.open(filename) +26 | tarfile.extractall(path=tempfile.mkdtemp(), members=tar) + | ^^^^^^^^^^^^^^^^^^ S202 +27 | tar.close() + | + +S202.py:38:5: S202 Uses of `tarfile.extractall()` + | +36 | def filter_fully_trusted(filename): +37 | tar = tarfile.open(filename) +38 | tarfile.extractall(path=tempfile.mkdtemp(), filter="fully_trusted") + | ^^^^^^^^^^^^^^^^^^ S202 +39 | tar.close() + | + + diff --git a/ruff.schema.json b/ruff.schema.json index c4acb767cd585..8ae7c3fe37fb2 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -3368,6 +3368,7 @@ "S2", "S20", "S201", + "S202", "S3", "S30", "S301", From 017e82911595bab746172b7976f993b715be4d79 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Fri, 24 Nov 2023 17:55:41 -0600 Subject: [PATCH 030/197] Update string nodes for implicit concatenation (#7927) ## Summary This PR updates the string nodes (`ExprStringLiteral`, `ExprBytesLiteral`, and `ExprFString`) to account for implicit string concatenation. ### Motivation In Python, implicit string concatenation are joined while parsing because the interpreter doesn't require the information for each part. While that's feasible for an interpreter, it falls short for a static analysis tool where having such information is more useful. Currently, various parts of the code uses the lexer to get the individual string parts. One of the main challenge this solves is that of string formatting. Currently, the formatter relies on the lexer to get the individual string parts, and formats them including the comments accordingly. But, with PEP 701, f-string can also contain comments. Without this change, it becomes very difficult to add support for f-string formatting. ### Implementation The initial proposal was made in this discussion: https://github.com/astral-sh/ruff/discussions/6183#discussioncomment-6591993. There were various AST designs which were explored for this task which are available in the linked internal document[^1]. The selected variant was the one where the nodes were kept as it is except that the `implicit_concatenated` field was removed and instead a new struct was added to the `Expr*` struct. This would be a private struct would contain the actual implementation of how the AST is designed for both single and implicitly concatenated strings. This implementation is achieved through an enum with two variants: `Single` and `Concatenated` to avoid allocating a vector even for single strings. There are various public methods available on the value struct to query certain information regarding the node. The nodes are structured in the following way: ``` ExprStringLiteral - "foo" "bar" |- StringLiteral - "foo" |- StringLiteral - "bar" ExprBytesLiteral - b"foo" b"bar" |- BytesLiteral - b"foo" |- BytesLiteral - b"bar" ExprFString - "foo" f"bar {x}" |- FStringPart::Literal - "foo" |- FStringPart::FString - f"bar {x}" |- StringLiteral - "bar " |- FormattedValue - "x" ``` [^1]: Internal document: https://www.notion.so/astral-sh/Implicit-String-Concatenation-e036345dc48943f89e416c087bf6f6d9?pvs=4 #### Visitor The way the nodes are structured is that the entire string, including all the parts that are implicitly concatenation, is a single node containing individual nodes for the parts. The previous section has a representation of that tree for all the string nodes. This means that new visitor methods are added to visit the individual parts of string, bytes, and f-strings for `Visitor`, `PreorderVisitor`, and `Transformer`. ## Test Plan - `cargo insta test --workspace --all-features --unreferenced reject` - Verify that the ecosystem results are unchanged --- .../src/checkers/ast/analyze/definitions.rs | 16 +- .../src/checkers/ast/analyze/expression.rs | 20 +- crates/ruff_linter/src/checkers/ast/mod.rs | 6 +- crates/ruff_linter/src/checkers/tokens.rs | 4 - crates/ruff_linter/src/cst/matchers.rs | 29 +- crates/ruff_linter/src/registry.rs | 1 - .../rules/airflow/rules/task_variable_name.rs | 2 +- .../flake8_annotations/rules/definition.rs | 1 - .../src/rules/flake8_bandit/helpers.rs | 2 +- .../rules/hardcoded_bind_all_interfaces.rs | 2 +- .../rules/hardcoded_sql_expression.rs | 89 +- .../rules/hardcoded_tmp_directory.rs | 2 +- .../rules/suspicious_function_call.rs | 10 +- .../rules/unnecessary_dict_kwargs.rs | 2 +- .../flake8_pyi/rules/unrecognized_platform.rs | 2 +- .../flake8_pytest_style/rules/helpers.rs | 9 +- .../flake8_pytest_style/rules/parametrize.rs | 14 +- .../rules/flake8_simplify/rules/ast_expr.rs | 21 +- .../path_constructor_current_directory.rs | 2 +- crates/ruff_linter/src/rules/flynt/helpers.rs | 6 +- .../flynt/rules/static_join_to_fstring.rs | 9 +- .../rules/f_string_missing_placeholders.rs | 105 +- .../src/rules/pyflakes/rules/strings.rs | 4 +- .../ruff_linter/src/rules/pylint/helpers.rs | 4 +- .../pylint/rules/assert_on_string_literal.rs | 47 +- .../pylint/rules/bad_string_format_type.rs | 4 +- .../rules/pyupgrade/rules/native_literals.rs | 38 +- .../pyupgrade/rules/unicode_kind_prefix.rs | 29 +- .../src/rules/refurb/rules/read_whole_file.rs | 10 +- .../explicit_f_string_type_conversion.rs | 103 +- .../src/rules/ruff/rules/implicit_optional.rs | 1 - crates/ruff_linter/src/rules/ruff/typing.rs | 1 - .../tryceratops/rules/raise_vanilla_args.rs | 19 +- crates/ruff_python_ast/src/comparable.rs | 159 +- crates/ruff_python_ast/src/expression.rs | 41 + crates/ruff_python_ast/src/helpers.rs | 17 +- crates/ruff_python_ast/src/node.rs | 232 +- crates/ruff_python_ast/src/nodes.rs | 528 +- crates/ruff_python_ast/src/visitor.rs | 62 +- .../ruff_python_ast/src/visitor/preorder.rs | 58 +- .../src/visitor/transformer.rs | 60 +- crates/ruff_python_codegen/src/generator.rs | 62 +- .../src/comments/placement.rs | 4 +- .../src/expression/expr_bin_op.rs | 8 +- .../src/expression/expr_bytes_literal.rs | 2 +- .../src/expression/expr_compare.rs | 8 +- .../src/expression/expr_f_string.rs | 2 +- .../src/expression/expr_string_literal.rs | 2 +- .../src/expression/mod.rs | 23 +- .../src/expression/string.rs | 255 +- .../src/statement/suite.rs | 12 +- .../ruff_python_formatter/tests/normalizer.rs | 26 +- crates/ruff_python_parser/src/python.lalrpop | 56 +- crates/ruff_python_parser/src/python.rs | 19203 ++++++++-------- ...r__invalid__tests__ok_attribute_weird.snap | 12 +- ...parser__parser__tests__dict_unpacking.snap | 48 +- ...ython_parser__parser__tests__fstrings.snap | 1394 +- ..._parser__tests__fstrings_with_unicode.snap | 352 +- ..._tests__generator_expression_argument.snap | 36 +- ...f_python_parser__parser__tests__match.snap | 48 +- ...on_parser__parser__tests__parse_class.snap | 12 +- ...parser__parser__tests__parse_f_string.snap | 34 +- ...n_parser__parser__tests__parse_kwargs.snap | 12 +- ..._parser__parser__tests__parse_print_2.snap | 12 +- ...ser__parser__tests__parse_print_hello.snap | 12 +- ...n_parser__parser__tests__parse_string.snap | 12 +- ...parser__tests__parse_type_declaration.snap | 12 +- ...f_python_parser__parser__tests__patma.snap | 84 +- ...uff_python_parser__parser__tests__try.snap | 184 +- ...ython_parser__parser__tests__try_star.snap | 328 +- ...arser__parser__tests__unicode_aliases.snap | 12 +- ...arser__string__tests__backspace_alias.snap | 12 +- ...hon_parser__string__tests__bell_alias.snap | 12 +- ..._string__tests__carriage_return_alias.snap | 12 +- ...r_tabulation_with_justification_alias.snap | 12 +- ...n_parser__string__tests__delete_alias.snap | 12 +- ...ests__dont_panic_on_8_in_octal_escape.snap | 12 +- ...er__string__tests__double_quoted_byte.snap | 524 +- ...n_parser__string__tests__escape_alias.snap | 12 +- ...g__tests__escape_char_in_byte_literal.snap | 32 +- ...n_parser__string__tests__escape_octet.snap | 22 +- ...arser__string__tests__form_feed_alias.snap | 12 +- ...string__tests__fstring_constant_range.snap | 138 +- ...ing__tests__fstring_escaped_character.snap | 64 +- ...tring__tests__fstring_escaped_newline.snap | 64 +- ...ing__tests__fstring_line_continuation.snap | 64 +- ...__fstring_parse_self_documenting_base.snap | 52 +- ...ring_parse_self_documenting_base_more.snap | 136 +- ...fstring_parse_self_documenting_format.snap | 96 +- ...ing__tests__fstring_unescaped_newline.snap | 64 +- ...thon_parser__string__tests__hts_alias.snap | 12 +- ...r__string__tests__parse_empty_fstring.snap | 12 +- ...tring__tests__parse_f_string_concat_1.snap | 43 +- ...tring__tests__parse_f_string_concat_2.snap | 43 +- ...tring__tests__parse_f_string_concat_3.snap | 75 +- ...tring__tests__parse_f_string_concat_4.snap | 90 +- ..._parser__string__tests__parse_fstring.snap | 94 +- ...__string__tests__parse_fstring_equals.snap | 74 +- ...ring_nested_concatenation_string_spec.snap | 112 +- ...ing__tests__parse_fstring_nested_spec.snap | 94 +- ...sts__parse_fstring_nested_string_spec.snap | 102 +- ...ring__tests__parse_fstring_not_equals.snap | 74 +- ..._tests__parse_fstring_not_nested_spec.snap | 86 +- ...ts__parse_fstring_self_doc_prec_space.snap | 52 +- ...parse_fstring_self_doc_trailing_space.snap | 52 +- ...ring__tests__parse_fstring_yield_expr.snap | 40 +- ...r__string__tests__parse_string_concat.snap | 22 +- ..._parse_string_triple_quotes_with_kind.snap | 12 +- ...ing__tests__parse_u_f_string_concat_1.snap | 43 +- ...ing__tests__parse_u_f_string_concat_2.snap | 50 +- ...tring__tests__parse_u_string_concat_1.snap | 22 +- ...tring__tests__parse_u_string_concat_2.snap | 22 +- ...er__string__tests__raw_byte_literal_1.snap | 20 +- ...er__string__tests__raw_byte_literal_2.snap | 16 +- ...on_parser__string__tests__raw_fstring.snap | 42 +- ...er__string__tests__single_quoted_byte.snap | 524 +- ..._tests__string_parser_escaped_mac_eol.snap | 12 +- ...tests__string_parser_escaped_unix_eol.snap | 12 +- ...ts__string_parser_escaped_windows_eol.snap | 12 +- ...ing__tests__triple_quoted_raw_fstring.snap | 42 +- crates/ruff_python_parser/src/string.rs | 157 +- 121 files changed, 14809 insertions(+), 12644 deletions(-) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/definitions.rs b/crates/ruff_linter/src/checkers/ast/analyze/definitions.rs index f4c40279096b2..6cafa66f49e32 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/definitions.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/definitions.rs @@ -158,21 +158,23 @@ pub(crate) fn definitions(checker: &mut Checker) { } // Extract a `Docstring` from a `Definition`. - let Some(expr) = docstring else { + let Some(string_literal) = docstring else { pydocstyle::rules::not_missing(checker, definition, *visibility); continue; }; - let contents = checker.locator().slice(expr); + let contents = checker.locator().slice(string_literal); let indentation = checker.locator().slice(TextRange::new( - checker.locator.line_start(expr.start()), - expr.start(), + checker.locator.line_start(string_literal.start()), + string_literal.start(), )); - if expr.implicit_concatenated { + if string_literal.value.is_implicit_concatenated() { #[allow(deprecated)] - let location = checker.locator.compute_source_location(expr.start()); + let location = checker + .locator + .compute_source_location(string_literal.start()); warn_user!( "Docstring at {}:{}:{} contains implicit string concatenation; ignoring...", relativize_path(checker.path), @@ -186,7 +188,7 @@ pub(crate) fn definitions(checker: &mut Checker) { let body_range = raw_contents_range(contents).unwrap(); let docstring = Docstring { definition, - expr, + expr: string_literal, contents, body_range, indentation, diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index f418fbf1212d5..76b735944978c 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -988,15 +988,22 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { pylint::rules::await_outside_async(checker, expr); } } - Expr::FString(fstring @ ast::ExprFString { values, .. }) => { + Expr::FString(f_string_expr @ ast::ExprFString { value, .. }) => { if checker.enabled(Rule::FStringMissingPlaceholders) { - pyflakes::rules::f_string_missing_placeholders(fstring, checker); + pyflakes::rules::f_string_missing_placeholders(checker, f_string_expr); + } + if checker.enabled(Rule::ExplicitFStringTypeConversion) { + for f_string in value.f_strings() { + ruff::rules::explicit_f_string_type_conversion(checker, f_string); + } } if checker.enabled(Rule::HardcodedSQLExpression) { flake8_bandit::rules::hardcoded_sql_expression(checker, expr); } - if checker.enabled(Rule::ExplicitFStringTypeConversion) { - ruff::rules::explicit_f_string_type_conversion(checker, expr, values); + if checker.enabled(Rule::UnicodeKindPrefix) { + for string_literal in value.literals() { + pyupgrade::rules::unicode_kind_prefix(checker, string_literal); + } } } Expr::BinOp(ast::ExprBinOp { @@ -1278,6 +1285,11 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::HardcodedTempFile) { flake8_bandit::rules::hardcoded_tmp_directory(checker, string); } + if checker.enabled(Rule::UnicodeKindPrefix) { + for string_part in string.value.parts() { + pyupgrade::rules::unicode_kind_prefix(checker, string_part); + } + } if checker.source_type.is_stub() { if checker.enabled(Rule::StringOrBytesTooLong) { flake8_pyi::rules::string_or_bytes_too_long(checker, expr); diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 231687f66c23b..7357937c1a88f 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -1303,9 +1303,9 @@ where fn visit_format_spec(&mut self, format_spec: &'b Expr) { match format_spec { - Expr::FString(ast::ExprFString { values, .. }) => { - for value in values { - self.visit_expr(value); + Expr::FString(ast::ExprFString { value, .. }) => { + for expr in value.elements() { + self.visit_expr(expr); } } _ => unreachable!("Unexpected expression for format_spec"), diff --git a/crates/ruff_linter/src/checkers/tokens.rs b/crates/ruff_linter/src/checkers/tokens.rs index e9d23ed91c626..ae7643d92f7e1 100644 --- a/crates/ruff_linter/src/checkers/tokens.rs +++ b/crates/ruff_linter/src/checkers/tokens.rs @@ -94,10 +94,6 @@ pub(crate) fn check_tokens( pycodestyle::rules::tab_indentation(&mut diagnostics, tokens, locator, indexer); } - if settings.rules.enabled(Rule::UnicodeKindPrefix) { - pyupgrade::rules::unicode_kind_prefix(&mut diagnostics, tokens); - } - if settings.rules.any_enabled(&[ Rule::InvalidCharacterBackspace, Rule::InvalidCharacterSub, diff --git a/crates/ruff_linter/src/cst/matchers.rs b/crates/ruff_linter/src/cst/matchers.rs index fac3be1e41010..3bce354cb60b8 100644 --- a/crates/ruff_linter/src/cst/matchers.rs +++ b/crates/ruff_linter/src/cst/matchers.rs @@ -1,9 +1,10 @@ use crate::fix::codemods::CodegenStylist; use anyhow::{bail, Result}; use libcst_native::{ - Arg, Attribute, Call, Comparison, CompoundStatement, Dict, Expression, FunctionDef, - GeneratorExp, If, Import, ImportAlias, ImportFrom, ImportNames, IndentedBlock, Lambda, - ListComp, Module, Name, SmallStatement, Statement, Suite, Tuple, With, + Arg, Attribute, Call, Comparison, CompoundStatement, Dict, Expression, FormattedString, + FormattedStringContent, FormattedStringExpression, FunctionDef, GeneratorExp, If, Import, + ImportAlias, ImportFrom, ImportNames, IndentedBlock, Lambda, ListComp, Module, Name, + SmallStatement, Statement, Suite, Tuple, With, }; use ruff_python_codegen::Stylist; @@ -153,6 +154,28 @@ pub(crate) fn match_lambda<'a, 'b>(expression: &'a Expression<'b>) -> Result<&'a } } +pub(crate) fn match_formatted_string<'a, 'b>( + expression: &'a mut Expression<'b>, +) -> Result<&'a mut FormattedString<'b>> { + if let Expression::FormattedString(formatted_string) = expression { + Ok(formatted_string) + } else { + bail!("Expected Expression::FormattedString"); + } +} + +pub(crate) fn match_formatted_string_expression<'a, 'b>( + formatted_string_content: &'a mut FormattedStringContent<'b>, +) -> Result<&'a mut FormattedStringExpression<'b>> { + if let FormattedStringContent::Expression(formatted_string_expression) = + formatted_string_content + { + Ok(formatted_string_expression) + } else { + bail!("Expected FormattedStringContent::Expression") + } +} + pub(crate) fn match_function_def<'a, 'b>( statement: &'a mut Statement<'b>, ) -> Result<&'a mut FunctionDef<'b>> { diff --git a/crates/ruff_linter/src/registry.rs b/crates/ruff_linter/src/registry.rs index 1468db59aed3e..2e6fcc199580e 100644 --- a/crates/ruff_linter/src/registry.rs +++ b/crates/ruff_linter/src/registry.rs @@ -297,7 +297,6 @@ impl Rule { | Rule::TabIndentation | Rule::TrailingCommaOnBareTuple | Rule::TypeCommentInStub - | Rule::UnicodeKindPrefix | Rule::UselessSemicolon | Rule::UTF8EncodingDeclaration => LintSource::Tokens, Rule::IOError => LintSource::Io, diff --git a/crates/ruff_linter/src/rules/airflow/rules/task_variable_name.rs b/crates/ruff_linter/src/rules/airflow/rules/task_variable_name.rs index dec0a953081fb..76ebb405a225d 100644 --- a/crates/ruff_linter/src/rules/airflow/rules/task_variable_name.rs +++ b/crates/ruff_linter/src/rules/airflow/rules/task_variable_name.rs @@ -81,7 +81,7 @@ pub(crate) fn variable_name_task_id( let ast::ExprStringLiteral { value: task_id, .. } = keyword.value.as_string_literal_expr()?; // If the target name is the same as the task_id, no violation. - if id == task_id { + if task_id == id { return None; } diff --git a/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs b/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs index 3fe862c01991d..c73f8da87cd2e 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs +++ b/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs @@ -508,7 +508,6 @@ fn check_dynamically_typed( if let Expr::StringLiteral(ast::ExprStringLiteral { range, value: string, - .. }) = annotation { // Quoted annotations diff --git a/crates/ruff_linter/src/rules/flake8_bandit/helpers.rs b/crates/ruff_linter/src/rules/flake8_bandit/helpers.rs index ad31e99137728..ac1bfefe1a2fd 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/helpers.rs @@ -10,7 +10,7 @@ static PASSWORD_CANDIDATE_REGEX: Lazy = Lazy::new(|| { pub(super) fn string_literal(expr: &Expr) -> Option<&str> { match expr { - Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => Some(value), + Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => Some(value.as_str()), _ => None, } } diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs index 4fadf908a3f01..af96341a093cf 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs @@ -35,7 +35,7 @@ impl Violation for HardcodedBindAllInterfaces { /// S104 pub(crate) fn hardcoded_bind_all_interfaces(string: &ExprStringLiteral) -> Option { - if string.value == "0.0.0.0" { + if string.value.as_str() == "0.0.0.0" { Some(Diagnostic::new(HardcodedBindAllInterfaces, string.range)) } else { None diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs index d54e0a0b23afa..d4d3df9bad712 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs @@ -5,13 +5,12 @@ use ruff_python_ast::{self as ast, Expr, Operator}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::any_over_expr; -use ruff_python_semantic::SemanticModel; +use ruff_python_ast::str::raw_contents; +use ruff_source_file::Locator; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; -use super::super::helpers::string_literal; - static SQL_REGEX: Lazy = Lazy::new(|| { Regex::new(r"(?i)\b(select\s.+\sfrom\s|delete\s+from\s|(insert|replace)\s.+\svalues\s|update\s.+\sset\s)") .unwrap() @@ -46,53 +45,77 @@ impl Violation for HardcodedSQLExpression { } } -fn has_string_literal(expr: &Expr) -> bool { - string_literal(expr).is_some() -} - -fn matches_sql_statement(string: &str) -> bool { - SQL_REGEX.is_match(string) +/// Concatenates the contents of an f-string, without the prefix and quotes, +/// and escapes any special characters. +/// +/// ## Example +/// +/// ```python +/// "foo" f"bar {x}" "baz" +/// ``` +/// +/// becomes `foobar {x}baz`. +fn concatenated_f_string(expr: &ast::ExprFString, locator: &Locator) -> String { + expr.value + .parts() + .filter_map(|part| { + raw_contents(locator.slice(part)).map(|s| s.escape_default().to_string()) + }) + .collect() } -fn matches_string_format_expression(expr: &Expr, semantic: &SemanticModel) -> bool { - match expr { +/// S608 +pub(crate) fn hardcoded_sql_expression(checker: &mut Checker, expr: &Expr) { + let content = match expr { // "select * from table where val = " + "str" + ... - // "select * from table where val = %s" % ... Expr::BinOp(ast::ExprBinOp { - op: Operator::Add | Operator::Mod, - .. + op: Operator::Add, .. }) => { // Only evaluate the full BinOp, not the nested components. - if semantic + if !checker + .semantic() .current_expression_parent() .map_or(true, |parent| !parent.is_bin_op_expr()) { - if any_over_expr(expr, &has_string_literal) { - return true; - } + return; + } + if !any_over_expr(expr, &Expr::is_string_literal_expr) { + return; } - false + checker.generator().expr(expr) + } + // "select * from table where val = %s" % ... + Expr::BinOp(ast::ExprBinOp { + left, + op: Operator::Mod, + .. + }) => { + let Some(string) = left.as_string_literal_expr() else { + return; + }; + string.value.escape_default().to_string() } Expr::Call(ast::ExprCall { func, .. }) => { let Expr::Attribute(ast::ExprAttribute { attr, value, .. }) = func.as_ref() else { - return false; + return; }; // "select * from table where val = {}".format(...) - attr == "format" && string_literal(value).is_some() + if attr != "format" { + return; + } + let Some(string) = value.as_string_literal_expr() else { + return; + }; + string.value.escape_default().to_string() } // f"select * from table where val = {val}" - Expr::FString(_) => true, - _ => false, - } -} + Expr::FString(f_string) => concatenated_f_string(f_string, checker.locator()), + _ => return, + }; -/// S608 -pub(crate) fn hardcoded_sql_expression(checker: &mut Checker, expr: &Expr) { - if matches_string_format_expression(expr, checker.semantic()) { - if matches_sql_statement(&checker.generator().expr(expr)) { - checker - .diagnostics - .push(Diagnostic::new(HardcodedSQLExpression, expr.range())); - } + if SQL_REGEX.is_match(&content) { + checker + .diagnostics + .push(Diagnostic::new(HardcodedSQLExpression, expr.range())); } } diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs index 1f5613647f54b..592f4e76211b2 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs @@ -76,7 +76,7 @@ pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, string: &ast::ExprS checker.diagnostics.push(Diagnostic::new( HardcodedTempFile { - string: string.value.clone(), + string: string.value.to_string(), }, string.range, )); diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs index e705676121cdd..0c6d9b9300664 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs @@ -854,11 +854,11 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, call: &ExprCall) { ["six", "moves", "urllib", "request", "urlopen" | "urlretrieve" | "Request"] => { // If the `url` argument is a string literal, allow `http` and `https` schemes. if call.arguments.args.iter().all(|arg| !arg.is_starred_expr()) && call.arguments.keywords.iter().all(|keyword| keyword.arg.is_some()) { - if let Some(Expr::StringLiteral(ast::ExprStringLiteral { value: url, .. })) = &call.arguments.find_argument("url", 0) { - let url = url.trim_start(); - if url.starts_with("http://") || url.starts_with("https://") { - return None; - } + if let Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) = &call.arguments.find_argument("url", 0) { + let url = value.trim_start(); + if url.starts_with("http://") || url.starts_with("https://") { + return None; + } } } Some(SuspiciousURLOpenUsage.into()) diff --git a/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs b/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs index 8a518c88906f4..a37da79ade651 100644 --- a/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs +++ b/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs @@ -111,7 +111,7 @@ pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, expr: &Expr, kwargs fn as_kwarg(key: &Expr) -> Option<&str> { if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = key { if is_identifier(value) { - return Some(value); + return Some(value.as_str()); } } None diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/unrecognized_platform.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/unrecognized_platform.rs index dc84fdffa10f8..c46ffa19e27b0 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/unrecognized_platform.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/unrecognized_platform.rs @@ -130,7 +130,7 @@ pub(crate) fn unrecognized_platform(checker: &mut Checker, test: &Expr) { if !matches!(value.as_str(), "linux" | "win32" | "cygwin" | "darwin") { checker.diagnostics.push(Diagnostic::new( UnrecognizedPlatformName { - platform: value.clone(), + platform: value.to_string(), }, right.range(), )); diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs index e618fa3b5f018..34303d204c415 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs @@ -55,8 +55,13 @@ pub(super) fn is_empty_or_null_string(expr: &Expr) -> bool { match expr { Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => value.is_empty(), Expr::NoneLiteral(_) => true, - Expr::FString(ast::ExprFString { values, .. }) => { - values.iter().all(is_empty_or_null_string) + Expr::FString(ast::ExprFString { value, .. }) => { + value.parts().all(|f_string_part| match f_string_part { + ast::FStringPart::Literal(literal) => literal.is_empty(), + ast::FStringPart::FString(f_string) => { + f_string.values.iter().all(is_empty_or_null_string) + } + }) } _ => false, } diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs index 5d494ed82e04c..e9b5b7a8954fc 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs @@ -252,7 +252,7 @@ fn elts_to_csv(elts: &[Expr], generator: Generator) -> Option { return None; } - let node = Expr::StringLiteral(ast::ExprStringLiteral { + let node = Expr::from(ast::StringLiteral { value: elts.iter().fold(String::new(), |mut acc, elt| { if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = elt { if !acc.is_empty() { @@ -262,9 +262,7 @@ fn elts_to_csv(elts: &[Expr], generator: Generator) -> Option { } acc }), - unicode: false, - implicit_concatenated: false, - range: TextRange::default(), + ..ast::StringLiteral::default() }); Some(generator.expr(&node)) } @@ -324,9 +322,9 @@ fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) { elts: names .iter() .map(|name| { - Expr::StringLiteral(ast::ExprStringLiteral { + Expr::from(ast::StringLiteral { value: (*name).to_string(), - ..ast::ExprStringLiteral::default() + ..ast::StringLiteral::default() }) }) .collect(), @@ -357,9 +355,9 @@ fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) { elts: names .iter() .map(|name| { - Expr::StringLiteral(ast::ExprStringLiteral { + Expr::from(ast::StringLiteral { value: (*name).to_string(), - ..ast::ExprStringLiteral::default() + ..ast::StringLiteral::default() }) }) .collect(), diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_expr.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_expr.rs index 4a3b5a7d524ab..deee6d9b2488d 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_expr.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_expr.rs @@ -166,14 +166,14 @@ pub(crate) fn use_capital_environment_variables(checker: &mut Checker, expr: &Ex } let capital_env_var = env_var.to_ascii_uppercase(); - if &capital_env_var == env_var { + if capital_env_var == env_var.as_str() { return; } checker.diagnostics.push(Diagnostic::new( UncapitalizedEnvironmentVariables { expected: SourceCodeSnippet::new(capital_env_var), - actual: SourceCodeSnippet::new(env_var.clone()), + actual: SourceCodeSnippet::new(env_var.to_string()), }, arg.range(), )); @@ -197,12 +197,7 @@ fn check_os_environ_subscript(checker: &mut Checker, expr: &Expr) { if id != "os" || attr != "environ" { return; } - let Expr::StringLiteral(ast::ExprStringLiteral { - value: env_var, - unicode, - .. - }) = slice.as_ref() - else { + let Expr::StringLiteral(ast::ExprStringLiteral { value: env_var, .. }) = slice.as_ref() else { return; }; @@ -211,21 +206,21 @@ fn check_os_environ_subscript(checker: &mut Checker, expr: &Expr) { } let capital_env_var = env_var.to_ascii_uppercase(); - if &capital_env_var == env_var { + if capital_env_var == env_var.as_str() { return; } let mut diagnostic = Diagnostic::new( UncapitalizedEnvironmentVariables { expected: SourceCodeSnippet::new(capital_env_var.clone()), - actual: SourceCodeSnippet::new(env_var.clone()), + actual: SourceCodeSnippet::new(env_var.to_string()), }, slice.range(), ); - let node = ast::ExprStringLiteral { + let node = ast::StringLiteral { value: capital_env_var, - unicode: *unicode, - ..ast::ExprStringLiteral::default() + unicode: env_var.is_unicode(), + ..ast::StringLiteral::default() }; let new_env_var = node.into(); diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( diff --git a/crates/ruff_linter/src/rules/flake8_use_pathlib/rules/path_constructor_current_directory.rs b/crates/ruff_linter/src/rules/flake8_use_pathlib/rules/path_constructor_current_directory.rs index 0fc1cbee681de..c4a31a47c1909 100644 --- a/crates/ruff_linter/src/rules/flake8_use_pathlib/rules/path_constructor_current_directory.rs +++ b/crates/ruff_linter/src/rules/flake8_use_pathlib/rules/path_constructor_current_directory.rs @@ -65,7 +65,7 @@ pub(crate) fn path_constructor_current_directory(checker: &mut Checker, expr: &E return; } - let [Expr::StringLiteral(ast::ExprStringLiteral { value, range, .. })] = args.as_slice() else { + let [Expr::StringLiteral(ast::ExprStringLiteral { value, range })] = args.as_slice() else { return; }; diff --git a/crates/ruff_linter/src/rules/flynt/helpers.rs b/crates/ruff_linter/src/rules/flynt/helpers.rs index 1caa107c40919..83c6b131461be 100644 --- a/crates/ruff_linter/src/rules/flynt/helpers.rs +++ b/crates/ruff_linter/src/rules/flynt/helpers.rs @@ -15,9 +15,9 @@ fn to_formatted_value_expr(inner: &Expr) -> Expr { /// Convert a string to a constant string expression. pub(super) fn to_constant_string(s: &str) -> Expr { - let node = ast::ExprStringLiteral { - value: s.to_owned(), - ..ast::ExprStringLiteral::default() + let node = ast::StringLiteral { + value: s.to_string(), + ..ast::StringLiteral::default() }; node.into() } diff --git a/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs b/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs index 8da7a91eb2c49..1704ca020c618 100644 --- a/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs +++ b/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs @@ -62,7 +62,7 @@ fn is_static_length(elts: &[Expr]) -> bool { fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option { // If all elements are string constants, join them into a single string. if joinees.iter().all(Expr::is_string_literal_expr) { - let node = ast::ExprStringLiteral { + let node = ast::StringLiteral { value: joinees .iter() .filter_map(|expr| { @@ -73,9 +73,7 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option { } }) .join(joiner), - unicode: false, - implicit_concatenated: false, - range: TextRange::default(), + ..ast::StringLiteral::default() }; return Some(node.into()); } @@ -95,9 +93,8 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option { fstring_elems.push(helpers::to_f_string_element(expr)?); } - let node = ast::ExprFString { + let node = ast::FString { values: fstring_elems, - implicit_concatenated: false, range: TextRange::default(), }; Some(node.into()) diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs b/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs index 448959149e826..f2adeb69d76ab 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs @@ -1,7 +1,6 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{self as ast, Expr, PySourceType}; -use ruff_python_parser::{lexer, AsMode, Tok}; +use ruff_python_ast::{self as ast, Expr}; use ruff_source_file::Locator; use ruff_text_size::{Ranged, TextRange, TextSize}; @@ -46,74 +45,36 @@ impl AlwaysFixableViolation for FStringMissingPlaceholders { } } -/// Return an iterator containing a two-element tuple for each f-string part -/// in the given [`ExprFString`] expression. -/// -/// The first element of the tuple is the f-string prefix range, and the second -/// element is the entire f-string range. It returns an iterator because of the -/// possibility of multiple f-strings implicitly concatenated together. -/// -/// For example, -/// -/// ```python -/// f"first" rf"second" -/// # ^ ^ (prefix range) -/// # ^^^^^^^^ ^^^^^^^^^^ (token range) -/// ``` -/// -/// would return `[(0..1, 0..8), (10..11, 9..19)]`. -/// -/// This function assumes that the given f-string expression is without any -/// placeholder expressions. -/// -/// [`ExprFString`]: `ruff_python_ast::ExprFString` -fn fstring_prefix_and_tok_range<'a>( - fstring: &'a ast::ExprFString, - locator: &'a Locator, - source_type: PySourceType, -) -> impl Iterator + 'a { - let contents = locator.slice(fstring); - let mut current_f_string_start = fstring.start(); - lexer::lex_starts_at(contents, source_type.as_mode(), fstring.start()) - .flatten() - .filter_map(move |(tok, range)| match tok { - Tok::FStringStart => { - current_f_string_start = range.start(); - None - } - Tok::FStringEnd => { - let first_char = - locator.slice(TextRange::at(current_f_string_start, TextSize::from(1))); - // f"..." => f_position = 0 - // fr"..." => f_position = 0 - // rf"..." => f_position = 1 - let f_position = u32::from(!(first_char == "f" || first_char == "F")); - Some(( - TextRange::at( - current_f_string_start + TextSize::from(f_position), - TextSize::from(1), - ), - TextRange::new(current_f_string_start, range.end()), - )) - } - _ => None, - }) -} - /// F541 -pub(crate) fn f_string_missing_placeholders(fstring: &ast::ExprFString, checker: &mut Checker) { - if !fstring.values.iter().any(Expr::is_formatted_value_expr) { - for (prefix_range, tok_range) in - fstring_prefix_and_tok_range(fstring, checker.locator(), checker.source_type) - { - let mut diagnostic = Diagnostic::new(FStringMissingPlaceholders, tok_range); - diagnostic.set_fix(convert_f_string_to_regular_string( - prefix_range, - tok_range, - checker.locator(), - )); - checker.diagnostics.push(diagnostic); - } +pub(crate) fn f_string_missing_placeholders(checker: &mut Checker, expr: &ast::ExprFString) { + if expr + .value + .f_strings() + .any(|f_string| f_string.values.iter().any(Expr::is_formatted_value_expr)) + { + return; + } + + for f_string in expr.value.f_strings() { + let first_char = checker + .locator() + .slice(TextRange::at(f_string.start(), TextSize::new(1))); + // f"..." => f_position = 0 + // fr"..." => f_position = 0 + // rf"..." => f_position = 1 + let f_position = u32::from(!(first_char == "f" || first_char == "F")); + let prefix_range = TextRange::at( + f_string.start() + TextSize::new(f_position), + TextSize::new(1), + ); + + let mut diagnostic = Diagnostic::new(FStringMissingPlaceholders, f_string.range()); + diagnostic.set_fix(convert_f_string_to_regular_string( + prefix_range, + f_string.range(), + checker.locator(), + )); + checker.diagnostics.push(diagnostic); } } @@ -129,12 +90,12 @@ fn unescape_f_string(content: &str) -> String { /// Generate a [`Fix`] to rewrite an f-string as a regular string. fn convert_f_string_to_regular_string( prefix_range: TextRange, - tok_range: TextRange, + node_range: TextRange, locator: &Locator, ) -> Fix { // Extract the f-string body. let mut content = - unescape_f_string(locator.slice(TextRange::new(prefix_range.end(), tok_range.end()))); + unescape_f_string(locator.slice(TextRange::new(prefix_range.end(), node_range.end()))); // If the preceding character is equivalent to the quote character, insert a space to avoid a // syntax error. For example, when removing the `f` prefix in `""f""`, rewrite to `"" ""` @@ -151,6 +112,6 @@ fn convert_f_string_to_regular_string( Fix::safe_edit(Edit::replacement( content, prefix_range.start(), - tok_range.end(), + node_range.end(), )) } diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs b/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs index 8821f576ffbd0..5aacba2f765dd 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs @@ -641,7 +641,7 @@ pub(crate) fn percent_format_missing_arguments( for key in keys.iter().flatten() { match key { Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { - keywords.insert(value); + keywords.insert(value.as_str()); } _ => { return; // Dynamic keys present @@ -652,7 +652,7 @@ pub(crate) fn percent_format_missing_arguments( let missing: Vec<&String> = summary .keywords .iter() - .filter(|k| !keywords.contains(k)) + .filter(|k| !keywords.contains(k.as_str())) .collect(); if !missing.is_empty() { diff --git a/crates/ruff_linter/src/rules/pylint/helpers.rs b/crates/ruff_linter/src/rules/pylint/helpers.rs index aadd753b00f01..8c040f2ed2c87 100644 --- a/crates/ruff_linter/src/rules/pylint/helpers.rs +++ b/crates/ruff_linter/src/rules/pylint/helpers.rs @@ -11,8 +11,8 @@ use crate::settings::LinterSettings; pub(super) fn type_param_name(arguments: &Arguments) -> Option<&str> { // Handle both `TypeVar("T")` and `TypeVar(name="T")`. let name_param = arguments.find_argument("name", 0)?; - if let Expr::StringLiteral(ast::ExprStringLiteral { value: name, .. }) = &name_param { - Some(name) + if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &name_param { + Some(value) } else { None } diff --git a/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs b/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs index f32bbd98946db..fee8f01a5c575 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs @@ -69,27 +69,34 @@ pub(crate) fn assert_on_string_literal(checker: &mut Checker, test: &Expr) { test.range(), )); } - Expr::FString(ast::ExprFString { values, .. }) => { - checker.diagnostics.push(Diagnostic::new( - AssertOnStringLiteral { - kind: if values.iter().all(|value| match value { - Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { - value.is_empty() - } - _ => false, - }) { - Kind::Empty - } else if values.iter().any(|value| match value { - Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { - !value.is_empty() - } - _ => false, - }) { - Kind::NonEmpty + Expr::FString(ast::ExprFString { value, .. }) => { + let kind = if value.parts().all(|f_string_part| match f_string_part { + ast::FStringPart::Literal(literal) => literal.is_empty(), + ast::FStringPart::FString(f_string) => f_string.values.iter().all(|value| { + if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = value { + value.is_empty() } else { - Kind::Unknown - }, - }, + false + } + }), + }) { + Kind::Empty + } else if value.parts().any(|f_string_part| match f_string_part { + ast::FStringPart::Literal(literal) => !literal.is_empty(), + ast::FStringPart::FString(f_string) => f_string.values.iter().any(|value| { + if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = value { + !value.is_empty() + } else { + false + } + }), + }) { + Kind::NonEmpty + } else { + Kind::Unknown + }; + checker.diagnostics.push(Diagnostic::new( + AssertOnStringLiteral { kind }, test.range(), )); } diff --git a/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_type.rs b/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_type.rs index 4d62c785de583..60b6b9bc5b05f 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_type.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_type.rs @@ -124,8 +124,8 @@ fn equivalent(format: &CFormatSpec, value: &Expr) -> bool { ResolvedPythonType::Atom(atom) => { // Special case where `%c` allows single character strings to be formatted if format.format_char == 'c' { - if let Expr::StringLiteral(string) = value { - let mut chars = string.chars(); + if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = value { + let mut chars = value.chars(); if chars.next().is_some() && chars.next().is_none() { return true; } diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/native_literals.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/native_literals.rs index 4828c46ebd270..fe151f4e459d9 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/native_literals.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/native_literals.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{self as ast, Expr}; +use ruff_python_ast::{self as ast, Expr, LiteralExpressionRef}; use ruff_text_size::{Ranged, TextRange}; use crate::checkers::ast::Checker; @@ -52,20 +52,24 @@ impl LiteralType { } } -impl TryFrom<&Expr> for LiteralType { +impl TryFrom> for LiteralType { type Error = (); - fn try_from(expr: &Expr) -> Result { - match expr { - Expr::StringLiteral(_) => Ok(LiteralType::Str), - Expr::BytesLiteral(_) => Ok(LiteralType::Bytes), - Expr::NumberLiteral(ast::ExprNumberLiteral { value, .. }) => match value { - ast::Number::Int(_) => Ok(LiteralType::Int), - ast::Number::Float(_) => Ok(LiteralType::Float), - ast::Number::Complex { .. } => Err(()), - }, - Expr::BooleanLiteral(_) => Ok(LiteralType::Bool), - _ => Err(()), + fn try_from(literal_expr: LiteralExpressionRef<'_>) -> Result { + match literal_expr { + LiteralExpressionRef::StringLiteral(_) => Ok(LiteralType::Str), + LiteralExpressionRef::BytesLiteral(_) => Ok(LiteralType::Bytes), + LiteralExpressionRef::NumberLiteral(ast::ExprNumberLiteral { value, .. }) => { + match value { + ast::Number::Int(_) => Ok(LiteralType::Int), + ast::Number::Float(_) => Ok(LiteralType::Float), + ast::Number::Complex { .. } => Err(()), + } + } + LiteralExpressionRef::BooleanLiteral(_) => Ok(LiteralType::Bool), + LiteralExpressionRef::NoneLiteral(_) | LiteralExpressionRef::EllipsisLiteral(_) => { + Err(()) + } } } } @@ -194,12 +198,16 @@ pub(crate) fn native_literals( checker.diagnostics.push(diagnostic); } Some(arg) => { + let Some(literal_expr) = arg.as_literal_expr() else { + return; + }; + // Skip implicit string concatenations. - if arg.is_implicit_concatenated_string() { + if literal_expr.is_implicit_concatenated() { return; } - let Ok(arg_literal_type) = LiteralType::try_from(arg) else { + let Ok(arg_literal_type) = LiteralType::try_from(literal_expr) else { return; }; diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/unicode_kind_prefix.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/unicode_kind_prefix.rs index 481bd9548253c..60c09586a6aa5 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/unicode_kind_prefix.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/unicode_kind_prefix.rs @@ -1,11 +1,10 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; - -use ruff_python_parser::lexer::LexResult; -use ruff_python_parser::{StringKind, Tok}; - +use ruff_python_ast::StringLiteral; use ruff_text_size::{Ranged, TextRange, TextSize}; +use crate::checkers::ast::Checker; + /// ## What it does /// Checks for uses of the Unicode kind prefix (`u`) in strings. /// @@ -40,19 +39,13 @@ impl AlwaysFixableViolation for UnicodeKindPrefix { } /// UP025 -pub(crate) fn unicode_kind_prefix(diagnostics: &mut Vec, tokens: &[LexResult]) { - for (token, range) in tokens.iter().flatten() { - if let Tok::String { - kind: StringKind::Unicode, - .. - } = token - { - let mut diagnostic = Diagnostic::new(UnicodeKindPrefix, *range); - diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(TextRange::at( - range.start(), - TextSize::from(1), - )))); - diagnostics.push(diagnostic); - } +pub(crate) fn unicode_kind_prefix(checker: &mut Checker, string: &StringLiteral) { + if string.unicode { + let mut diagnostic = Diagnostic::new(UnicodeKindPrefix, string.range); + diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(TextRange::at( + string.start(), + TextSize::from(1), + )))); + checker.diagnostics.push(diagnostic); } } diff --git a/crates/ruff_linter/src/rules/refurb/rules/read_whole_file.rs b/crates/ruff_linter/src/rules/refurb/rules/read_whole_file.rs index b71306c3444ae..f90f3d114f28b 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/read_whole_file.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/read_whole_file.rs @@ -244,14 +244,10 @@ fn match_open_keywords( /// Match open mode to see if it is supported. fn match_open_mode(mode: &Expr) -> Option { - let ast::ExprStringLiteral { - value, - implicit_concatenated: false, - .. - } = mode.as_string_literal_expr()? - else { + let ast::ExprStringLiteral { value, .. } = mode.as_string_literal_expr()?; + if value.is_implicit_concatenated() { return None; - }; + } match value.as_str() { "r" => Some(ReadMode::Text), "rb" => Some(ReadMode::Bytes), diff --git a/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs b/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs index 1931270157b1a..d30a04705ea76 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs @@ -1,7 +1,4 @@ use anyhow::{bail, Result}; -use libcst_native::{ - ConcatenatedString, Expression, FormattedStringContent, FormattedStringExpression, -}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; @@ -11,7 +8,10 @@ use ruff_source_file::Locator; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; -use crate::cst::matchers::{match_call_mut, match_name, transform_expression}; +use crate::cst::matchers::{ + match_call_mut, match_formatted_string, match_formatted_string_expression, match_name, + transform_expression, +}; /// ## What it does /// Checks for uses of `str()`, `repr()`, and `ascii()` as explicit type @@ -52,25 +52,14 @@ impl AlwaysFixableViolation for ExplicitFStringTypeConversion { } /// RUF010 -pub(crate) fn explicit_f_string_type_conversion( - checker: &mut Checker, - expr: &Expr, - values: &[Expr], -) { - for (index, formatted_value) in values - .iter() - .filter_map(|expr| { - if let Expr::FormattedValue(expr) = &expr { - Some(expr) - } else { - None - } - }) - .enumerate() - { - let ast::ExprFormattedValue { +pub(crate) fn explicit_f_string_type_conversion(checker: &mut Checker, f_string: &ast::FString) { + for (index, expr) in f_string.values.iter().enumerate() { + let Some(ast::ExprFormattedValue { value, conversion, .. - } = formatted_value; + }) = expr.as_formatted_value_expr() + else { + continue; + }; // Skip if there's already a conversion flag. if !conversion.is_none() { @@ -123,7 +112,7 @@ pub(crate) fn explicit_f_string_type_conversion( let mut diagnostic = Diagnostic::new(ExplicitFStringTypeConversion, value.range()); diagnostic.try_set_fix(|| { - convert_call_to_conversion_flag(expr, index, checker.locator(), checker.stylist()) + convert_call_to_conversion_flag(f_string, index, checker.locator(), checker.stylist()) }); checker.diagnostics.push(diagnostic); } @@ -131,15 +120,17 @@ pub(crate) fn explicit_f_string_type_conversion( /// Generate a [`Fix`] to replace an explicit type conversion with a conversion flag. fn convert_call_to_conversion_flag( - expr: &Expr, + f_string: &ast::FString, index: usize, locator: &Locator, stylist: &Stylist, ) -> Result { - let source_code = locator.slice(expr); + let source_code = locator.slice(f_string); transform_expression(source_code, stylist, |mut expression| { + let formatted_string = match_formatted_string(&mut expression)?; // Replace the formatted call expression at `index` with a conversion flag. - let formatted_string_expression = match_part(index, &mut expression)?; + let formatted_string_expression = + match_formatted_string_expression(&mut formatted_string.parts[index])?; let call = match_call_mut(&mut formatted_string_expression.expression)?; let name = match_name(&call.func)?; match name.value { @@ -157,63 +148,5 @@ fn convert_call_to_conversion_flag( formatted_string_expression.expression = call.args[0].value.clone(); Ok(expression) }) - .map(|output| Fix::safe_edit(Edit::range_replacement(output, expr.range()))) -} - -/// Return the [`FormattedStringContent`] at the given index in an f-string or implicit -/// string concatenation. -fn match_part<'a, 'b>( - index: usize, - expr: &'a mut Expression<'b>, -) -> Result<&'a mut FormattedStringExpression<'b>> { - match expr { - Expression::ConcatenatedString(expr) => Ok(collect_parts(expr).remove(index)), - Expression::FormattedString(expr) => { - // Find the formatted expression at the given index. The `parts` field contains a mix - // of string literals and expressions, but our `index` only counts expressions. All - // the boxing and mutability makes this difficult to write in a functional style. - let mut format_index = 0; - for part in &mut expr.parts { - if let FormattedStringContent::Expression(expr) = part { - if format_index == index { - return Ok(expr); - } - format_index += 1; - } - } - - bail!("Index out of bounds: `{index}`") - } - _ => bail!("Unexpected expression: `{:?}`", expr), - } -} - -/// Given an implicit string concatenation, return a list of all the formatted expressions. -fn collect_parts<'a, 'b>( - expr: &'a mut ConcatenatedString<'b>, -) -> Vec<&'a mut FormattedStringExpression<'b>> { - fn inner<'a, 'b>( - string: &'a mut libcst_native::String<'b>, - formatted_expressions: &mut Vec<&'a mut FormattedStringExpression<'b>>, - ) { - match string { - libcst_native::String::Formatted(expr) => { - for part in &mut expr.parts { - if let FormattedStringContent::Expression(expr) = part { - formatted_expressions.push(expr); - } - } - } - libcst_native::String::Concatenated(expr) => { - inner(&mut expr.left, formatted_expressions); - inner(&mut expr.right, formatted_expressions); - } - libcst_native::String::Simple(_) => {} - } - } - - let mut formatted_expressions = vec![]; - inner(&mut expr.left, &mut formatted_expressions); - inner(&mut expr.right, &mut formatted_expressions); - formatted_expressions + .map(|output| Fix::safe_edit(Edit::range_replacement(output, f_string.range()))) } diff --git a/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs b/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs index db23de636b7a5..065fa94ec1a83 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs @@ -184,7 +184,6 @@ pub(crate) fn implicit_optional(checker: &mut Checker, parameters: &Parameters) if let Expr::StringLiteral(ast::ExprStringLiteral { range, value: string, - .. }) = annotation.as_ref() { // Quoted annotation. diff --git a/crates/ruff_linter/src/rules/ruff/typing.rs b/crates/ruff_linter/src/rules/ruff/typing.rs index 730e93357ef94..f02cc09ad5ad0 100644 --- a/crates/ruff_linter/src/rules/ruff/typing.rs +++ b/crates/ruff_linter/src/rules/ruff/typing.rs @@ -111,7 +111,6 @@ impl<'a> TypingTarget<'a> { Expr::StringLiteral(ast::ExprStringLiteral { value: string, range, - .. }) => parse_type_annotation(string, *range, locator.contents()) .map_or(None, |(expr, _)| Some(TypingTarget::ForwardReference(expr))), _ => semantic.resolve_call_path(expr).map_or( diff --git a/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs b/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs index 58f94a56e7bf3..acb257705063b 100644 --- a/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs +++ b/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs @@ -89,10 +89,21 @@ pub(crate) fn raise_vanilla_args(checker: &mut Checker, expr: &Expr) { /// some whitespace). fn contains_message(expr: &Expr) -> bool { match expr { - Expr::FString(ast::ExprFString { values, .. }) => { - for value in values { - if contains_message(value) { - return true; + Expr::FString(ast::ExprFString { value, .. }) => { + for f_string_part in value.parts() { + match f_string_part { + ast::FStringPart::Literal(literal) => { + if literal.chars().any(char::is_whitespace) { + return true; + } + } + ast::FStringPart::FString(f_string) => { + for value in &f_string.values { + if contains_message(value) { + return true; + } + } + } } } } diff --git a/crates/ruff_python_ast/src/comparable.rs b/crates/ruff_python_ast/src/comparable.rs index dbbe6e75a351c..0fe4a17f8e8b0 100644 --- a/crates/ruff_python_ast/src/comparable.rs +++ b/crates/ruff_python_ast/src/comparable.rs @@ -529,6 +529,91 @@ impl<'a> From<&'a ast::ElifElseClause> for ComparableElifElseClause<'a> { } } +#[derive(Debug, PartialEq, Eq, Hash)] +pub enum ComparableLiteral<'a> { + None, + Ellipsis, + Bool(&'a bool), + Str(Vec>), + Bytes(Vec>), + Number(ComparableNumber<'a>), +} + +impl<'a> From> for ComparableLiteral<'a> { + fn from(literal: ast::LiteralExpressionRef<'a>) -> Self { + match literal { + ast::LiteralExpressionRef::NoneLiteral(_) => Self::None, + ast::LiteralExpressionRef::EllipsisLiteral(_) => Self::Ellipsis, + ast::LiteralExpressionRef::BooleanLiteral(ast::ExprBooleanLiteral { + value, .. + }) => Self::Bool(value), + ast::LiteralExpressionRef::StringLiteral(ast::ExprStringLiteral { value, .. }) => { + Self::Str(value.parts().map(Into::into).collect()) + } + ast::LiteralExpressionRef::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => { + Self::Bytes(value.parts().map(Into::into).collect()) + } + ast::LiteralExpressionRef::NumberLiteral(ast::ExprNumberLiteral { value, .. }) => { + Self::Number(value.into()) + } + } + } +} + +#[derive(Debug, PartialEq, Eq, Hash)] +pub struct ComparableFString<'a> { + values: Vec>, +} + +impl<'a> From<&'a ast::FString> for ComparableFString<'a> { + fn from(fstring: &'a ast::FString) -> Self { + Self { + values: fstring.values.iter().map(Into::into).collect(), + } + } +} + +#[derive(Debug, PartialEq, Eq, Hash)] +pub enum ComparableFStringPart<'a> { + Literal(ComparableStringLiteral<'a>), + FString(ComparableFString<'a>), +} + +impl<'a> From<&'a ast::FStringPart> for ComparableFStringPart<'a> { + fn from(f_string_part: &'a ast::FStringPart) -> Self { + match f_string_part { + ast::FStringPart::Literal(string_literal) => Self::Literal(string_literal.into()), + ast::FStringPart::FString(f_string) => Self::FString(f_string.into()), + } + } +} + +#[derive(Debug, PartialEq, Eq, Hash)] +pub struct ComparableStringLiteral<'a> { + value: &'a str, +} + +impl<'a> From<&'a ast::StringLiteral> for ComparableStringLiteral<'a> { + fn from(string_literal: &'a ast::StringLiteral) -> Self { + Self { + value: string_literal.value.as_str(), + } + } +} + +#[derive(Debug, PartialEq, Eq, Hash)] +pub struct ComparableBytesLiteral<'a> { + value: &'a [u8], +} + +impl<'a> From<&'a ast::BytesLiteral> for ComparableBytesLiteral<'a> { + fn from(bytes_literal: &'a ast::BytesLiteral) -> Self { + Self { + value: bytes_literal.value.as_slice(), + } + } +} + #[derive(Debug, PartialEq, Eq, Hash)] pub struct ExprBoolOp<'a> { op: ComparableBoolOp, @@ -641,48 +726,17 @@ pub struct ExprFormattedValue<'a> { #[derive(Debug, PartialEq, Eq, Hash)] pub struct ExprFString<'a> { - values: Vec>, -} - -#[derive(Debug, PartialEq, Eq, Hash)] -pub enum ComparableLiteral<'a> { - None, - Ellipsis, - Bool(&'a bool), - Str(&'a str), - Bytes(&'a [u8]), - Number(ComparableNumber<'a>), -} - -impl<'a> From> for ComparableLiteral<'a> { - fn from(literal: ast::LiteralExpressionRef<'a>) -> Self { - match literal { - ast::LiteralExpressionRef::NoneLiteral(_) => Self::None, - ast::LiteralExpressionRef::EllipsisLiteral(_) => Self::Ellipsis, - ast::LiteralExpressionRef::BooleanLiteral(ast::ExprBooleanLiteral { - value, .. - }) => Self::Bool(value), - ast::LiteralExpressionRef::StringLiteral(ast::ExprStringLiteral { value, .. }) => { - Self::Str(value) - } - ast::LiteralExpressionRef::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => { - Self::Bytes(value) - } - ast::LiteralExpressionRef::NumberLiteral(ast::ExprNumberLiteral { value, .. }) => { - Self::Number(value.into()) - } - } - } + parts: Vec>, } #[derive(Debug, PartialEq, Eq, Hash)] pub struct ExprStringLiteral<'a> { - value: &'a str, + parts: Vec>, } #[derive(Debug, PartialEq, Eq, Hash)] pub struct ExprBytesLiteral<'a> { - value: &'a [u8], + parts: Vec>, } #[derive(Debug, PartialEq, Eq, Hash)] @@ -933,28 +987,21 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> { debug_text: debug_text.as_ref(), format_spec: format_spec.as_ref().map(Into::into), }), - ast::Expr::FString(ast::ExprFString { - values, - implicit_concatenated: _, - range: _, - }) => Self::FString(ExprFString { - values: values.iter().map(Into::into).collect(), - }), - ast::Expr::StringLiteral(ast::ExprStringLiteral { - value, - // Compare strings based on resolved value, not representation (i.e., ignore whether - // the string was implicitly concatenated). - implicit_concatenated: _, - unicode: _, - range: _, - }) => Self::StringLiteral(ExprStringLiteral { value }), - ast::Expr::BytesLiteral(ast::ExprBytesLiteral { - value, - // Compare bytes based on resolved value, not representation (i.e., ignore whether - // the bytes was implicitly concatenated). - implicit_concatenated: _, - range: _, - }) => Self::BytesLiteral(ExprBytesLiteral { value }), + ast::Expr::FString(ast::ExprFString { value, range: _ }) => { + Self::FString(ExprFString { + parts: value.parts().map(Into::into).collect(), + }) + } + ast::Expr::StringLiteral(ast::ExprStringLiteral { value, range: _ }) => { + Self::StringLiteral(ExprStringLiteral { + parts: value.parts().map(Into::into).collect(), + }) + } + ast::Expr::BytesLiteral(ast::ExprBytesLiteral { value, range: _ }) => { + Self::BytesLiteral(ExprBytesLiteral { + parts: value.parts().map(Into::into).collect(), + }) + } ast::Expr::NumberLiteral(ast::ExprNumberLiteral { value, range: _ }) => { Self::NumberLiteral(ExprNumberLiteral { value: value.into(), diff --git a/crates/ruff_python_ast/src/expression.rs b/crates/ruff_python_ast/src/expression.rs index 83bac7272442c..4bdc46f7dbf8d 100644 --- a/crates/ruff_python_ast/src/expression.rs +++ b/crates/ruff_python_ast/src/expression.rs @@ -361,3 +361,44 @@ impl Ranged for LiteralExpressionRef<'_> { } } } + +impl<'a> From> for AnyNodeRef<'a> { + fn from(value: LiteralExpressionRef<'a>) -> Self { + match value { + LiteralExpressionRef::StringLiteral(expression) => { + AnyNodeRef::ExprStringLiteral(expression) + } + LiteralExpressionRef::BytesLiteral(expression) => { + AnyNodeRef::ExprBytesLiteral(expression) + } + LiteralExpressionRef::NumberLiteral(expression) => { + AnyNodeRef::ExprNumberLiteral(expression) + } + LiteralExpressionRef::BooleanLiteral(expression) => { + AnyNodeRef::ExprBooleanLiteral(expression) + } + LiteralExpressionRef::NoneLiteral(expression) => { + AnyNodeRef::ExprNoneLiteral(expression) + } + LiteralExpressionRef::EllipsisLiteral(expression) => { + AnyNodeRef::ExprEllipsisLiteral(expression) + } + } + } +} + +impl LiteralExpressionRef<'_> { + /// Returns `true` if the literal is either a string or bytes literal that + /// is implicitly concatenated. + pub fn is_implicit_concatenated(&self) -> bool { + match self { + LiteralExpressionRef::StringLiteral(expression) => { + expression.value.is_implicit_concatenated() + } + LiteralExpressionRef::BytesLiteral(expression) => { + expression.value.is_implicit_concatenated() + } + _ => false, + } + } +} diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index 24b63669c1e21..a82b5677df7fa 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -133,10 +133,12 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool { return true; } match expr { - Expr::BoolOp(ast::ExprBoolOp { values, .. }) - | Expr::FString(ast::ExprFString { values, .. }) => { + Expr::BoolOp(ast::ExprBoolOp { values, .. }) => { values.iter().any(|expr| any_over_expr(expr, func)) } + Expr::FString(ast::ExprFString { value, .. }) => { + value.elements().any(|expr| any_over_expr(expr, func)) + } Expr::NamedExpr(ast::ExprNamedExpr { target, value, @@ -1139,11 +1141,14 @@ impl Truthiness { } Expr::NoneLiteral(_) => Self::Falsey, Expr::EllipsisLiteral(_) => Self::Truthy, - Expr::FString(ast::ExprFString { values, .. }) => { - if values.is_empty() { + Expr::FString(ast::ExprFString { value, .. }) => { + if value.parts().all(|part| match part { + ast::FStringPart::Literal(string_literal) => string_literal.is_empty(), + ast::FStringPart::FString(f_string) => f_string.values.is_empty(), + }) { Self::Falsey - } else if values.iter().any(|value| { - if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &value { + } else if value.elements().any(|expr| { + if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &expr { !value.is_empty() } else { false diff --git a/crates/ruff_python_ast/src/node.rs b/crates/ruff_python_ast/src/node.rs index e1a3b5ebf6486..e21a000d79ae7 100644 --- a/crates/ruff_python_ast/src/node.rs +++ b/crates/ruff_python_ast/src/node.rs @@ -113,6 +113,9 @@ pub enum AnyNode { TypeParamTypeVar(TypeParamTypeVar), TypeParamTypeVarTuple(TypeParamTypeVarTuple), TypeParamParamSpec(TypeParamParamSpec), + FString(ast::FString), + StringLiteral(ast::StringLiteral), + BytesLiteral(ast::BytesLiteral), } impl AnyNode { @@ -204,6 +207,9 @@ impl AnyNode { | AnyNode::TypeParamTypeVar(_) | AnyNode::TypeParamTypeVarTuple(_) | AnyNode::TypeParamParamSpec(_) + | AnyNode::FString(_) + | AnyNode::StringLiteral(_) + | AnyNode::BytesLiteral(_) | AnyNode::ElifElseClause(_) => None, } } @@ -296,6 +302,9 @@ impl AnyNode { | AnyNode::TypeParamTypeVar(_) | AnyNode::TypeParamTypeVarTuple(_) | AnyNode::TypeParamParamSpec(_) + | AnyNode::FString(_) + | AnyNode::StringLiteral(_) + | AnyNode::BytesLiteral(_) | AnyNode::ElifElseClause(_) => None, } } @@ -388,6 +397,9 @@ impl AnyNode { | AnyNode::TypeParamTypeVar(_) | AnyNode::TypeParamTypeVarTuple(_) | AnyNode::TypeParamParamSpec(_) + | AnyNode::FString(_) + | AnyNode::StringLiteral(_) + | AnyNode::BytesLiteral(_) | AnyNode::ElifElseClause(_) => None, } } @@ -480,6 +492,9 @@ impl AnyNode { | AnyNode::TypeParamTypeVar(_) | AnyNode::TypeParamTypeVarTuple(_) | AnyNode::TypeParamParamSpec(_) + | AnyNode::FString(_) + | AnyNode::StringLiteral(_) + | AnyNode::BytesLiteral(_) | AnyNode::ElifElseClause(_) => None, } } @@ -572,6 +587,9 @@ impl AnyNode { | AnyNode::TypeParamTypeVar(_) | AnyNode::TypeParamTypeVarTuple(_) | AnyNode::TypeParamParamSpec(_) + | AnyNode::FString(_) + | AnyNode::StringLiteral(_) + | AnyNode::BytesLiteral(_) | AnyNode::ElifElseClause(_) => None, } } @@ -683,6 +701,9 @@ impl AnyNode { Self::TypeParamTypeVar(node) => AnyNodeRef::TypeParamTypeVar(node), Self::TypeParamTypeVarTuple(node) => AnyNodeRef::TypeParamTypeVarTuple(node), Self::TypeParamParamSpec(node) => AnyNodeRef::TypeParamParamSpec(node), + Self::FString(node) => AnyNodeRef::FString(node), + Self::StringLiteral(node) => AnyNodeRef::StringLiteral(node), + Self::BytesLiteral(node) => AnyNodeRef::BytesLiteral(node), Self::ElifElseClause(node) => AnyNodeRef::ElifElseClause(node), } } @@ -2674,14 +2695,17 @@ impl AstNode for ast::ExprFString { where V: PreorderVisitor<'a> + ?Sized, { - let ast::ExprFString { - values, - implicit_concatenated: _, - range: _, - } = self; + let ast::ExprFString { value, range: _ } = self; - for expr in values { - visitor.visit_expr(expr); + for f_string_part in value.parts() { + match f_string_part { + ast::FStringPart::Literal(string_literal) => { + visitor.visit_string_literal(string_literal); + } + ast::FStringPart::FString(f_string) => { + visitor.visit_f_string(f_string); + } + } } } } @@ -2713,10 +2737,15 @@ impl AstNode for ast::ExprStringLiteral { AnyNode::from(self) } - fn visit_preorder<'a, V>(&'a self, _visitor: &mut V) + fn visit_preorder<'a, V>(&'a self, visitor: &mut V) where V: PreorderVisitor<'a> + ?Sized, { + let ast::ExprStringLiteral { value, range: _ } = self; + + for string_literal in value.parts() { + visitor.visit_string_literal(string_literal); + } } } impl AstNode for ast::ExprBytesLiteral { @@ -2747,10 +2776,15 @@ impl AstNode for ast::ExprBytesLiteral { AnyNode::from(self) } - fn visit_preorder<'a, V>(&'a self, _visitor: &mut V) + fn visit_preorder<'a, V>(&'a self, visitor: &mut V) where V: PreorderVisitor<'a> + ?Sized, { + let ast::ExprBytesLiteral { value, range: _ } = self; + + for bytes_literal in value.parts() { + visitor.visit_bytes_literal(bytes_literal); + } } } impl AstNode for ast::ExprNumberLiteral { @@ -4273,6 +4307,114 @@ impl AstNode for ast::TypeParamParamSpec { let ast::TypeParamParamSpec { range: _, name: _ } = self; } } +impl AstNode for ast::FString { + fn cast(kind: AnyNode) -> Option + where + Self: Sized, + { + if let AnyNode::FString(node) = kind { + Some(node) + } else { + None + } + } + + fn cast_ref(kind: AnyNodeRef) -> Option<&Self> { + if let AnyNodeRef::FString(node) = kind { + Some(node) + } else { + None + } + } + + fn as_any_node_ref(&self) -> AnyNodeRef { + AnyNodeRef::from(self) + } + + fn into_any_node(self) -> AnyNode { + AnyNode::from(self) + } + + fn visit_preorder<'a, V>(&'a self, visitor: &mut V) + where + V: PreorderVisitor<'a> + ?Sized, + { + let ast::FString { values, range: _ } = self; + + for expr in values { + visitor.visit_expr(expr); + } + } +} +impl AstNode for ast::StringLiteral { + fn cast(kind: AnyNode) -> Option + where + Self: Sized, + { + if let AnyNode::StringLiteral(node) = kind { + Some(node) + } else { + None + } + } + + fn cast_ref(kind: AnyNodeRef) -> Option<&Self> { + if let AnyNodeRef::StringLiteral(node) = kind { + Some(node) + } else { + None + } + } + + fn as_any_node_ref(&self) -> AnyNodeRef { + AnyNodeRef::from(self) + } + + fn into_any_node(self) -> AnyNode { + AnyNode::from(self) + } + + fn visit_preorder<'a, V>(&'a self, _visitor: &mut V) + where + V: PreorderVisitor<'a> + ?Sized, + { + } +} +impl AstNode for ast::BytesLiteral { + fn cast(kind: AnyNode) -> Option + where + Self: Sized, + { + if let AnyNode::BytesLiteral(node) = kind { + Some(node) + } else { + None + } + } + + fn cast_ref(kind: AnyNodeRef) -> Option<&Self> { + if let AnyNodeRef::BytesLiteral(node) = kind { + Some(node) + } else { + None + } + } + + fn as_any_node_ref(&self) -> AnyNodeRef { + AnyNodeRef::from(self) + } + + fn into_any_node(self) -> AnyNode { + AnyNode::from(self) + } + + fn visit_preorder<'a, V>(&'a self, _visitor: &mut V) + where + V: PreorderVisitor<'a> + ?Sized, + { + } +} + impl From for AnyNode { fn from(stmt: Stmt) -> Self { match stmt { @@ -4882,6 +5024,24 @@ impl From for AnyNode { } } +impl From for AnyNode { + fn from(node: ast::FString) -> Self { + AnyNode::FString(node) + } +} + +impl From for AnyNode { + fn from(node: ast::StringLiteral) -> Self { + AnyNode::StringLiteral(node) + } +} + +impl From for AnyNode { + fn from(node: ast::BytesLiteral) -> Self { + AnyNode::BytesLiteral(node) + } +} + impl Ranged for AnyNode { fn range(&self) -> TextRange { match self { @@ -4970,6 +5130,9 @@ impl Ranged for AnyNode { AnyNode::TypeParamTypeVar(node) => node.range(), AnyNode::TypeParamTypeVarTuple(node) => node.range(), AnyNode::TypeParamParamSpec(node) => node.range(), + AnyNode::FString(node) => node.range(), + AnyNode::StringLiteral(node) => node.range(), + AnyNode::BytesLiteral(node) => node.range(), AnyNode::ElifElseClause(node) => node.range(), } } @@ -5062,6 +5225,9 @@ pub enum AnyNodeRef<'a> { TypeParamTypeVar(&'a TypeParamTypeVar), TypeParamTypeVarTuple(&'a TypeParamTypeVarTuple), TypeParamParamSpec(&'a TypeParamParamSpec), + FString(&'a ast::FString), + StringLiteral(&'a ast::StringLiteral), + BytesLiteral(&'a ast::BytesLiteral), ElifElseClause(&'a ast::ElifElseClause), } @@ -5153,6 +5319,9 @@ impl<'a> AnyNodeRef<'a> { AnyNodeRef::TypeParamTypeVar(node) => NonNull::from(*node).cast(), AnyNodeRef::TypeParamTypeVarTuple(node) => NonNull::from(*node).cast(), AnyNodeRef::TypeParamParamSpec(node) => NonNull::from(*node).cast(), + AnyNodeRef::FString(node) => NonNull::from(*node).cast(), + AnyNodeRef::StringLiteral(node) => NonNull::from(*node).cast(), + AnyNodeRef::BytesLiteral(node) => NonNull::from(*node).cast(), AnyNodeRef::ElifElseClause(node) => NonNull::from(*node).cast(), } } @@ -5250,6 +5419,9 @@ impl<'a> AnyNodeRef<'a> { AnyNodeRef::TypeParamTypeVar(_) => NodeKind::TypeParamTypeVar, AnyNodeRef::TypeParamTypeVarTuple(_) => NodeKind::TypeParamTypeVarTuple, AnyNodeRef::TypeParamParamSpec(_) => NodeKind::TypeParamParamSpec, + AnyNodeRef::FString(_) => NodeKind::FString, + AnyNodeRef::StringLiteral(_) => NodeKind::StringLiteral, + AnyNodeRef::BytesLiteral(_) => NodeKind::BytesLiteral, AnyNodeRef::ElifElseClause(_) => NodeKind::ElifElseClause, } } @@ -5342,6 +5514,9 @@ impl<'a> AnyNodeRef<'a> { | AnyNodeRef::TypeParamTypeVar(_) | AnyNodeRef::TypeParamTypeVarTuple(_) | AnyNodeRef::TypeParamParamSpec(_) + | AnyNodeRef::FString(_) + | AnyNodeRef::StringLiteral(_) + | AnyNodeRef::BytesLiteral(_) | AnyNodeRef::ElifElseClause(_) => false, } } @@ -5434,6 +5609,9 @@ impl<'a> AnyNodeRef<'a> { | AnyNodeRef::TypeParamTypeVar(_) | AnyNodeRef::TypeParamTypeVarTuple(_) | AnyNodeRef::TypeParamParamSpec(_) + | AnyNodeRef::FString(_) + | AnyNodeRef::StringLiteral(_) + | AnyNodeRef::BytesLiteral(_) | AnyNodeRef::ElifElseClause(_) => false, } } @@ -5525,6 +5703,9 @@ impl<'a> AnyNodeRef<'a> { | AnyNodeRef::TypeParamTypeVar(_) | AnyNodeRef::TypeParamTypeVarTuple(_) | AnyNodeRef::TypeParamParamSpec(_) + | AnyNodeRef::FString(_) + | AnyNodeRef::StringLiteral(_) + | AnyNodeRef::BytesLiteral(_) | AnyNodeRef::ElifElseClause(_) => false, } } @@ -5617,6 +5798,9 @@ impl<'a> AnyNodeRef<'a> { | AnyNodeRef::TypeParamTypeVar(_) | AnyNodeRef::TypeParamTypeVarTuple(_) | AnyNodeRef::TypeParamParamSpec(_) + | AnyNodeRef::FString(_) + | AnyNodeRef::StringLiteral(_) + | AnyNodeRef::BytesLiteral(_) | AnyNodeRef::ElifElseClause(_) => false, } } @@ -5709,6 +5893,9 @@ impl<'a> AnyNodeRef<'a> { | AnyNodeRef::TypeParamTypeVar(_) | AnyNodeRef::TypeParamTypeVarTuple(_) | AnyNodeRef::TypeParamParamSpec(_) + | AnyNodeRef::FString(_) + | AnyNodeRef::StringLiteral(_) + | AnyNodeRef::BytesLiteral(_) | AnyNodeRef::ElifElseClause(_) => false, } } @@ -5829,6 +6016,9 @@ impl<'a> AnyNodeRef<'a> { AnyNodeRef::TypeParamTypeVar(node) => node.visit_preorder(visitor), AnyNodeRef::TypeParamTypeVarTuple(node) => node.visit_preorder(visitor), AnyNodeRef::TypeParamParamSpec(node) => node.visit_preorder(visitor), + AnyNodeRef::FString(node) => node.visit_preorder(visitor), + AnyNodeRef::StringLiteral(node) => node.visit_preorder(visitor), + AnyNodeRef::BytesLiteral(node) => node.visit_preorder(visitor), AnyNodeRef::ElifElseClause(node) => node.visit_preorder(visitor), } } @@ -6355,6 +6545,24 @@ impl<'a> From<&'a TypeParamParamSpec> for AnyNodeRef<'a> { } } +impl<'a> From<&'a ast::FString> for AnyNodeRef<'a> { + fn from(node: &'a ast::FString) -> Self { + AnyNodeRef::FString(node) + } +} + +impl<'a> From<&'a ast::StringLiteral> for AnyNodeRef<'a> { + fn from(node: &'a ast::StringLiteral) -> Self { + AnyNodeRef::StringLiteral(node) + } +} + +impl<'a> From<&'a ast::BytesLiteral> for AnyNodeRef<'a> { + fn from(node: &'a ast::BytesLiteral) -> Self { + AnyNodeRef::BytesLiteral(node) + } +} + impl<'a> From<&'a Stmt> for AnyNodeRef<'a> { fn from(stmt: &'a Stmt) -> Self { match stmt { @@ -6606,6 +6814,9 @@ impl Ranged for AnyNodeRef<'_> { AnyNodeRef::TypeParamTypeVar(node) => node.range(), AnyNodeRef::TypeParamTypeVarTuple(node) => node.range(), AnyNodeRef::TypeParamParamSpec(node) => node.range(), + AnyNodeRef::FString(node) => node.range(), + AnyNodeRef::StringLiteral(node) => node.range(), + AnyNodeRef::BytesLiteral(node) => node.range(), } } } @@ -6701,4 +6912,7 @@ pub enum NodeKind { TypeParamTypeVar, TypeParamTypeVarTuple, TypeParamParamSpec, + FString, + StringLiteral, + BytesLiteral, } diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index 0af30770e4f32..e0bc5b4730686 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -1,14 +1,17 @@ #![allow(clippy::derive_partial_eq_without_eq)] -use itertools::Itertools; - +use std::cell::OnceCell; use std::fmt; use std::fmt::Debug; use std::ops::Deref; -use crate::{int, LiteralExpressionRef}; +use itertools::Either::{Left, Right}; +use itertools::Itertools; + use ruff_text_size::{Ranged, TextRange, TextSize}; +use crate::{int, LiteralExpressionRef}; + /// See also [mod](https://docs.python.org/3/library/ast.html#ast.mod) #[derive(Clone, Debug, PartialEq, is_macro::Is)] pub enum Mod { @@ -640,6 +643,7 @@ impl Expr { ) } + /// Returns [`LiteralExpressionRef`] if the expression is a literal expression. pub fn as_literal_expr(&self) -> Option> { match self { Expr::StringLiteral(expr) => Some(LiteralExpressionRef::StringLiteral(expr)), @@ -651,24 +655,6 @@ impl Expr { _ => None, } } - - pub fn is_implicit_concatenated_string(&self) -> bool { - match self { - Expr::StringLiteral(ExprStringLiteral { - implicit_concatenated, - .. - }) - | Expr::BytesLiteral(ExprBytesLiteral { - implicit_concatenated, - .. - }) - | Expr::FString(ExprFString { - implicit_concatenated, - .. - }) => *implicit_concatenated, - _ => false, - } - } } /// An AST node used to represent a IPython escape command at the expression level. @@ -984,13 +970,17 @@ pub struct DebugText { pub trailing: String, } -/// See also [JoinedStr](https://docs.python.org/3/library/ast.html#ast.JoinedStr) +/// An AST node used to represent an f-string. +/// +/// This type differs from the original Python AST ([JoinedStr]) in that it +/// doesn't join the implicitly concatenated parts into a single string. Instead, +/// it keeps them separate and provide various methods to access the parts. +/// +/// [JoinedStr]: https://docs.python.org/3/library/ast.html#ast.JoinedStr #[derive(Clone, Debug, PartialEq)] pub struct ExprFString { pub range: TextRange, - pub values: Vec, - /// Whether the f-string contains multiple string tokens that were implicitly concatenated. - pub implicit_concatenated: bool, + pub value: FStringValue, } impl From for Expr { @@ -999,12 +989,155 @@ impl From for Expr { } } +/// The value representing an [`ExprFString`]. +#[derive(Clone, Debug, PartialEq)] +pub struct FStringValue { + inner: FStringValueInner, +} + +impl FStringValue { + /// Creates a new f-string with the given value. + pub fn single(value: FString) -> Self { + Self { + inner: FStringValueInner::Single(FStringPart::FString(value)), + } + } + + /// Creates a new f-string with the given values that represents an implicitly + /// concatenated f-string. + /// + /// # Panics + /// + /// Panics if `values` is less than 2. Use [`FStringValue::single`] instead. + pub fn concatenated(values: Vec) -> Self { + assert!(values.len() > 1); + Self { + inner: FStringValueInner::Concatenated(values), + } + } + + /// Returns `true` if the f-string is implicitly concatenated, `false` otherwise. + pub fn is_implicit_concatenated(&self) -> bool { + matches!(self.inner, FStringValueInner::Concatenated(_)) + } + + /// Returns an iterator over all the [`FStringPart`]s contained in this value. + pub fn parts(&self) -> impl Iterator { + match &self.inner { + FStringValueInner::Single(part) => Left(std::iter::once(part)), + FStringValueInner::Concatenated(parts) => Right(parts.iter()), + } + } + + /// Returns an iterator over all the [`FStringPart`]s contained in this value + /// that allows modification. + pub(crate) fn parts_mut(&mut self) -> impl Iterator { + match &mut self.inner { + FStringValueInner::Single(part) => Left(std::iter::once(part)), + FStringValueInner::Concatenated(parts) => Right(parts.iter_mut()), + } + } + + /// Returns an iterator over the [`StringLiteral`] parts contained in this value. + /// + /// Note that this doesn't nest into the f-string parts. For example, + /// + /// ```python + /// "foo" f"bar {x}" "baz" f"qux" + /// ``` + /// + /// Here, the string literal parts returned would be `"foo"` and `"baz"`. + pub fn literals(&self) -> impl Iterator { + self.parts().filter_map(|part| part.as_literal()) + } + + /// Returns an iterator over the [`FString`] parts contained in this value. + /// + /// Note that this doesn't nest into the f-string parts. For example, + /// + /// ```python + /// "foo" f"bar {x}" "baz" f"qux" + /// ``` + /// + /// Here, the f-string parts returned would be `f"bar {x}"` and `f"qux"`. + pub fn f_strings(&self) -> impl Iterator { + self.parts().filter_map(|part| part.as_f_string()) + } + + /// Returns an iterator over all the f-string elements contained in this value. + /// + /// An f-string element is what makes up an [`FString`] i.e., it is either a + /// string literal or an expression. In the following example, + /// + /// ```python + /// "foo" f"bar {x}" "baz" f"qux" + /// ``` + /// + /// The f-string elements returned would be string literal (`"bar "`), + /// expression (`x`) and string literal (`"qux"`). + pub fn elements(&self) -> impl Iterator { + self.f_strings().flat_map(|fstring| fstring.values.iter()) + } +} + +/// An internal representation of [`FStringValue`]. +#[derive(Clone, Debug, PartialEq)] +enum FStringValueInner { + /// A single f-string i.e., `f"foo"`. + /// + /// This is always going to be `FStringPart::FString` variant which is + /// maintained by the `FStringValue::single` constructor. + Single(FStringPart), + + /// An implicitly concatenated f-string i.e., `"foo" f"bar {x}"`. + Concatenated(Vec), +} + +/// An f-string part which is either a string literal or an f-string. +#[derive(Clone, Debug, PartialEq, is_macro::Is)] +pub enum FStringPart { + Literal(StringLiteral), + FString(FString), +} + +impl Ranged for FStringPart { + fn range(&self) -> TextRange { + match self { + FStringPart::Literal(string_literal) => string_literal.range(), + FStringPart::FString(f_string) => f_string.range(), + } + } +} + +/// An AST node that represents a single f-string which is part of an [`ExprFString`]. +#[derive(Clone, Debug, PartialEq)] +pub struct FString { + pub range: TextRange, + pub values: Vec, +} + +impl Ranged for FString { + fn range(&self) -> TextRange { + self.range + } +} + +impl From for Expr { + fn from(payload: FString) -> Self { + ExprFString { + range: payload.range, + value: FStringValue::single(payload), + } + .into() + } +} + +/// An AST node that represents either a single string literal or an implicitly +/// concatenated string literals. #[derive(Clone, Debug, Default, PartialEq)] pub struct ExprStringLiteral { pub range: TextRange, - pub value: String, - pub unicode: bool, - pub implicit_concatenated: bool, + pub value: StringLiteralValue, } impl From for Expr { @@ -1019,7 +1152,134 @@ impl Ranged for ExprStringLiteral { } } -impl Deref for ExprStringLiteral { +/// The value representing a [`ExprStringLiteral`]. +#[derive(Clone, Debug, Default, PartialEq)] +pub struct StringLiteralValue { + inner: StringLiteralValueInner, +} + +impl StringLiteralValue { + /// Creates a new single string literal with the given value. + pub fn single(string: StringLiteral) -> Self { + Self { + inner: StringLiteralValueInner::Single(string), + } + } + + /// Creates a new string literal with the given values that represents an + /// implicitly concatenated strings. + /// + /// # Panics + /// + /// Panics if `strings` is less than 2. Use [`StringLiteralValue::single`] + /// instead. + pub fn concatenated(strings: Vec) -> Self { + assert!(strings.len() > 1); + Self { + inner: StringLiteralValueInner::Concatenated(ConcatenatedStringLiteral { + strings, + value: OnceCell::new(), + }), + } + } + + /// Returns `true` if the string literal is implicitly concatenated. + pub const fn is_implicit_concatenated(&self) -> bool { + matches!(self.inner, StringLiteralValueInner::Concatenated(_)) + } + + /// Returns `true` if the string literal is a unicode string. + /// + /// For an implicitly concatenated string, it returns `true` only if the first + /// string literal is a unicode string. + pub fn is_unicode(&self) -> bool { + self.parts().next().map_or(false, |part| part.unicode) + } + + /// Returns an iterator over all the [`StringLiteral`] parts contained in this value. + pub fn parts(&self) -> impl Iterator { + match &self.inner { + StringLiteralValueInner::Single(value) => Left(std::iter::once(value)), + StringLiteralValueInner::Concatenated(value) => Right(value.strings.iter()), + } + } + + /// Returns an iterator over all the [`StringLiteral`] parts contained in this value + /// that allows modification. + pub(crate) fn parts_mut(&mut self) -> impl Iterator { + match &mut self.inner { + StringLiteralValueInner::Single(value) => Left(std::iter::once(value)), + StringLiteralValueInner::Concatenated(value) => Right(value.strings.iter_mut()), + } + } + + /// Returns the concatenated string value as a [`str`]. + pub fn as_str(&self) -> &str { + match &self.inner { + StringLiteralValueInner::Single(value) => value.as_str(), + StringLiteralValueInner::Concatenated(value) => value.as_str(), + } + } +} + +impl PartialEq for StringLiteralValue { + fn eq(&self, other: &str) -> bool { + self.as_str() == other + } +} + +impl PartialEq for StringLiteralValue { + fn eq(&self, other: &String) -> bool { + self.as_str() == other + } +} + +impl Deref for StringLiteralValue { + type Target = str; + + fn deref(&self) -> &Self::Target { + self.as_str() + } +} + +impl fmt::Display for StringLiteralValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +/// An internal representation of [`StringLiteralValue`]. +#[derive(Clone, Debug, PartialEq)] +enum StringLiteralValueInner { + /// A single string literal i.e., `"foo"`. + Single(StringLiteral), + + /// An implicitly concatenated string literals i.e., `"foo" "bar"`. + Concatenated(ConcatenatedStringLiteral), +} + +impl Default for StringLiteralValueInner { + fn default() -> Self { + Self::Single(StringLiteral::default()) + } +} + +/// An AST node that represents a single string literal which is part of an +/// [`ExprStringLiteral`]. +#[derive(Clone, Debug, Default, PartialEq)] +pub struct StringLiteral { + pub range: TextRange, + pub value: String, + pub unicode: bool, +} + +impl Ranged for StringLiteral { + fn range(&self) -> TextRange { + self.range + } +} + +impl Deref for StringLiteral { type Target = str; fn deref(&self) -> &Self::Target { @@ -1027,11 +1287,69 @@ impl Deref for ExprStringLiteral { } } +impl StringLiteral { + /// Extracts a string slice containing the entire `String`. + pub fn as_str(&self) -> &str { + self + } +} + +impl From for Expr { + fn from(payload: StringLiteral) -> Self { + ExprStringLiteral { + range: payload.range, + value: StringLiteralValue::single(payload), + } + .into() + } +} + +/// An internal representation of [`StringLiteral`] that represents an +/// implicitly concatenated string. +#[derive(Clone)] +struct ConcatenatedStringLiteral { + /// Each string literal that makes up the concatenated string. + strings: Vec, + /// The concatenated string value. + value: OnceCell, +} + +impl ConcatenatedStringLiteral { + /// Extracts a string slice containing the entire concatenated string. + fn as_str(&self) -> &str { + self.value + .get_or_init(|| self.strings.iter().map(StringLiteral::as_str).collect()) + } +} + +impl PartialEq for ConcatenatedStringLiteral { + fn eq(&self, other: &Self) -> bool { + if self.strings.len() != other.strings.len() { + return false; + } + // The `zip` here is safe because we have checked the length of both parts. + self.strings + .iter() + .zip(other.strings.iter()) + .all(|(s1, s2)| s1 == s2) + } +} + +impl Debug for ConcatenatedStringLiteral { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ConcatenatedStringLiteral") + .field("strings", &self.strings) + .field("value", &self.as_str()) + .finish() + } +} + +/// An AST node that represents either a single bytes literal or an implicitly +/// concatenated bytes literals. #[derive(Clone, Debug, Default, PartialEq)] pub struct ExprBytesLiteral { pub range: TextRange, - pub value: Vec, - pub implicit_concatenated: bool, + pub value: BytesLiteralValue, } impl From for Expr { @@ -1046,6 +1364,140 @@ impl Ranged for ExprBytesLiteral { } } +/// The value representing a [`ExprBytesLiteral`]. +#[derive(Clone, Debug, Default, PartialEq)] +pub struct BytesLiteralValue { + inner: BytesLiteralValueInner, +} + +impl BytesLiteralValue { + /// Creates a new single bytes literal with the given value. + pub fn single(value: BytesLiteral) -> Self { + Self { + inner: BytesLiteralValueInner::Single(value), + } + } + + /// Creates a new bytes literal with the given values that represents an + /// implicitly concatenated bytes. + /// + /// # Panics + /// + /// Panics if `values` is less than 2. Use [`BytesLiteralValue::single`] + /// instead. + pub fn concatenated(values: Vec) -> Self { + assert!(values.len() > 1); + Self { + inner: BytesLiteralValueInner::Concatenated(values), + } + } + + /// Returns `true` if the bytes literal is implicitly concatenated. + pub const fn is_implicit_concatenated(&self) -> bool { + matches!(self.inner, BytesLiteralValueInner::Concatenated(_)) + } + + /// Returns an iterator over all the [`BytesLiteral`] parts contained in this value. + pub fn parts(&self) -> impl Iterator { + match &self.inner { + BytesLiteralValueInner::Single(value) => Left(std::iter::once(value)), + BytesLiteralValueInner::Concatenated(values) => Right(values.iter()), + } + } + + /// Returns an iterator over all the [`BytesLiteral`] parts contained in this value + /// that allows modification. + pub(crate) fn parts_mut(&mut self) -> impl Iterator { + match &mut self.inner { + BytesLiteralValueInner::Single(value) => Left(std::iter::once(value)), + BytesLiteralValueInner::Concatenated(values) => Right(values.iter_mut()), + } + } + + /// Returns `true` if the concatenated bytes has a length of zero. + pub fn is_empty(&self) -> bool { + self.parts().all(|part| part.is_empty()) + } + + /// Returns the length of the concatenated bytes. + pub fn len(&self) -> usize { + self.parts().map(|part| part.len()).sum() + } + + /// Returns an iterator over the bytes of the concatenated bytes. + fn bytes(&self) -> impl Iterator + '_ { + self.parts() + .flat_map(|part| part.as_slice().iter().copied()) + } +} + +impl PartialEq<[u8]> for BytesLiteralValue { + fn eq(&self, other: &[u8]) -> bool { + if self.len() != other.len() { + return false; + } + // The `zip` here is safe because we have checked the length of both parts. + self.bytes() + .zip(other.iter().copied()) + .all(|(b1, b2)| b1 == b2) + } +} + +/// An internal representation of [`BytesLiteralValue`]. +#[derive(Clone, Debug, PartialEq)] +enum BytesLiteralValueInner { + /// A single bytes literal i.e., `b"foo"`. + Single(BytesLiteral), + + /// An implicitly concatenated bytes literals i.e., `b"foo" b"bar"`. + Concatenated(Vec), +} + +impl Default for BytesLiteralValueInner { + fn default() -> Self { + Self::Single(BytesLiteral::default()) + } +} + +/// An AST node that represents a single bytes literal which is part of an +/// [`ExprBytesLiteral`]. +#[derive(Clone, Debug, Default, PartialEq)] +pub struct BytesLiteral { + pub range: TextRange, + pub value: Vec, +} + +impl Ranged for BytesLiteral { + fn range(&self) -> TextRange { + self.range + } +} + +impl Deref for BytesLiteral { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.value.as_slice() + } +} + +impl BytesLiteral { + /// Extracts a byte slice containing the entire [`BytesLiteral`]. + pub fn as_slice(&self) -> &[u8] { + self + } +} + +impl From for Expr { + fn from(payload: BytesLiteral) -> Self { + ExprBytesLiteral { + range: payload.range, + value: BytesLiteralValue::single(payload), + } + .into() + } +} + #[derive(Clone, Debug, PartialEq)] pub struct ExprNumberLiteral { pub range: TextRange, @@ -3088,12 +3540,12 @@ impl Ranged for crate::Expr { Self::Call(node) => node.range(), Self::FormattedValue(node) => node.range(), Self::FString(node) => node.range(), - Expr::StringLiteral(node) => node.range(), - Expr::BytesLiteral(node) => node.range(), - Expr::NumberLiteral(node) => node.range(), - Expr::BooleanLiteral(node) => node.range(), - Expr::NoneLiteral(node) => node.range(), - Expr::EllipsisLiteral(node) => node.range(), + Self::StringLiteral(node) => node.range(), + Self::BytesLiteral(node) => node.range(), + Self::NumberLiteral(node) => node.range(), + Self::BooleanLiteral(node) => node.range(), + Self::NoneLiteral(node) => node.range(), + Self::EllipsisLiteral(node) => node.range(), Self::Attribute(node) => node.range(), Self::Subscript(node) => node.range(), Self::Starred(node) => node.range(), @@ -3101,7 +3553,7 @@ impl Ranged for crate::Expr { Self::List(node) => node.range(), Self::Tuple(node) => node.range(), Self::Slice(node) => node.range(), - Expr::IpyEscapeCommand(node) => node.range(), + Self::IpyEscapeCommand(node) => node.range(), } } } diff --git a/crates/ruff_python_ast/src/visitor.rs b/crates/ruff_python_ast/src/visitor.rs index f740044fb5ffc..8687b09c1019d 100644 --- a/crates/ruff_python_ast/src/visitor.rs +++ b/crates/ruff_python_ast/src/visitor.rs @@ -4,10 +4,10 @@ pub mod preorder; pub mod transformer; use crate::{ - self as ast, Alias, Arguments, BoolOp, CmpOp, Comprehension, Decorator, ElifElseClause, - ExceptHandler, Expr, ExprContext, Keyword, MatchCase, Operator, Parameter, Parameters, Pattern, - PatternArguments, PatternKeyword, Stmt, TypeParam, TypeParamTypeVar, TypeParams, UnaryOp, - WithItem, + self as ast, Alias, Arguments, BoolOp, BytesLiteral, CmpOp, Comprehension, Decorator, + ElifElseClause, ExceptHandler, Expr, ExprContext, FString, FStringPart, Keyword, MatchCase, + Operator, Parameter, Parameters, Pattern, PatternArguments, PatternKeyword, Stmt, + StringLiteral, TypeParam, TypeParamTypeVar, TypeParams, UnaryOp, WithItem, }; /// A trait for AST visitors. Visits all nodes in the AST recursively in evaluation-order. @@ -98,6 +98,15 @@ pub trait Visitor<'a> { fn visit_elif_else_clause(&mut self, elif_else_clause: &'a ElifElseClause) { walk_elif_else_clause(self, elif_else_clause); } + fn visit_f_string(&mut self, f_string: &'a FString) { + walk_f_string(self, f_string); + } + fn visit_string_literal(&mut self, string_literal: &'a StringLiteral) { + walk_string_literal(self, string_literal); + } + fn visit_bytes_literal(&mut self, bytes_literal: &'a BytesLiteral) { + walk_bytes_literal(self, bytes_literal); + } } pub fn walk_body<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, body: &'a [Stmt]) { @@ -475,14 +484,27 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) { visitor.visit_format_spec(expr); } } - Expr::FString(ast::ExprFString { values, .. }) => { - for expr in values { - visitor.visit_expr(expr); + Expr::FString(ast::ExprFString { value, .. }) => { + for part in value.parts() { + match part { + FStringPart::Literal(string_literal) => { + visitor.visit_string_literal(string_literal); + } + FStringPart::FString(f_string) => visitor.visit_f_string(f_string), + } } } - Expr::StringLiteral(_) - | Expr::BytesLiteral(_) - | Expr::NumberLiteral(_) + Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { + for string_literal in value.parts() { + visitor.visit_string_literal(string_literal); + } + } + Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => { + for bytes_literal in value.parts() { + visitor.visit_bytes_literal(bytes_literal); + } + } + Expr::NumberLiteral(_) | Expr::BooleanLiteral(_) | Expr::NoneLiteral(_) | Expr::EllipsisLiteral(_) => {} @@ -576,6 +598,12 @@ pub fn walk_except_handler<'a, V: Visitor<'a> + ?Sized>( } } +pub fn walk_f_string<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, f_string: &'a FString) { + for expr in &f_string.values { + visitor.visit_expr(expr); + } +} + pub fn walk_format_spec<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, format_spec: &'a Expr) { visitor.visit_expr(format_spec); } @@ -746,3 +774,17 @@ pub fn walk_cmp_op<'a, V: Visitor<'a> + ?Sized>(visitor: &V, cmp_op: &'a CmpOp) #[allow(unused_variables)] pub fn walk_alias<'a, V: Visitor<'a> + ?Sized>(visitor: &V, alias: &'a Alias) {} + +#[allow(unused_variables)] +pub fn walk_string_literal<'a, V: Visitor<'a> + ?Sized>( + visitor: &V, + string_literal: &'a StringLiteral, +) { +} + +#[allow(unused_variables)] +pub fn walk_bytes_literal<'a, V: Visitor<'a> + ?Sized>( + visitor: &V, + bytes_literal: &'a BytesLiteral, +) { +} diff --git a/crates/ruff_python_ast/src/visitor/preorder.rs b/crates/ruff_python_ast/src/visitor/preorder.rs index 8de18d1413ff6..5b2e3ad793ef5 100644 --- a/crates/ruff_python_ast/src/visitor/preorder.rs +++ b/crates/ruff_python_ast/src/visitor/preorder.rs @@ -1,7 +1,8 @@ use crate::{ - Alias, Arguments, BoolOp, CmpOp, Comprehension, Decorator, ElifElseClause, ExceptHandler, Expr, - Keyword, MatchCase, Mod, Operator, Parameter, ParameterWithDefault, Parameters, Pattern, - PatternArguments, PatternKeyword, Singleton, Stmt, TypeParam, TypeParams, UnaryOp, WithItem, + Alias, Arguments, BoolOp, BytesLiteral, CmpOp, Comprehension, Decorator, ElifElseClause, + ExceptHandler, Expr, FString, Keyword, MatchCase, Mod, Operator, Parameter, + ParameterWithDefault, Parameters, Pattern, PatternArguments, PatternKeyword, Singleton, Stmt, + StringLiteral, TypeParam, TypeParams, UnaryOp, WithItem, }; use crate::{AnyNodeRef, AstNode}; @@ -152,6 +153,21 @@ pub trait PreorderVisitor<'a> { fn visit_elif_else_clause(&mut self, elif_else_clause: &'a ElifElseClause) { walk_elif_else_clause(self, elif_else_clause); } + + #[inline] + fn visit_f_string(&mut self, f_string: &'a FString) { + walk_f_string(self, f_string); + } + + #[inline] + fn visit_string_literal(&mut self, string_literal: &'a StringLiteral) { + walk_string_literal(self, string_literal); + } + + #[inline] + fn visit_bytes_literal(&mut self, bytes_literal: &'a BytesLiteral) { + walk_bytes_literal(self, bytes_literal); + } } pub fn walk_module<'a, V>(visitor: &mut V, module: &'a Mod) @@ -530,6 +546,42 @@ where { } +#[inline] +pub fn walk_f_string<'a, V>(visitor: &mut V, f_string: &'a FString) +where + V: PreorderVisitor<'a> + ?Sized, +{ + let node = AnyNodeRef::from(f_string); + if visitor.enter_node(node).is_traverse() { + f_string.visit_preorder(visitor); + } + visitor.leave_node(node); +} + +#[inline] +pub fn walk_string_literal<'a, V>(visitor: &mut V, string_literal: &'a StringLiteral) +where + V: PreorderVisitor<'a> + ?Sized, +{ + let node = AnyNodeRef::from(string_literal); + if visitor.enter_node(node).is_traverse() { + string_literal.visit_preorder(visitor); + } + visitor.leave_node(node); +} + +#[inline] +pub fn walk_bytes_literal<'a, V>(visitor: &mut V, bytes_literal: &'a BytesLiteral) +where + V: PreorderVisitor<'a> + ?Sized, +{ + let node = AnyNodeRef::from(bytes_literal); + if visitor.enter_node(node).is_traverse() { + bytes_literal.visit_preorder(visitor); + } + visitor.leave_node(node); +} + #[inline] pub fn walk_alias<'a, V>(visitor: &mut V, alias: &'a Alias) where diff --git a/crates/ruff_python_ast/src/visitor/transformer.rs b/crates/ruff_python_ast/src/visitor/transformer.rs index b90ab0a1b61e9..7e0688092f592 100644 --- a/crates/ruff_python_ast/src/visitor/transformer.rs +++ b/crates/ruff_python_ast/src/visitor/transformer.rs @@ -1,8 +1,8 @@ use crate::{ - self as ast, Alias, Arguments, BoolOp, CmpOp, Comprehension, Decorator, ElifElseClause, - ExceptHandler, Expr, ExprContext, Keyword, MatchCase, Operator, Parameter, Parameters, Pattern, - PatternArguments, PatternKeyword, Stmt, TypeParam, TypeParamTypeVar, TypeParams, UnaryOp, - WithItem, + self as ast, Alias, Arguments, BoolOp, BytesLiteral, CmpOp, Comprehension, Decorator, + ElifElseClause, ExceptHandler, Expr, ExprContext, FString, Keyword, MatchCase, Operator, + Parameter, Parameters, Pattern, PatternArguments, PatternKeyword, Stmt, StringLiteral, + TypeParam, TypeParamTypeVar, TypeParams, UnaryOp, WithItem, }; /// A trait for transforming ASTs. Visits all nodes in the AST recursively in evaluation-order. @@ -85,6 +85,15 @@ pub trait Transformer { fn visit_elif_else_clause(&self, elif_else_clause: &mut ElifElseClause) { walk_elif_else_clause(self, elif_else_clause); } + fn visit_f_string(&self, f_string: &mut FString) { + walk_f_string(self, f_string); + } + fn visit_string_literal(&self, string_literal: &mut StringLiteral) { + walk_string_literal(self, string_literal); + } + fn visit_bytes_literal(&self, bytes_literal: &mut BytesLiteral) { + walk_bytes_literal(self, bytes_literal); + } } pub fn walk_body(visitor: &V, body: &mut [Stmt]) { @@ -462,14 +471,29 @@ pub fn walk_expr(visitor: &V, expr: &mut Expr) { visitor.visit_format_spec(expr); } } - Expr::FString(ast::ExprFString { values, .. }) => { - for expr in values { - visitor.visit_expr(expr); + Expr::FString(ast::ExprFString { value, .. }) => { + for f_string_part in value.parts_mut() { + match f_string_part { + ast::FStringPart::Literal(string_literal) => { + visitor.visit_string_literal(string_literal); + } + ast::FStringPart::FString(f_string) => { + visitor.visit_f_string(f_string); + } + } } } - Expr::StringLiteral(_) - | Expr::BytesLiteral(_) - | Expr::NumberLiteral(_) + Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { + for string_literal in value.parts_mut() { + visitor.visit_string_literal(string_literal); + } + } + Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => { + for bytes_literal in value.parts_mut() { + visitor.visit_bytes_literal(bytes_literal); + } + } + Expr::NumberLiteral(_) | Expr::BooleanLiteral(_) | Expr::NoneLiteral(_) | Expr::EllipsisLiteral(_) => {} @@ -560,6 +584,12 @@ pub fn walk_except_handler( } } +pub fn walk_f_string(visitor: &V, f_string: &mut FString) { + for expr in &mut f_string.values { + visitor.visit_expr(expr); + } +} + pub fn walk_format_spec(visitor: &V, format_spec: &mut Expr) { visitor.visit_expr(format_spec); } @@ -730,3 +760,13 @@ pub fn walk_cmp_op(visitor: &V, cmp_op: &mut CmpOp) {} #[allow(unused_variables)] pub fn walk_alias(visitor: &V, alias: &mut Alias) {} + +#[allow(unused_variables)] +pub fn walk_string_literal( + visitor: &V, + string_literal: &mut StringLiteral, +) { +} + +#[allow(unused_variables)] +pub fn walk_bytes_literal(visitor: &V, bytes_literal: &mut BytesLiteral) {} diff --git a/crates/ruff_python_codegen/src/generator.rs b/crates/ruff_python_codegen/src/generator.rs index 3c83bc26d9300..ac5abc2e8a6cc 100644 --- a/crates/ruff_python_codegen/src/generator.rs +++ b/crates/ruff_python_codegen/src/generator.rs @@ -1081,17 +1081,18 @@ impl<'a> Generator<'a> { *conversion, format_spec.as_deref(), ), - Expr::FString(ast::ExprFString { values, .. }) => { - self.unparse_f_string(values, false); + Expr::FString(ast::ExprFString { value, .. }) => { + self.unparse_f_string_value(value, false); } - Expr::StringLiteral(ast::ExprStringLiteral { value, unicode, .. }) => { - if *unicode { - self.p("u"); - } - self.p_str_repr(value); + Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { + self.unparse_string_literal_value(value); } Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => { - self.p_bytes_repr(value); + let mut first = true; + for bytes_literal in value.parts() { + self.p_delim(&mut first, " "); + self.p_bytes_repr(&bytes_literal.value); + } } Expr::NumberLiteral(ast::ExprNumberLiteral { value, .. }) => { static INF_STR: &str = "1e309"; @@ -1275,6 +1276,36 @@ impl<'a> Generator<'a> { } } + fn unparse_string_literal(&mut self, string_literal: &ast::StringLiteral) { + if string_literal.unicode { + self.p("u"); + } + self.p_str_repr(&string_literal.value); + } + + fn unparse_string_literal_value(&mut self, value: &ast::StringLiteralValue) { + let mut first = true; + for string_literal in value.parts() { + self.p_delim(&mut first, " "); + self.unparse_string_literal(string_literal); + } + } + + fn unparse_f_string_value(&mut self, value: &ast::FStringValue, is_spec: bool) { + let mut first = true; + for f_string_part in value.parts() { + self.p_delim(&mut first, " "); + match f_string_part { + ast::FStringPart::Literal(string_literal) => { + self.unparse_string_literal(string_literal); + } + ast::FStringPart::FString(f_string) => { + self.unparse_f_string(&f_string.values, is_spec); + } + } + } + } + fn unparse_f_string_body(&mut self, values: &[Expr], is_spec: bool) { for value in values { self.unparse_f_string_elem(value, is_spec); @@ -1325,10 +1356,10 @@ impl<'a> Generator<'a> { fn unparse_f_string_elem(&mut self, expr: &Expr, is_spec: bool) { match expr { Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { - self.unparse_f_string_literal(value); + self.unparse_f_string_literal(value.as_str()); } - Expr::FString(ast::ExprFString { values, .. }) => { - self.unparse_f_string(values, is_spec); + Expr::FString(ast::ExprFString { value, .. }) => { + self.unparse_f_string_value(value, is_spec); } Expr::FormattedValue(ast::ExprFormattedValue { value, @@ -1678,7 +1709,7 @@ class Foo: assert_eq!(round_trip(r"u'hello'"), r#"u"hello""#); assert_eq!(round_trip(r"r'hello'"), r#""hello""#); assert_eq!(round_trip(r"b'hello'"), r#"b"hello""#); - assert_eq!(round_trip(r#"("abc" "def" "ghi")"#), r#""abcdefghi""#); + assert_eq!(round_trip(r#"("abc" "def" "ghi")"#), r#""abc" "def" "ghi""#); assert_eq!(round_trip(r#""he\"llo""#), r#"'he"llo'"#); assert_eq!(round_trip(r#"f"abc{'def'}{1}""#), r#"f"abc{'def'}{1}""#); assert_eq!(round_trip(r#"f'abc{"def"}{1}'"#), r#"f"abc{'def'}{1}""#); @@ -1693,6 +1724,13 @@ class Foo: assert_round_trip!(r#"f"{a=!r:0.05f}""#); } + #[test] + fn implicit_string_concatenation() { + assert_round_trip!(r#""first" "second" "third""#); + assert_round_trip!(r#"b"first" b"second" b"third""#); + assert_round_trip!(r#""first" "second" f"third {var}""#); + } + #[test] fn indent() { assert_eq!( diff --git a/crates/ruff_python_formatter/src/comments/placement.rs b/crates/ruff_python_formatter/src/comments/placement.rs index 5fe12bd190322..4b667fd23629f 100644 --- a/crates/ruff_python_formatter/src/comments/placement.rs +++ b/crates/ruff_python_formatter/src/comments/placement.rs @@ -283,13 +283,13 @@ fn handle_enclosed_comment<'a>( AnyNodeRef::StmtWith(with_) => handle_with_comment(comment, with_), AnyNodeRef::ExprCall(_) => handle_call_comment(comment), AnyNodeRef::ExprStringLiteral(_) => { - if let Some(AnyNodeRef::ExprFString(fstring)) = comment.enclosing_parent() { + if let Some(AnyNodeRef::FString(fstring)) = comment.enclosing_parent() { CommentPlacement::dangling(fstring, comment) } else { CommentPlacement::Default(comment) } } - AnyNodeRef::ExprFString(fstring) => CommentPlacement::dangling(fstring, comment), + AnyNodeRef::FString(fstring) => CommentPlacement::dangling(fstring, comment), AnyNodeRef::ExprList(_) | AnyNodeRef::ExprSet(_) | AnyNodeRef::ExprListComp(_) diff --git a/crates/ruff_python_formatter/src/expression/expr_bin_op.rs b/crates/ruff_python_formatter/src/expression/expr_bin_op.rs index 4a9361881d7e5..337dd825f2f4f 100644 --- a/crates/ruff_python_formatter/src/expression/expr_bin_op.rs +++ b/crates/ruff_python_formatter/src/expression/expr_bin_op.rs @@ -35,13 +35,13 @@ impl NeedsParentheses for ExprBinOp { ) -> OptionalParentheses { if parent.is_expr_await() { OptionalParentheses::Always - } else if self.left.is_literal_expr() { + } else if let Some(literal_expr) = self.left.as_literal_expr() { // Multiline strings are guaranteed to never fit, avoid adding unnecessary parentheses - if !self.left.is_implicit_concatenated_string() - && is_multiline_string(self.left.as_ref().into(), context.source()) + if !literal_expr.is_implicit_concatenated() + && is_multiline_string(literal_expr.into(), context.source()) && has_parentheses(&self.right, context).is_some() && !context.comments().has_dangling(self) - && !context.comments().has(self.left.as_ref()) + && !context.comments().has(literal_expr) && !context.comments().has(self.right.as_ref()) { OptionalParentheses::Never diff --git a/crates/ruff_python_formatter/src/expression/expr_bytes_literal.rs b/crates/ruff_python_formatter/src/expression/expr_bytes_literal.rs index 968487a07cb4a..2fc0cd474ce77 100644 --- a/crates/ruff_python_formatter/src/expression/expr_bytes_literal.rs +++ b/crates/ruff_python_formatter/src/expression/expr_bytes_literal.rs @@ -31,7 +31,7 @@ impl NeedsParentheses for ExprBytesLiteral { _parent: AnyNodeRef, context: &PyFormatContext, ) -> OptionalParentheses { - if self.implicit_concatenated { + if self.value.is_implicit_concatenated() { OptionalParentheses::Multiline } else if is_multiline_string(self.into(), context.source()) { OptionalParentheses::Never diff --git a/crates/ruff_python_formatter/src/expression/expr_compare.rs b/crates/ruff_python_formatter/src/expression/expr_compare.rs index f48bd66eccd9c..e9a338075e318 100644 --- a/crates/ruff_python_formatter/src/expression/expr_compare.rs +++ b/crates/ruff_python_formatter/src/expression/expr_compare.rs @@ -37,11 +37,11 @@ impl NeedsParentheses for ExprCompare { ) -> OptionalParentheses { if parent.is_expr_await() { OptionalParentheses::Always - } else if self.left.is_literal_expr() { + } else if let Some(literal_expr) = self.left.as_literal_expr() { // Multiline strings are guaranteed to never fit, avoid adding unnecessary parentheses - if !self.left.is_implicit_concatenated_string() - && is_multiline_string(self.left.as_ref().into(), context.source()) - && !context.comments().has(self.left.as_ref()) + if !literal_expr.is_implicit_concatenated() + && is_multiline_string(literal_expr.into(), context.source()) + && !context.comments().has(literal_expr) && self.comparators.first().is_some_and(|right| { has_parentheses(right, context).is_some() && !context.comments().has(right) }) diff --git a/crates/ruff_python_formatter/src/expression/expr_f_string.rs b/crates/ruff_python_formatter/src/expression/expr_f_string.rs index 51beb4dbb8f4a..12e112ecc1638 100644 --- a/crates/ruff_python_formatter/src/expression/expr_f_string.rs +++ b/crates/ruff_python_formatter/src/expression/expr_f_string.rs @@ -34,7 +34,7 @@ impl NeedsParentheses for ExprFString { _parent: AnyNodeRef, context: &PyFormatContext, ) -> OptionalParentheses { - if self.implicit_concatenated { + if self.value.is_implicit_concatenated() { OptionalParentheses::Multiline } else if memchr2(b'\n', b'\r', context.source()[self.range].as_bytes()).is_none() { OptionalParentheses::BestFit diff --git a/crates/ruff_python_formatter/src/expression/expr_string_literal.rs b/crates/ruff_python_formatter/src/expression/expr_string_literal.rs index e6ce374c292fb..199fb740ef712 100644 --- a/crates/ruff_python_formatter/src/expression/expr_string_literal.rs +++ b/crates/ruff_python_formatter/src/expression/expr_string_literal.rs @@ -46,7 +46,7 @@ impl NeedsParentheses for ExprStringLiteral { _parent: AnyNodeRef, context: &PyFormatContext, ) -> OptionalParentheses { - if self.implicit_concatenated { + if self.value.is_implicit_concatenated() { OptionalParentheses::Multiline } else if is_multiline_string(self.into(), context.source()) { OptionalParentheses::Never diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index 019546e596edd..86fae5137a448 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -804,18 +804,17 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> { return; } - Expr::StringLiteral(ast::ExprStringLiteral { - implicit_concatenated: true, - .. - }) - | Expr::BytesLiteral(ast::ExprBytesLiteral { - implicit_concatenated: true, - .. - }) - | Expr::FString(ast::ExprFString { - implicit_concatenated: true, - .. - }) => { + Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) + if value.is_implicit_concatenated() => + { + self.update_max_precedence(OperatorPrecedence::String); + } + Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) + if value.is_implicit_concatenated() => + { + self.update_max_precedence(OperatorPrecedence::String); + } + Expr::FString(ast::ExprFString { value, .. }) if value.is_implicit_concatenated() => { self.update_max_precedence(OperatorPrecedence::String); } diff --git a/crates/ruff_python_formatter/src/expression/string.rs b/crates/ruff_python_formatter/src/expression/string.rs index 0fef24af91cf4..cb534d49a4517 100644 --- a/crates/ruff_python_formatter/src/expression/string.rs +++ b/crates/ruff_python_formatter/src/expression/string.rs @@ -2,13 +2,11 @@ use std::borrow::Cow; use bitflags::bitflags; -use ruff_formatter::{format_args, write, FormatError}; +use ruff_formatter::{format_args, write}; use ruff_python_ast::AnyNodeRef; use ruff_python_ast::{ self as ast, ExprBytesLiteral, ExprFString, ExprStringLiteral, ExpressionRef, }; -use ruff_python_parser::lexer::{lex_starts_at, LexicalError, LexicalErrorType}; -use ruff_python_parser::{Mode, Tok}; use ruff_source_file::Locator; use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; @@ -52,7 +50,7 @@ impl<'a> AnyString<'a> { .trim_start_matches(|c| c != '"' && c != '\''); let triple_quoted = unprefixed.starts_with(r#"""""#) || unprefixed.starts_with(r"'''"); - if f_string.values.iter().any(|value| match value { + if f_string.value.elements().any(|value| match value { Expr::FormattedValue(ast::ExprFormattedValue { range, .. }) => { let string_content = locator.slice(*range); if triple_quoted { @@ -74,18 +72,29 @@ impl<'a> AnyString<'a> { /// Returns `true` if the string is implicitly concatenated. pub(super) fn is_implicit_concatenated(&self) -> bool { match self { - Self::String(ExprStringLiteral { - implicit_concatenated, - .. - }) => *implicit_concatenated, - Self::Bytes(ExprBytesLiteral { - implicit_concatenated, - .. - }) => *implicit_concatenated, - Self::FString(ExprFString { - implicit_concatenated, - .. - }) => *implicit_concatenated, + Self::String(ExprStringLiteral { value, .. }) => value.is_implicit_concatenated(), + Self::Bytes(ExprBytesLiteral { value, .. }) => value.is_implicit_concatenated(), + Self::FString(ExprFString { value, .. }) => value.is_implicit_concatenated(), + } + } + + fn parts(&self) -> Vec> { + match self { + Self::String(ExprStringLiteral { value, .. }) => { + value.parts().map(AnyStringPart::String).collect() + } + Self::Bytes(ExprBytesLiteral { value, .. }) => { + value.parts().map(AnyStringPart::Bytes).collect() + } + Self::FString(ExprFString { value, .. }) => value + .parts() + .map(|f_string_part| match f_string_part { + ast::FStringPart::Literal(string_literal) => { + AnyStringPart::String(string_literal) + } + ast::FStringPart::FString(f_string) => AnyStringPart::FString(f_string), + }) + .collect(), } } } @@ -120,6 +129,33 @@ impl<'a> From<&AnyString<'a>> for ExpressionRef<'a> { } } +#[derive(Clone, Debug)] +enum AnyStringPart<'a> { + String(&'a ast::StringLiteral), + Bytes(&'a ast::BytesLiteral), + FString(&'a ast::FString), +} + +impl<'a> From<&AnyStringPart<'a>> for AnyNodeRef<'a> { + fn from(value: &AnyStringPart<'a>) -> Self { + match value { + AnyStringPart::String(part) => AnyNodeRef::StringLiteral(part), + AnyStringPart::Bytes(part) => AnyNodeRef::BytesLiteral(part), + AnyStringPart::FString(part) => AnyNodeRef::FString(part), + } + } +} + +impl Ranged for AnyStringPart<'_> { + fn range(&self) -> TextRange { + match self { + Self::String(part) => part.range(), + Self::Bytes(part) => part.range(), + Self::FString(part) => part.range(), + } + } +} + pub(super) struct FormatString<'a> { string: &'a AnyString<'a>, layout: StringLayout, @@ -185,7 +221,7 @@ impl<'a> Format> for FormatString<'a> { // comments. if let AnyString::FString(fstring) = self.string { let comments = f.context().comments(); - fstring.values.iter().for_each(|value| { + fstring.value.elements().for_each(|value| { comments.mark_verbatim_node_comments_formatted(value.into()); }); } @@ -193,60 +229,6 @@ impl<'a> Format> for FormatString<'a> { } } -/// A builder for the f-string range. -/// -/// For now, this is limited to the outermost f-string and doesn't support -/// nested f-strings. -#[derive(Debug, Default)] -struct FStringRangeBuilder { - start_location: TextSize, - end_location: TextSize, - nesting: u32, -} - -impl FStringRangeBuilder { - fn visit_token(&mut self, token: &Tok, range: TextRange) { - match token { - Tok::FStringStart => { - if self.nesting == 0 { - self.start_location = range.start(); - } - self.nesting += 1; - } - Tok::FStringEnd => { - // We can assume that this will never overflow because we know - // that the program once parsed to a valid AST which means that - // the start and end tokens for f-strings are balanced. - self.nesting -= 1; - if self.nesting == 0 { - self.end_location = range.end(); - } - } - _ => {} - } - } - - /// Returns `true` if the lexer is currently inside of a f-string. - /// - /// It'll return `false` once the `FStringEnd` token for the outermost - /// f-string is visited. - const fn in_fstring(&self) -> bool { - self.nesting > 0 - } - - /// Returns the complete range of the previously visited f-string. - /// - /// This method should only be called once the lexer is outside of any - /// f-string otherwise it might return an invalid range. - /// - /// It doesn't consume the builder because there can be multiple f-strings - /// throughout the source code. - fn finish(&self) -> TextRange { - debug_assert!(!self.in_fstring()); - TextRange::new(self.start_location, self.end_location) - } -} - struct FormatStringContinuation<'a> { string: &'a AnyString<'a>, } @@ -262,129 +244,24 @@ impl Format> for FormatStringContinuation<'_> { let comments = f.context().comments().clone(); let locator = f.context().locator(); let quote_style = f.options().quote_style(); - let mut dangling_comments = comments.dangling(self.string); - - let string_range = self.string.range(); - let string_content = locator.slice(string_range); - - // The AST parses implicit concatenation as a single string. - // Call into the lexer to extract the individual chunks and format each string on its own. - // This code does not yet implement the automatic joining of strings that fit on the same line - // because this is a black preview style. - let lexer = lex_starts_at(string_content, Mode::Expression, string_range.start()); - - // The lexer emits multiple tokens for a single f-string literal. Each token - // will have it's own range but we require the complete range of the f-string. - let mut fstring_range_builder = FStringRangeBuilder::default(); let mut joiner = f.join_with(in_parentheses_only_soft_line_break_or_space()); - for token in lexer { - let (token, token_range) = match token { - Ok(spanned) => spanned, - Err(LexicalError { - error: LexicalErrorType::IndentationError, - .. - }) => { - // This can happen if the string continuation appears anywhere inside of a parenthesized expression - // because the lexer doesn't know about the parentheses. For example, the following snipped triggers an Indentation error - // ```python - // { - // "key": ( - // [], - // 'a' - // 'b' - // 'c' - // ) - // } - // ``` - // Ignoring the error here is *safe* because we know that the program once parsed to a valid AST. - continue; - } - Err(_) => { - return Err(FormatError::syntax_error( - "Unexpected lexer error in string formatting", - )); - } - }; - - fstring_range_builder.visit_token(&token, token_range); - - // We need to ignore all the tokens within the f-string as there can - // be `String` tokens inside it as well. For example, - // - // ```python - // f"foo {'bar'} foo" - // # ^^^^^ - // # Ignore any logic for this `String` token - // ``` - // - // Here, we're interested in the complete f-string, not the individual - // tokens inside it. - if fstring_range_builder.in_fstring() { - continue; - } - - match token { - Tok::String { .. } | Tok::FStringEnd => { - let token_range = if token.is_f_string_end() { - fstring_range_builder.finish() - } else { - token_range - }; - - // ```python - // ( - // "a" - // # leading - // "the comment above" - // ) - // ``` - let leading_comments_end = dangling_comments - .partition_point(|comment| comment.start() <= token_range.start()); - - let (leading_part_comments, rest) = - dangling_comments.split_at(leading_comments_end); - - // ```python - // ( - // "a" # trailing comment - // "the comment above" - // ) - // ``` - let trailing_comments_end = rest.partition_point(|comment| { - comment.line_position().is_end_of_line() - && !locator.contains_line_break(TextRange::new( - token_range.end(), - comment.start(), - )) - }); - - let (trailing_part_comments, rest) = rest.split_at(trailing_comments_end); - let part = StringPart::from_source(token_range, &locator); - let normalized = - part.normalize(self.string.quoting(&locator), &locator, quote_style); - - joiner.entry(&format_args![ - line_suffix_boundary(), - leading_comments(leading_part_comments), - normalized, - trailing_comments(trailing_part_comments) - ]); - - dangling_comments = rest; - } - Tok::Comment(_) - | Tok::NonLogicalNewline - | Tok::Newline - | Tok::Indent - | Tok::Dedent => continue, - token => unreachable!("Unexpected token {token:?}"), - } + for part in self.string.parts() { + let normalized = StringPart::from_source(part.range(), &locator).normalize( + self.string.quoting(&locator), + &locator, + quote_style, + ); + + joiner.entry(&format_args![ + line_suffix_boundary(), + leading_comments(comments.leading(&part)), + normalized, + trailing_comments(comments.trailing(&part)) + ]); } - debug_assert!(dangling_comments.is_empty()); - joiner.finish() } } diff --git a/crates/ruff_python_formatter/src/statement/suite.rs b/crates/ruff_python_formatter/src/statement/suite.rs index 65ed7faec11d5..d8001cebe3c43 100644 --- a/crates/ruff_python_formatter/src/statement/suite.rs +++ b/crates/ruff_python_formatter/src/statement/suite.rs @@ -569,10 +569,14 @@ impl<'a> DocstringStmt<'a> { }; match value.as_ref() { - Expr::StringLiteral(value) if !value.implicit_concatenated => Some(DocstringStmt { - docstring: stmt, - suite_kind, - }), + Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) + if !value.is_implicit_concatenated() => + { + Some(DocstringStmt { + docstring: stmt, + suite_kind, + }) + } _ => None, } } diff --git a/crates/ruff_python_formatter/tests/normalizer.rs b/crates/ruff_python_formatter/tests/normalizer.rs index 68c15349dd173..991c4206fb9c2 100644 --- a/crates/ruff_python_formatter/tests/normalizer.rs +++ b/crates/ruff_python_formatter/tests/normalizer.rs @@ -51,20 +51,16 @@ impl Transformer for Normalizer { transformer::walk_stmt(self, stmt); } - fn visit_expr(&self, expr: &mut Expr) { - if let Expr::StringLiteral(string_literal) = expr { - // Normalize a string by (1) stripping any leading and trailing space from each - // line, and (2) removing any blank lines from the start and end of the string. - string_literal.value = string_literal - .value - .lines() - .map(str::trim) - .collect::>() - .join("\n") - .trim() - .to_owned(); - } - - transformer::walk_expr(self, expr); + fn visit_string_literal(&self, string_literal: &mut ast::StringLiteral) { + // Normalize a string by (1) stripping any leading and trailing space from each + // line, and (2) removing any blank lines from the start and end of the string. + string_literal.value = string_literal + .value + .lines() + .map(str::trim) + .collect::>() + .join("\n") + .trim() + .to_owned(); } } diff --git a/crates/ruff_python_parser/src/python.lalrpop b/crates/ruff_python_parser/src/python.lalrpop index 9c73f648bfd61..20a924fb0ffd6 100644 --- a/crates/ruff_python_parser/src/python.lalrpop +++ b/crates/ruff_python_parser/src/python.lalrpop @@ -11,7 +11,7 @@ use crate::{ lexer::{LexicalError, LexicalErrorType}, function::{ArgumentList, parse_arguments, validate_pos_params, validate_arguments}, context::set_context, - string::{StringType, concatenate_strings, parse_fstring_middle, parse_string_literal}, + string::{StringType, concatenated_strings, parse_fstring_middle, parse_string_literal}, token::{self, StringKind}, invalid, }; @@ -491,7 +491,7 @@ MatchStatement: ast::Stmt = { } ) }, - "match" > ","? ":" "\n" Indent Dedent => { + "match" > ","? ":" "\n" Indent Dedent => { let end_location = cases .last() .unwrap() @@ -542,7 +542,7 @@ Patterns: ast::Pattern = { range: (location..end_location).into() }, ), - > ","? => { + > ","? => { ast::Pattern::MatchSequence( ast::PatternMatchSequence { patterns, @@ -579,7 +579,7 @@ AsPattern: ast::Pattern = { OrPattern: ast::Pattern = { => pattern, - > => { + > => { ast::Pattern::MatchOr( ast::PatternMatchOr { patterns, range: (location..end_location).into() } ) @@ -677,8 +677,12 @@ LiteralPattern: ast::Pattern = { value: Box::new(value.into()), range: (location..end_location).into() }.into(), - =>? Ok(ast::PatternMatchValue { - value: Box::new(concatenate_strings(strings, (location..end_location).into())?), + => ast::PatternMatchValue { + value: Box::new(string.into()), + range: (location..end_location).into() + }.into(), + > =>? Ok(ast::PatternMatchValue { + value: Box::new(concatenated_strings(strings, (location..end_location).into())?), range: (location..end_location).into() }.into()), } @@ -721,6 +725,7 @@ ValuePattern: ast::Pattern = { MappingKey: ast::Expr = { MatchNameOrAttr, + String, => e.into(), => e.into(), "None" => ast::ExprNoneLiteral { @@ -734,7 +739,6 @@ MappingKey: ast::Expr = { value: false, range: (location..end_location).into() }.into(), - =>? Ok(concatenate_strings(strings, (location..end_location).into())?), } MatchMappingEntry: (ast::Expr, ast::Pattern) = { @@ -1561,7 +1565,7 @@ SubscriptList: ast::ParenthesizedExpr = { range: (location..end_location).into(), }.into() }, - > ","? => { + > ","? => { let elts = elts.into_iter().map(ast::Expr::from).collect(); ast::ExprTuple { elts, @@ -1587,23 +1591,29 @@ SliceOp: Option = { ":" ?> => e, } +String: ast::Expr = { + => string.into(), + > =>? { + Ok(concatenated_strings(strings, (location..end_location).into())?) + } +}; + StringLiteralOrFString: StringType = { StringLiteral, FStringExpr, }; StringLiteral: StringType = { - =>? { + =>? { let (source, kind, triple_quoted) = string; - Ok(parse_string_literal(&source, kind, triple_quoted, start_location)?) + Ok(parse_string_literal(&source, kind, triple_quoted, (location..end_location).into())?) } }; FStringExpr: StringType = { FStringStart FStringEnd => { - StringType::FString(ast::ExprFString { + StringType::FString(ast::FString { values, - implicit_concatenated: false, range: (location..end_location).into() }) } @@ -1611,9 +1621,9 @@ FStringExpr: StringType = { FStringMiddlePattern: ast::Expr = { FStringReplacementField, - =>? { + =>? { let (source, is_raw) = fstring_middle; - Ok(parse_fstring_middle(&source, is_raw, start_location)?) + Ok(parse_fstring_middle(&source, is_raw, (location..end_location).into())?) } }; @@ -1661,9 +1671,8 @@ FStringFormatSpecSuffix: ast::Expr = { FStringFormatSpec: ast::Expr = { => { - ast::ExprFString { + ast::FString { values, - implicit_concatenated: false, range: (location..end_location).into() }.into() }, @@ -1685,7 +1694,7 @@ FStringConversion: (TextSize, ast::ConversionFlag) = { }; Atom: ast::ParenthesizedExpr = { - =>? Ok(concatenate_strings(strings, (location..end_location).into())?.into()), + => expr.into(), => ast::ExprNumberLiteral { value, range: (location..end_location).into(), @@ -1926,9 +1935,18 @@ OneOrMore: Vec = { }; /// Two or more items that are separated by `Sep` -TwoOrMore: Vec = { +TwoOrMoreSep: Vec = { Sep => vec![e1, e2], - > Sep => { + > Sep => { + v.push(e); + v + } +}; + +/// Two or more items that are contiguous. +TwoOrMore: Vec = { + => vec![e1, e2], + > => { v.push(e); v } diff --git a/crates/ruff_python_parser/src/python.rs b/crates/ruff_python_parser/src/python.rs index bfbd1475dd947..89968c167273c 100644 --- a/crates/ruff_python_parser/src/python.rs +++ b/crates/ruff_python_parser/src/python.rs @@ -1,5 +1,5 @@ // auto-generated: "lalrpop 0.20.0" -// sha3: b8ac4a859b69d580e50733d39c96a3fe018f568e71e532ebb3153a19902e64e5 +// sha3: e78a653b50980f07fcb78bfa43c9f023870e26514f59acdec0bec5bf84c2a133 use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; use ruff_python_ast::{self as ast, Int, IpyEscapeKind}; use crate::{ @@ -8,7 +8,7 @@ use crate::{ lexer::{LexicalError, LexicalErrorType}, function::{ArgumentList, parse_arguments, validate_pos_params, validate_arguments}, context::set_context, - string::{StringType, concatenate_strings, parse_fstring_middle, parse_string_literal}, + string::{StringType, concatenated_strings, parse_fstring_middle, parse_string_literal}, token::{self, StringKind}, invalid, }; @@ -32,7 +32,7 @@ mod __parse__Top { lexer::{LexicalError, LexicalErrorType}, function::{ArgumentList, parse_arguments, validate_pos_params, validate_arguments}, context::set_context, - string::{StringType, concatenate_strings, parse_fstring_middle, parse_string_literal}, + string::{StringType, concatenated_strings, parse_fstring_middle, parse_string_literal}, token::{self, StringKind}, invalid, }; @@ -142,8 +142,8 @@ mod __parse__Top { Variant92(Option), Variant93(core::option::Option>), Variant94(Vec), - Variant95(alloc::vec::Vec), - Variant96(ast::Mod), + Variant95(ast::Mod), + Variant96(Vec), Variant97(ast::TypeParam), Variant98(ast::TypeParams), Variant99(core::option::Option), @@ -154,437 +154,437 @@ mod __parse__Top { // State 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, // State 1 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 2 - -768, 0, 0, 0, 0, 0, 0, -768, 0, -768, 0, 0, 0, -768, 0, 0, -768, 0, 0, 0, -768, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -768, 0, -768, -768, -768, -768, 0, 0, 0, 0, 0, -768, -768, -768, -768, 0, -768, -768, -768, -768, 0, 0, 0, 0, -768, -768, -768, -768, -768, 0, 0, -768, -768, -768, -768, 0, -768, -768, -768, -768, -768, -768, -768, -768, -768, 0, 0, 0, -768, 0, 0, -768, 0, 0, 0, -768, -768, 0, -768, -768, -768, -768, + -769, 0, 0, 0, 0, 0, 0, -769, 0, -769, 0, 0, 0, -769, 0, 0, -769, 0, 0, 0, -769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -769, 0, -769, -769, -769, -769, 0, 0, 0, 0, 0, -769, -769, -769, -769, 0, -769, -769, -769, -769, 0, 0, 0, 0, -769, -769, -769, -769, -769, 0, 0, -769, -769, -769, -769, 0, -769, -769, -769, -769, -769, -769, -769, -769, -769, 0, 0, 0, -769, 0, 0, -769, 0, 0, 0, -769, -769, 0, -769, -769, -769, -769, // State 3 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 4 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 5 - -790, -790, -790, 0, -790, -790, -790, 0, -790, 0, 0, -790, -790, 440, -790, -790, 441, -790, 0, 0, 0, 0, 0, -790, -790, -790, 0, -790, -790, -790, -790, -790, -790, -790, -790, -790, -790, -790, -790, 0, -790, 0, 0, 0, 0, -790, -790, -790, -790, -790, 0, -790, 0, 0, 0, 0, 0, 0, 0, 0, -790, 0, 0, -790, -790, 0, -790, 0, -790, -790, 0, 0, 0, -790, -790, 0, 0, 0, 0, 0, 0, 0, 0, 0, -790, -790, -790, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -791, -791, -791, 0, -791, -791, -791, 0, -791, 0, 0, -791, -791, 440, -791, -791, 441, -791, 0, 0, 0, 0, 0, -791, -791, -791, 0, -791, -791, -791, -791, -791, -791, -791, -791, -791, -791, -791, -791, 0, -791, 0, 0, 0, 0, -791, -791, -791, -791, -791, 0, -791, 0, 0, 0, 0, 0, 0, 0, 0, -791, 0, 0, -791, -791, 0, -791, 0, -791, -791, 0, 0, 0, -791, -791, 0, 0, 0, 0, 0, 0, 0, 0, 0, -791, -791, -791, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 6 - -248, -248, -248, -248, -248, -248, -248, 25, -248, -248, -248, -248, -248, -248, -248, -248, -248, -248, 0, 26, 0, -248, -248, -248, -248, -248, 0, -248, -248, -248, -248, -248, -248, -248, -248, -248, -248, -248, -248, -248, -248, 0, 0, 0, 27, -248, -248, -248, -248, -248, 0, -248, 0, 0, 0, 0, 0, 0, 0, 0, -248, 0, 0, -248, -248, 0, -248, 0, -248, -248, 0, 0, 0, -248, -248, 0, 0, 0, 0, 0, 0, 0, 0, 0, -248, -248, -248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -248, -248, -248, -248, -248, -248, -248, 26, -248, -248, -248, -248, -248, -248, -248, -248, -248, -248, 0, 27, 0, -248, -248, -248, -248, -248, 0, -248, -248, -248, -248, -248, -248, -248, -248, -248, -248, -248, -248, -248, -248, 0, 0, 0, 28, -248, -248, -248, -248, -248, 0, -248, 0, 0, 0, 0, 0, 0, 0, 0, -248, 0, 0, -248, -248, 0, -248, 0, -248, -248, 0, 0, 0, -248, -248, 0, 0, 0, 0, 0, 0, 0, 0, 0, -248, -248, -248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 7 - -304, -304, 443, 0, -304, 0, -304, 0, -304, 0, 0, -304, -304, 0, -304, -304, 0, -304, 0, 0, 0, 0, 0, -304, -304, -304, 0, -304, 444, 0, -304, 445, -304, 446, 447, 448, 0, -304, 0, 0, -304, 0, 0, 0, 0, -304, 0, -304, -304, -304, 0, -304, 0, 0, 0, 0, 0, 0, 0, 0, -304, 0, 0, -304, -304, 0, -304, 0, 449, 450, 0, 0, 0, 451, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, -304, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -304, -304, 443, 0, -304, 0, -304, 0, -304, 0, 0, -304, -304, 0, -304, -304, 0, -304, 0, 0, 0, 0, 0, -304, -304, -304, 0, -304, 444, 0, -304, 445, -304, 446, 447, 448, 0, -304, 0, 0, -304, 0, 0, 0, 0, -304, 0, -304, -304, -304, 0, -304, 0, 0, 0, 0, 0, 0, 0, 0, -304, 0, 0, -304, -304, 0, -304, 0, 449, 450, 0, 0, 0, 451, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, -304, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 8 453, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 9 -155, -155, -155, 0, -155, -155, -155, 0, -155, 0, 0, -155, -155, 0, -155, -155, 0, -155, 0, 0, 0, 0, 0, -155, -155, -155, 0, -155, -155, 455, -155, -155, -155, -155, -155, -155, 456, -155, -155, 0, -155, 0, 0, 0, 0, -155, -155, -155, -155, -155, 0, -155, 0, 0, 0, 0, 0, 0, 0, 0, -155, 0, 0, -155, -155, 0, -155, 0, -155, -155, 0, 0, 0, -155, -155, 0, 0, 0, 0, 0, 0, 0, 0, 0, -155, -155, -155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 10 - -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, 0, -183, 0, -183, -183, -183, -183, -183, 0, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, 0, 0, 0, -183, -183, -183, -183, -183, -183, 0, -183, 0, 0, 0, 0, 0, 0, 0, 0, -183, 0, 0, -183, -183, 0, -183, 0, -183, -183, 0, 0, 0, -183, -183, 0, 0, 0, 0, 0, 0, 0, 0, 0, -183, -183, -183, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 436, + -836, -836, -836, -836, -836, -836, -836, -836, -836, -836, -836, -836, -836, -836, -836, -836, -836, -836, 0, -836, 0, -836, -836, -836, -836, -836, 0, -836, -836, -836, -836, -836, -836, -836, -836, -836, -836, -836, -836, -836, -836, 0, 0, 0, -836, -836, -836, -836, -836, -836, 0, -836, 0, 0, 0, 0, 0, 0, 0, 0, -836, 0, 0, -836, -836, 0, -836, 0, -836, -836, 0, 0, 0, -836, -836, 0, 0, 0, 0, 0, 0, 0, 0, 0, -836, -836, -836, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 436, // State 11 -169, -169, -169, 458, -169, -169, -169, 0, -169, 459, 0, -169, -169, -169, -169, -169, -169, -169, 0, 0, 0, 460, 461, -169, -169, -169, 0, -169, -169, -169, -169, -169, -169, -169, -169, -169, -169, -169, -169, 462, -169, 0, 0, 0, 0, -169, -169, -169, -169, -169, 0, -169, 0, 0, 0, 0, 0, 0, 0, 0, -169, 0, 0, -169, -169, 0, -169, 0, -169, -169, 0, 0, 0, -169, -169, 0, 0, 0, 0, 0, 0, 0, 0, 0, -169, -169, -169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 12 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + -837, -837, -837, -837, -837, -837, -837, -837, -837, -837, -837, -837, -837, -837, -837, -837, -837, -837, 0, -837, 0, -837, -837, -837, -837, -837, 0, -837, -837, -837, -837, -837, -837, -837, -837, -837, -837, -837, -837, -837, -837, 0, 0, 0, -837, -837, -837, -837, -837, -837, 0, -837, 0, 0, 0, 0, 0, 0, 0, 0, -837, 0, 0, -837, -837, 0, -837, 0, -837, -837, 0, 0, 0, -837, -837, 0, 0, 0, 0, 0, 0, 0, 0, 0, -837, -837, -837, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 436, // State 13 - 0, 0, 0, 0, 0, 0, 0, 14, 471, 15, 39, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 14 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 472, 16, 40, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 15 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 479, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 16 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 480, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 17 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 18 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 19 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 48, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 494, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 20 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 0, 497, 0, 0, 0, 0, 0, 0, 498, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 49, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 495, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 21 - 524, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 525, 17, 526, 0, 57, 527, 58, 59, 0, 0, 0, 0, 60, 61, 62, 63, 64, 0, 0, 18, 65, 66, 19, 0, 528, 67, 68, 529, 69, 70, 71, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 498, 0, 0, 0, 0, 0, 0, 499, 0, 0, 0, 0, // State 22 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 525, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 526, 18, 527, 0, 58, 528, 59, 60, 0, 0, 0, 0, 61, 62, 63, 64, 65, 0, 0, 19, 66, 67, 20, 0, 529, 68, 69, 530, 70, 71, 72, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 23 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 24 - 0, 0, 0, 0, 0, 0, 0, 14, 535, 76, 77, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 25 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 536, 77, 78, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 26 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 27 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 28 - -303, -303, 443, 0, -303, 0, -303, 0, -303, 0, 0, -303, -303, 0, -303, -303, 0, -303, 0, 0, 0, 0, 0, -303, -303, -303, 0, -303, 444, 0, -303, 445, -303, 446, 447, 448, 0, -303, 0, 0, -303, 0, 0, 0, 0, -303, 0, -303, -303, -303, 0, -303, 0, 0, 0, 0, 0, 0, 0, 0, -303, 0, 0, -303, -303, 0, -303, 0, 449, 450, 0, 0, 0, 451, -303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -303, -303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 29 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + -303, -303, 443, 0, -303, 0, -303, 0, -303, 0, 0, -303, -303, 0, -303, -303, 0, -303, 0, 0, 0, 0, 0, -303, -303, -303, 0, -303, 444, 0, -303, 445, -303, 446, 447, 448, 0, -303, 0, 0, -303, 0, 0, 0, 0, -303, 0, -303, -303, -303, 0, -303, 0, 0, 0, 0, 0, 0, 0, 0, -303, 0, 0, -303, -303, 0, -303, 0, 449, 450, 0, 0, 0, 451, -303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -303, -303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 30 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 31 - -426, -426, 0, 0, -426, 0, -426, 14, -426, 15, 0, -426, -426, 425, -426, 0, 426, -426, 0, 0, 427, 0, 0, -426, -426, -426, 0, -426, 0, 0, -426, 0, -426, 0, 0, 0, 0, -426, 0, 0, -426, 428, 429, 430, 16, 0, 0, -426, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, -426, -426, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 32 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + -426, -426, 0, 0, -426, 0, -426, 15, -426, 16, 0, -426, -426, 425, -426, 0, 426, -426, 0, 0, 427, 0, 0, -426, -426, -426, 0, -426, 0, 0, -426, 0, -426, 0, 0, 0, 0, -426, 0, 0, -426, 428, 429, 430, 17, 0, 0, -426, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, -426, -426, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 33 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 34 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 35 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 36 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 37 - 0, 0, 0, 0, 0, 0, 0, 0, 556, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 38 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 557, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 39 - -947, -947, 0, 0, 0, 0, 0, 14, -947, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, -947, 0, -947, 0, 0, 0, 0, -947, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, -947, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 40 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -552, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -552, 0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -950, -950, 0, 0, 0, 0, 0, 15, -950, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, -950, 0, -950, 0, 0, 0, 0, -950, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, -950, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 41 - -247, -247, -247, -247, -247, -247, -247, 25, -247, -247, -247, -247, -247, -247, -247, -247, -247, -247, 0, 26, 0, -247, -247, -247, -247, -247, 0, -247, -247, -247, -247, -247, -247, -247, -247, -247, -247, -247, -247, -247, -247, 0, 0, 0, 27, -247, -247, -247, -247, -247, 0, -247, 0, 0, 0, 0, 0, 0, 0, 0, -247, 0, 0, -247, -247, 0, -247, 0, -247, -247, 0, 0, 0, -247, -247, 0, 0, 0, 0, 0, 0, 0, 0, 0, -247, -247, -247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -553, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -553, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 42 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, -723, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + -247, -247, -247, -247, -247, -247, -247, 26, -247, -247, -247, -247, -247, -247, -247, -247, -247, -247, 0, 27, 0, -247, -247, -247, -247, -247, 0, -247, -247, -247, -247, -247, -247, -247, -247, -247, -247, -247, -247, -247, -247, 0, 0, 0, 28, -247, -247, -247, -247, -247, 0, -247, 0, 0, 0, 0, 0, 0, 0, 0, -247, 0, 0, -247, -247, 0, -247, 0, -247, -247, 0, 0, 0, -247, -247, 0, 0, 0, 0, 0, 0, 0, 0, 0, -247, -247, -247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 43 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -460, 0, 0, 0, 0, 0, 0, 0, 0, 0, -460, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, -724, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 44 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 93, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -460, 0, 0, 0, 0, 0, 0, 0, 0, 0, -460, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 45 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 94, 434, 0, 435, 436, // State 46 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 47 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -879, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -879, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 48 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 0, 574, 0, 0, 0, 0, 0, 0, 498, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 49 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 575, 0, 0, 0, 0, 0, 0, 499, 0, 0, 0, 0, // State 50 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 51 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 579, 0, 0, 0, 98, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 52 - -304, 0, 443, 0, -304, 0, -304, 0, 0, 0, 0, -304, -304, 0, -304, -304, 0, -304, 0, 0, 0, 0, 0, -304, -304, -304, 0, -304, 444, 0, -304, 445, -304, 446, 447, 448, 0, -304, 581, 0, -304, 0, 0, 0, 0, 0, 0, -304, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -304, 0, 449, 450, 0, 0, 0, 451, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 580, 0, 0, 0, 99, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 53 - -358, 0, 0, 0, 583, 0, 584, 0, 0, 0, 0, 585, 586, 0, 587, 0, 0, 588, 0, 0, 0, 0, 0, 589, 590, 0, 0, -358, 0, 0, 591, 0, 102, 0, 0, 0, 0, 592, 0, 0, 593, 0, 0, 0, 0, 0, 0, 594, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 595, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -304, 0, 443, 0, -304, 0, -304, 0, 0, 0, 0, -304, -304, 0, -304, -304, 0, -304, 0, 0, 0, 0, 0, -304, -304, -304, 0, -304, 444, 0, -304, 445, -304, 446, 447, 448, 0, -304, 582, 0, -304, 0, 0, 0, 0, 0, 0, -304, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -304, 0, 449, 450, 0, 0, 0, 451, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 54 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + -358, 0, 0, 0, 584, 0, 585, 0, 0, 0, 0, 586, 587, 0, 588, 0, 0, 589, 0, 0, 0, 0, 0, 590, 591, 0, 0, -358, 0, 0, 592, 0, 103, 0, 0, 0, 0, 593, 0, 0, 594, 0, 0, 0, 0, 0, 0, 595, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 596, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 55 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 56 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 57 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 58 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 59 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 60 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 611, 612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 61 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 0, // State 62 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 63 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 64 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 0, // State 65 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 66 - -775, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, -775, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 67 - -394, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, -394, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + -776, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, -776, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 68 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + -394, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, -394, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 69 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 70 - 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 653, 654, 655, 124, 0, 0, 0, 0, 0, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 71 - -154, -154, -154, 0, -154, -154, -154, 0, -154, 0, 0, -154, -154, 0, -154, -154, 0, -154, 0, 0, 0, 0, 0, -154, -154, -154, 0, -154, -154, 455, -154, -154, -154, -154, -154, -154, 456, -154, -154, 0, -154, 0, 0, 0, 0, -154, -154, -154, -154, -154, 0, -154, 0, 0, 0, 0, 0, 0, 0, 0, -154, 0, 0, -154, -154, 0, -154, 0, -154, -154, 0, 0, 0, -154, -154, 0, 0, 0, 0, 0, 0, 0, 0, 0, -154, -154, -154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 654, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 655, 656, 657, 124, 0, 0, 0, 0, 0, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 72 - -168, -168, -168, 458, -168, -168, -168, 0, -168, 459, 0, -168, -168, -168, -168, -168, -168, -168, 0, 0, 0, 460, 461, -168, -168, -168, 0, -168, -168, -168, -168, -168, -168, -168, -168, -168, -168, -168, -168, 462, -168, 0, 0, 0, 0, -168, -168, -168, -168, -168, 0, -168, 0, 0, 0, 0, 0, 0, 0, 0, -168, 0, 0, -168, -168, 0, -168, 0, -168, -168, 0, 0, 0, -168, -168, 0, 0, 0, 0, 0, 0, 0, 0, 0, -168, -168, -168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -154, -154, -154, 0, -154, -154, -154, 0, -154, 0, 0, -154, -154, 0, -154, -154, 0, -154, 0, 0, 0, 0, 0, -154, -154, -154, 0, -154, -154, 455, -154, -154, -154, -154, -154, -154, 456, -154, -154, 0, -154, 0, 0, 0, 0, -154, -154, -154, -154, -154, 0, -154, 0, 0, 0, 0, 0, 0, 0, 0, -154, 0, 0, -154, -154, 0, -154, 0, -154, -154, 0, 0, 0, -154, -154, 0, 0, 0, 0, 0, 0, 0, 0, 0, -154, -154, -154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 73 - 0, 0, 0, 0, 0, 0, 0, 14, 657, 76, 77, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + -168, -168, -168, 458, -168, -168, -168, 0, -168, 459, 0, -168, -168, -168, -168, -168, -168, -168, 0, 0, 0, 460, 461, -168, -168, -168, 0, -168, -168, -168, -168, -168, -168, -168, -168, -168, -168, -168, -168, 462, -168, 0, 0, 0, 0, -168, -168, -168, -168, -168, 0, -168, 0, 0, 0, 0, 0, 0, 0, 0, -168, 0, 0, -168, -168, 0, -168, 0, -168, -168, 0, 0, 0, -168, -168, 0, 0, 0, 0, 0, 0, 0, 0, 0, -168, -168, -168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 74 - 0, 0, 0, 0, 0, 0, 0, 0, -418, 0, 0, 0, 0, 0, 0, -418, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 659, 77, 78, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 75 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, -418, 0, 0, 0, 0, 0, 0, -418, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 76 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 77 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, -850, 426, 0, 0, 0, 427, 0, 0, 0, 0, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, -850, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 78 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, -849, 426, 0, 0, 0, 427, 0, 0, 0, 0, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, -849, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 79 - -789, -789, -789, 0, -789, -789, -789, 0, -789, 0, 0, -789, -789, 440, -789, -789, 441, -789, 0, 0, 0, 0, 0, -789, -789, -789, 0, -789, -789, -789, -789, -789, -789, -789, -789, -789, -789, -789, -789, 0, -789, 0, 0, 0, 0, -789, -789, -789, -789, -789, 0, -789, 0, 0, 0, 0, 0, 0, 0, 0, -789, 0, 0, -789, -789, 0, -789, 0, -789, -789, 0, 0, 0, -789, -789, 0, 0, 0, 0, 0, 0, 0, 0, 0, -789, -789, -789, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 80 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + -790, -790, -790, 0, -790, -790, -790, 0, -790, 0, 0, -790, -790, 440, -790, -790, 441, -790, 0, 0, 0, 0, 0, -790, -790, -790, 0, -790, -790, -790, -790, -790, -790, -790, -790, -790, -790, -790, -790, 0, -790, 0, 0, 0, 0, -790, -790, -790, -790, -790, 0, -790, 0, 0, 0, 0, 0, 0, 0, 0, -790, 0, 0, -790, -790, 0, -790, 0, -790, -790, 0, 0, 0, -790, -790, 0, 0, 0, 0, 0, 0, 0, 0, 0, -790, -790, -790, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 81 - 0, 0, 0, 0, 0, 0, 0, 0, -290, 0, 0, 0, 0, 0, 0, -290, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -290, 0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -290, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 82 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, -290, 0, 0, 0, 0, 0, 0, -290, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -290, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -290, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 83 - 0, 0, 0, 0, 0, 0, 0, 14, 672, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 84 - 0, 0, 0, 0, 0, 0, 0, 14, 675, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 674, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 85 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 677, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 86 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, -465, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 87 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, 0, 0, 0, -674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, -465, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 88 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 140, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, 0, 0, 0, -675, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 89 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 140, 434, 0, 435, 436, // State 90 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142, 0, 0, 0, 0, 0, 0, 0, 0, 0, -722, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 91 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -715, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142, 0, 0, 0, 0, 0, 0, 0, 0, 0, -723, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 92 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -716, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 93 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 48, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, -329, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 94 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, -787, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 49, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, -329, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 95 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, -788, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 96 - 0, 695, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 696, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 97 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 698, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 98 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 99 - -359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -359, 0, 0, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 100 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + -359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -359, 0, 0, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 101 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 704, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 102 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 706, 435, 436, // State 103 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 104 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 105 - 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 653, 654, 655, 124, 0, 0, 0, 0, 0, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 106 - 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 654, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 655, 656, 657, 124, 0, 0, 0, 0, 0, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 107 - 0, 0, 0, 0, 0, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 108 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 611, 612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -451, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 0, + 0, 0, 0, 0, 0, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 109 - -333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -333, 0, 0, 0, 161, 0, 0, 0, 0, 0, 0, 0, -333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -451, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 0, // State 110 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + -333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -333, 0, 0, 0, 161, 0, 0, 0, 0, 0, 0, 0, -333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 111 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 112 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 113 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 114 - 0, 0, -790, 0, 0, -790, 0, 0, 0, 0, 0, 0, 0, 440, 0, -790, 441, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -790, -790, 0, -790, 0, -790, -790, -790, -790, 0, 0, 0, 0, 0, 0, 0, 0, 0, -790, 0, -790, -790, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -790, 0, -790, -790, 0, 0, 0, -790, -790, 0, 0, 0, 0, 0, 0, 0, 0, 0, -790, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 115 - 0, 0, -248, -248, 0, -248, 0, 25, 0, -248, -248, 0, 0, -248, 0, -248, -248, 0, 0, 175, 0, -248, -248, 0, 0, 0, 0, 0, -248, -248, 0, -248, 0, -248, -248, -248, -248, 0, 0, -248, 0, 0, 0, 0, 176, 0, -248, 0, -248, -248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -248, 0, -248, -248, 0, 0, 0, -248, -248, 0, 0, 0, 0, 0, 0, 0, 0, 0, -248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -791, 0, 0, -791, 0, 0, 0, 0, 0, 0, 0, 440, 0, -791, 441, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -791, -791, 0, -791, 0, -791, -791, -791, -791, 0, 0, 0, 0, 0, 0, 0, 0, 0, -791, 0, -791, -791, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -791, 0, -791, -791, 0, 0, 0, -791, -791, 0, 0, 0, 0, 0, 0, 0, 0, 0, -791, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 116 - 0, 0, 443, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 444, 0, 0, 445, 0, 446, 447, 448, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -304, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -304, 0, 449, 450, 0, 0, 0, 451, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -248, -248, 0, -248, 0, 26, 0, -248, -248, 0, 0, -248, 0, -248, -248, 0, 0, 175, 0, -248, -248, 0, 0, 0, 0, 0, -248, -248, 0, -248, 0, -248, -248, -248, -248, 0, 0, -248, 0, 0, 0, 0, 176, 0, -248, 0, -248, -248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -248, 0, -248, -248, 0, 0, 0, -248, -248, 0, 0, 0, 0, 0, 0, 0, 0, 0, -248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 117 - 0, 0, -155, 0, 0, -155, 0, 0, 0, 0, 0, 0, 0, 0, 0, -155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -155, 455, 0, -155, 0, -155, -155, -155, 456, 0, 0, 0, 0, 0, 0, 0, 0, 0, -155, 0, -155, -155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -155, 0, -155, -155, 0, 0, 0, -155, -155, 0, 0, 0, 0, 0, 0, 0, 0, 0, -155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 443, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 444, 0, 0, 445, 0, 446, 447, 448, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -304, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -304, 0, 449, 450, 0, 0, 0, 451, -304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 118 - 0, 0, -183, -183, 0, -183, 0, -183, 0, -183, -183, 0, 0, -183, 0, -183, -183, 0, 0, -183, 0, -183, -183, 0, 0, -212, 0, 0, -183, -183, 0, -183, 0, -183, -183, -183, -183, 0, 0, -183, 0, 0, 0, 0, -183, 0, -183, 0, -183, -183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -183, 0, -183, -183, 0, 0, 0, -183, -183, 0, 0, 0, 0, 0, 0, 0, 0, 0, -183, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 436, + 0, 0, -155, 0, 0, -155, 0, 0, 0, 0, 0, 0, 0, 0, 0, -155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -155, 455, 0, -155, 0, -155, -155, -155, 456, 0, 0, 0, 0, 0, 0, 0, 0, 0, -155, 0, -155, -155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -155, 0, -155, -155, 0, 0, 0, -155, -155, 0, 0, 0, 0, 0, 0, 0, 0, 0, -155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 119 0, 0, -169, 458, 0, -169, 0, 0, 0, 459, 0, 0, 0, -169, 0, -169, -169, 0, 0, 0, 0, 460, 461, 0, 0, 0, 0, 0, -169, -169, 0, -169, 0, -169, -169, -169, -169, 0, 0, 462, 0, 0, 0, 0, 0, 0, -169, 0, -169, -169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -169, 0, -169, -169, 0, 0, 0, -169, -169, 0, 0, 0, 0, 0, 0, 0, 0, 0, -169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 120 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 122 - 0, 0, 0, 0, 0, 0, 0, 14, 727, 15, 190, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 729, 16, 190, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 123 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 729, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 731, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 124 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 125 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 126 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 48, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 733, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 49, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 735, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 127 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 128 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, -852, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, -851, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 129 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, -848, 426, 0, 0, 0, 427, 0, 0, 0, 0, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, -848, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, -847, 426, 0, 0, 0, 427, 0, 0, 0, 0, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, -847, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 130 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, -853, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, -852, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 131 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -849, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -849, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -848, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -848, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 132 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, -802, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, -802, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, -803, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, -803, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 133 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 134 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 135 - 0, 0, 0, 0, 0, 0, 0, 14, 745, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 747, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 136 - 0, 0, 0, 0, 0, 0, 0, 0, 747, 0, 0, 0, 0, 0, 0, 197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 749, 0, 0, 0, 0, 0, 0, 197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 137 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, -692, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, -693, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 138 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, -702, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, -703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 139 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 140 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -717, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -718, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 141 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -714, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -715, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 142 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 757, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 143 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, -368, 0, 0, 0, 0, 0, 0, 0, 0, 0, 498, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, -368, 0, 0, 0, 0, 0, 0, 0, 0, 0, 499, 0, 0, 0, 0, // State 144 - 0, 695, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 762, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 764, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 145 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 146 - 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 147 0, 0, 0, 0, 0, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 148 - -362, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -362, 0, 0, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -362, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -362, 0, 0, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 149 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 150 0, 0, 0, 0, 0, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 151 - 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 152 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 153 0, 0, 0, 0, 0, 0, 0, 0, 0, 213, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 154 0, 0, 0, 0, 0, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 155 - 0, 0, 0, 0, 0, 0, 0, 0, 781, 217, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 783, 217, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 156 - -353, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, -353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + -353, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, -353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 157 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 158 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -424, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -424, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 159 - 0, 0, 0, 0, 0, 0, 0, 219, 0, 787, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 219, 0, 789, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 160 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 161 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 162 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 163 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 164 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 0, // State 165 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 793, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 795, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 166 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 796, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 798, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 167 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 168 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 169 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 804, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 806, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 170 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 171 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 172 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 173 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 174 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 175 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 176 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 177 0, 0, 443, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -303, 0, 0, 0, 0, 0, 0, 0, 0, 0, -305, 0, 0, 444, 0, 0, 445, 0, 446, 447, 448, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -303, -303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -303, 0, 449, 450, 0, 0, 0, 451, -303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 178 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 179 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 180 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 181 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 182 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 183 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 184 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 185 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 186 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 187 - 0, 0, 0, 0, 0, 0, 0, 0, 820, 0, 0, 0, 0, 0, 0, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 822, 0, 0, 0, 0, 0, 0, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 188 - 0, 0, 0, 0, 0, 0, 0, 0, 823, 0, 0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 825, 0, 0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 189 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 190 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -552, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -552, 0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -553, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -553, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 191 - 0, 0, -247, -247, 0, -247, 0, 25, 0, -247, -247, 0, 0, -247, 0, -247, -247, 0, 0, 26, 0, -247, -247, 0, 0, -249, 0, 0, -247, -247, 0, -247, 0, -247, -247, -247, -247, 0, 0, -247, 0, 0, 0, 0, 27, 0, -247, 0, -247, -247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -247, 0, -247, -247, 0, 0, 0, -247, -247, 0, 0, 0, 0, 0, 0, 0, 0, 0, -247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -247, -247, 0, -247, 0, 26, 0, -247, -247, 0, 0, -247, 0, -247, -247, 0, 0, 27, 0, -247, -247, 0, 0, -249, 0, 0, -247, -247, 0, -247, 0, -247, -247, -247, -247, 0, 0, -247, 0, 0, 0, 0, 28, 0, -247, 0, -247, -247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -247, 0, -247, -247, 0, 0, 0, -247, -247, 0, 0, 0, 0, 0, 0, 0, 0, 0, -247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 192 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 193 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -879, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -879, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 194 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -847, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -847, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -846, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -846, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 195 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 196 - 0, 0, 0, 0, 0, 0, 0, 14, 834, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 836, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 197 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, -689, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, -690, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 198 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -665, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 199 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -675, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -676, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 200 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -716, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -717, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 201 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, -369, 0, 0, 0, 0, 0, 0, 0, 0, 0, 498, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, -369, 0, 0, 0, 0, 0, 0, 0, 0, 0, 499, 0, 0, 0, 0, // State 202 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 843, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 203 0, 0, 0, 0, 0, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 204 - 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 205 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 206 0, 0, 0, 0, 0, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 207 0, 0, 0, 0, 0, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 208 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 209 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 210 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 211 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 212 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 213 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 214 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 215 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 216 - 0, 0, 0, 0, 0, 0, 0, 0, -645, 0, 0, 0, 0, 0, 0, 257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -646, 0, 0, 0, 0, 0, 0, 257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 217 0, 0, 0, 0, 0, 0, 0, 0, -458, 0, 0, 0, 0, 0, 0, -458, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 218 @@ -592,87 +592,87 @@ mod __parse__Top { // State 219 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 220 - -432, 0, 0, 0, 0, 0, 0, -432, 0, -432, 0, 0, 0, -432, 0, 0, -432, 0, 0, 0, -432, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -432, 0, -432, -432, -432, -432, 0, 0, 0, 0, 0, -432, -432, -432, -432, 0, -432, -432, -432, -432, 261, 868, 0, 0, -432, -432, -432, -432, -432, 0, 0, -432, -432, -432, -432, 0, -432, -432, -432, -432, -432, -432, -432, -432, -432, 0, 0, 0, -432, -432, 0, -432, 0, 0, 0, -432, -432, 0, -432, -432, -432, -432, + -432, 0, 0, 0, 0, 0, 0, -432, 0, -432, 0, 0, 0, -432, 0, 0, -432, 0, 0, 0, -432, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -432, 0, -432, -432, -432, -432, 0, 0, 0, 0, 0, -432, -432, -432, -432, 0, -432, -432, -432, -432, 261, 870, 0, 0, -432, -432, -432, -432, -432, 0, 0, -432, -432, -432, -432, 0, -432, -432, -432, -432, -432, -432, -432, -432, -432, 0, 0, 0, -432, -432, 0, -432, 0, 0, 0, -432, -432, 0, -432, -432, -432, -432, // State 221 - -888, 0, 0, 0, 0, 0, 0, -888, 0, -888, 0, 0, 0, -888, 0, 0, -888, 0, 0, 0, -888, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -888, 0, -888, -888, -888, -888, 0, 0, 0, 0, 0, -888, -888, -888, -888, 0, -888, -888, -888, -888, 0, 875, 265, 876, -888, -888, -888, -888, -888, 0, 0, -888, -888, -888, -888, 0, -888, -888, -888, -888, -888, -888, -888, -888, -888, 0, 0, 0, -888, -888, 0, -888, 0, 0, 0, -888, -888, 0, -888, -888, -888, -888, + -887, 0, 0, 0, 0, 0, 0, -887, 0, -887, 0, 0, 0, -887, 0, 0, -887, 0, 0, 0, -887, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -887, 0, -887, -887, -887, -887, 0, 0, 0, 0, 0, -887, -887, -887, -887, 0, -887, -887, -887, -887, 0, 877, 265, 878, -887, -887, -887, -887, -887, 0, 0, -887, -887, -887, -887, 0, -887, -887, -887, -887, -887, -887, -887, -887, -887, 0, 0, 0, -887, -887, 0, -887, 0, 0, 0, -887, -887, 0, -887, -887, -887, -887, // State 222 - -892, 0, 0, 0, 0, 0, 0, -892, 0, -892, 0, 0, 0, -892, 0, 0, -892, 0, 0, 0, -892, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -892, 0, -892, -892, -892, -892, 0, 0, 0, 0, 0, -892, -892, -892, -892, 0, -892, -892, -892, -892, 0, 878, 879, 880, -892, -892, -892, -892, -892, 0, 0, -892, -892, -892, -892, 0, -892, -892, -892, -892, -892, -892, -892, -892, -892, 0, 0, 0, -892, -892, 0, -892, 0, 0, 0, -892, -892, 0, -892, -892, -892, -892, + -891, 0, 0, 0, 0, 0, 0, -891, 0, -891, 0, 0, 0, -891, 0, 0, -891, 0, 0, 0, -891, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -891, 0, -891, -891, -891, -891, 0, 0, 0, 0, 0, -891, -891, -891, -891, 0, -891, -891, -891, -891, 0, 880, 881, 882, -891, -891, -891, -891, -891, 0, 0, -891, -891, -891, -891, 0, -891, -891, -891, -891, -891, -891, -891, -891, -891, 0, 0, 0, -891, -891, 0, -891, 0, 0, 0, -891, -891, 0, -891, -891, -891, -891, // State 223 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 266, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 266, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 224 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 525, 17, 526, 0, 57, 527, 58, 59, 0, 0, 0, 0, 60, 61, 62, 63, 64, 0, 0, 18, 65, 66, 19, 0, 528, 67, 68, 529, 69, 70, 71, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 526, 18, 527, 0, 58, 528, 59, 60, 0, 0, 0, 0, 61, 62, 63, 64, 65, 0, 0, 19, 66, 67, 20, 0, 529, 68, 69, 530, 70, 71, 72, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 225 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 226 0, 0, -154, 0, 0, -154, 0, 0, 0, 0, 0, 0, 0, 0, 0, -154, 0, 0, 0, 0, 0, 0, 0, 0, 0, -156, 0, 0, -154, 455, 0, -154, 0, -154, -154, -154, 456, 0, 0, 0, 0, 0, 0, 0, 0, 0, -154, 0, -154, -154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -154, 0, -154, -154, 0, 0, 0, -154, -154, 0, 0, 0, 0, 0, 0, 0, 0, 0, -154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 227 0, 0, -168, 458, 0, -168, 0, 0, 0, 459, 0, 0, 0, -168, 0, -168, -168, 0, 0, 0, 0, 460, 461, 0, 0, -170, 0, 0, -168, -168, 0, -168, 0, -168, -168, -168, -168, 0, 0, 462, 0, 0, 0, 0, 0, 0, -168, 0, -168, -168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -168, 0, -168, -168, 0, 0, 0, -168, -168, 0, 0, 0, 0, 0, 0, 0, 0, 0, -168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 228 - 0, 0, -789, 0, 0, -789, 0, 0, 0, 0, 0, 0, 0, 440, 0, -789, 441, 0, 0, 0, 0, 0, 0, 0, 0, -791, 0, 0, -789, -789, 0, -789, 0, -789, -789, -789, -789, 0, 0, 0, 0, 0, 0, 0, 0, 0, -789, 0, -789, -789, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -789, 0, -789, -789, 0, 0, 0, -789, -789, 0, 0, 0, 0, 0, 0, 0, 0, 0, -789, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -790, 0, 0, -790, 0, 0, 0, 0, 0, 0, 0, 440, 0, -790, 441, 0, 0, 0, 0, 0, 0, 0, 0, -792, 0, 0, -790, -790, 0, -790, 0, -790, -790, -790, -790, 0, 0, 0, 0, 0, 0, 0, 0, 0, -790, 0, -790, -790, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -790, 0, -790, -790, 0, 0, 0, -790, -790, 0, 0, 0, 0, 0, 0, 0, 0, 0, -790, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 229 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 230 - 0, 0, 0, 0, 0, 0, 0, 14, 890, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 892, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 231 - 0, 0, 0, 0, 0, 0, 0, 14, 892, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 894, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 232 - 0, 0, 0, 0, 0, 0, 0, 14, 894, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 896, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 233 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 234 - 0, 0, 0, 0, 0, 0, 0, 0, -797, 0, 0, 0, 0, 0, 0, -797, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -797, 0, 0, 0, 0, 0, -797, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -797, 0, 0, 278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -797, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -798, 0, 0, 0, 0, 0, 0, -798, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -798, 0, 0, 0, 0, 0, -798, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -798, 0, 0, 278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -798, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 235 - 0, 0, 0, 0, 0, 0, 0, 14, 900, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 902, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 236 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -671, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 237 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -662, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 238 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 280, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -676, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 280, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -677, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 239 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 282, 0, 0, 0, 0, 0, 0, 0, 0, 0, -693, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 282, 0, 0, 0, 0, 0, 0, 0, 0, 0, -694, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 240 0, 0, 0, 0, 0, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 241 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 242 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 243 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 244 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 245 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 246 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 247 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 248 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 249 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 213, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 919, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 213, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 921, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 250 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 251 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 252 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 253 - 0, 0, 0, 0, 0, 0, 0, 0, -596, 292, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 293, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -597, 292, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 293, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 254 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 255 - 0, 0, 0, 0, 0, 0, 0, 0, -644, 0, 0, 0, 0, 0, 0, 296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -645, 0, 0, 0, 0, 0, 0, 296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 256 - 0, 0, 0, 0, 0, 0, 0, 0, -637, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -638, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 257 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 258 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 259 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 260 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 261 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 262 @@ -680,329 +680,329 @@ mod __parse__Top { // State 263 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 264 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 265 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 266 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 267 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 268 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 269 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 525, 17, 526, 0, 57, 527, 58, 59, 0, 0, 0, 0, 60, 61, 62, 63, 64, 0, 0, 18, 65, 66, 19, 0, 528, 67, 68, 529, 69, 70, 71, 40, 20, 0, 0, 0, 431, 946, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 526, 18, 527, 0, 58, 528, 59, 60, 0, 0, 0, 0, 61, 62, 63, 64, 65, 0, 0, 19, 66, 67, 20, 0, 529, 68, 69, 530, 70, 71, 72, 41, 21, 0, 0, 0, 431, 948, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 270 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 271 - 0, 0, 0, 0, 0, 0, 0, 14, 948, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 950, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 272 - 0, 0, 0, 0, 0, 0, 0, 0, 950, 0, 0, 0, 0, 0, 0, 314, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 952, 0, 0, 0, 0, 0, 0, 314, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 273 - 0, 0, 0, 0, 0, 0, 0, 0, 952, 0, 0, 0, 0, 0, 0, 315, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 954, 0, 0, 0, 0, 0, 0, 315, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 274 - 0, 0, 0, 0, 0, 0, 0, 14, 953, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 955, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 275 - 0, 0, 0, 0, 0, 0, 0, 0, -795, 0, 0, 0, 0, 0, 0, -795, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -795, 0, 0, 0, 0, 0, -795, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -795, 0, 0, 278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -795, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -796, 0, 0, 0, 0, 0, 0, -796, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -796, 0, 0, 0, 0, 0, -796, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -796, 0, 0, 278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -796, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 276 - 0, 0, 0, 0, 0, 0, 0, 0, -798, 0, 0, 0, 0, 0, 0, -798, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -798, 0, 0, 0, 0, 0, -798, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -798, 0, 0, 278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -798, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -799, 0, 0, 0, 0, 0, 0, -799, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -799, 0, 0, 0, 0, 0, -799, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -799, 0, 0, 278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -799, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 277 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 278 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -668, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -669, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 279 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 318, 0, 0, 0, 0, 0, 0, 0, 0, 0, -694, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 318, 0, 0, 0, 0, 0, 0, 0, 0, 0, -695, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 280 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 320, 0, 0, 0, 0, 0, 0, 0, 0, 0, -690, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 320, 0, 0, 0, 0, 0, 0, 0, 0, 0, -691, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 281 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 282 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 283 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 284 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 285 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 286 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 287 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 288 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 289 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 290 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 291 - 0, 0, 0, 0, 0, 0, 0, 0, -614, 0, 0, 0, 0, 0, 0, 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -615, 0, 0, 0, 0, 0, 0, 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 292 - 0, 0, 0, 0, 0, 0, 0, 0, -624, 0, 0, 0, 0, 0, 0, 328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -625, 0, 0, 0, 0, 0, 0, 328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 293 - 0, 0, 0, 0, 0, 0, 0, 0, -639, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -640, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 294 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 295 - 0, 0, 0, 0, 0, 0, 0, 0, -636, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -637, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 296 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 297 - 0, 0, 0, 0, 0, 0, 0, 0, 983, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 985, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 298 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 299 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 300 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 301 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 987, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 989, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 302 - 0, 0, 0, 0, 0, 0, 0, 339, 0, 340, 0, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1006, 1007, 1008, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 340, 0, 341, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1007, 1008, 1009, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 303 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 304 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1009, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1010, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 305 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 306 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 307 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 308 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 309 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 310 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 311 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 312 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 313 - 0, 0, 0, 0, 0, 0, 0, 14, 1024, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 1025, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 314 - 0, 0, 0, 0, 0, 0, 0, 14, 1026, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 1027, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 315 - 0, 0, 0, 0, 0, 0, 0, 0, -796, 0, 0, 0, 0, 0, 0, -796, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -796, 0, 0, 0, 0, 0, -796, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -796, 0, 0, 278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -796, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -797, 0, 0, 0, 0, 0, 0, -797, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -797, 0, 0, 0, 0, 0, -797, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -797, 0, 0, 278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -797, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 316 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 350, 0, 0, 0, 0, 0, 0, 0, 0, 0, -691, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0, 0, 0, 0, -692, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 317 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -668, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 318 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -673, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 319 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -664, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 320 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 321 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 322 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 323 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 324 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 325 - 0, 0, 0, 0, 0, 0, 0, 0, -611, 0, 0, 0, 0, 0, 0, 356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -612, 0, 0, 0, 0, 0, 0, 357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 326 - 0, 0, 0, 0, 0, 0, 0, 0, -587, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -588, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 327 - 0, 0, 0, 0, 0, 0, 0, 0, -597, 358, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -598, 359, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 328 - 0, 0, 0, 0, 0, 0, 0, 0, -638, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -639, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 329 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 330 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 331 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 332 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1049, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 333 - 0, 0, 0, 0, 0, 0, 0, 362, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 363, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 363, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 364, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 334 - 0, 0, 0, 0, 0, 0, 0, 362, -919, 0, 0, 0, 0, 0, 0, -919, 0, 0, 0, 364, 0, 0, 0, 0, 0, -919, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -919, 0, 0, 0, -919, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -919, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -919, 0, -919, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 363, -922, 0, 0, 0, 0, 0, 0, -922, 0, 0, 0, 365, 0, 0, 0, 0, 0, -922, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -922, 0, 0, 0, -922, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -922, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -922, 0, -922, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 335 0, 0, 0, 0, 0, 0, 0, 0, -472, 0, 0, 0, 0, 440, 0, -472, 441, 0, 0, 0, 0, 0, 0, 0, 0, -472, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -472, 0, 0, 0, -472, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -472, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -472, 0, -472, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 336 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 368, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 369, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 369, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 370, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 337 0, 0, 0, 0, 0, 0, 0, 0, -474, 0, 0, 0, 0, 0, 0, -474, 0, 0, 0, 0, 0, 0, 0, 0, 0, -474, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -474, 0, 0, 0, -474, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -474, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -474, 0, -474, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 436, // State 338 - 0, 0, 0, 0, 0, 0, 0, 339, 1054, 340, 0, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1006, 1007, 1008, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, -475, 0, 0, 0, 0, 0, 0, -475, 0, 0, 0, 0, 0, 0, 0, 0, 0, -475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -475, 0, 0, 0, -475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -475, 0, -475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 436, // State 339 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 340, 1056, 341, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1007, 1008, 1009, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 340 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 341 - 0, 0, 0, 0, 0, 0, 0, 339, 0, 340, 0, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1006, 1007, 1008, 342, 1058, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 0, 0, // State 342 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 376, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1066, 1067, 1068, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1069, 0, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 340, 0, 341, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1007, 1008, 1009, 343, 1060, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 343 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1070, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 376, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1069, 1070, 1071, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1072, 0, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 344 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1073, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 345 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 346 - 0, 0, 0, 0, 0, 0, 0, 14, 1079, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 347 - 0, 0, 0, 0, 0, 0, 0, 14, 1080, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 1082, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 348 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -673, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 1083, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 349 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -664, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 350 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -669, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -665, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 351 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -670, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 352 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 353 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 354 - 0, 0, 0, 0, 0, 0, 0, 0, -593, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 355 - 0, 0, 0, 0, 0, 0, 0, 0, -584, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -594, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 356 - 0, 0, 0, 0, 0, 0, 0, 0, -598, 382, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -585, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 357 - 0, 0, 0, 0, 0, 0, 0, 0, -615, 0, 0, 0, 0, 0, 0, 384, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -599, 382, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 358 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, -616, 0, 0, 0, 0, 0, 0, 384, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 359 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 360 - 0, 0, 0, 0, 0, 0, 0, 339, 0, 340, 0, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1006, 1007, 1008, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 361 - 0, 0, 0, 0, 0, 0, 0, 339, 1105, 340, 0, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1006, 1007, 1008, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 340, 0, 341, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1007, 1008, 1009, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 362 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 340, 1108, 341, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1007, 1008, 1009, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 364 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 0, 0, - // State 365 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + // State 365 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 0, 0, // State 366 - 0, 0, 0, 0, 0, 0, 0, 339, 0, 340, 0, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, -760, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1006, 1007, 1008, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -760, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 367 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 340, 0, 341, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, -761, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1007, 1008, 1009, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -761, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 368 - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 369 - 0, 0, 0, 0, 0, 0, 0, 339, 0, 340, 0, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1006, 1007, 1008, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 370 - 0, 0, 0, 0, 0, 0, 0, 339, 0, 340, 0, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, -761, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1006, 1007, 1008, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -761, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 340, 0, 341, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1007, 1008, 1009, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 371 - 0, 0, 0, 0, 0, 0, 0, 339, 0, 340, 0, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1006, 1007, 1008, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 340, 0, 341, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, -762, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1007, 1008, 1009, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -762, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 372 - 0, 0, 0, 0, 0, 0, 0, 339, 0, 340, 0, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1006, 1007, 1008, 342, 1119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 340, 0, 341, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1007, 1008, 1009, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 373 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 440, 0, 0, 441, 0, 0, 0, 0, 0, 0, 0, 0, -476, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 340, 0, 341, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1007, 1008, 1009, 343, 1122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 374 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -481, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 440, 0, 0, 441, 0, 0, 0, 0, 0, 0, 0, 0, -478, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 376 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 377 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -670, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -671, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 378 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 379 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 380 - 0, 0, 0, 0, 0, 0, 0, 0, -590, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -591, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 381 - 0, 0, 0, 0, 0, 0, 0, 0, -616, 0, 0, 0, 0, 0, 0, 392, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -617, 0, 0, 0, 0, 0, 0, 392, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 382 - 0, 0, 0, 0, 0, 0, 0, 0, -612, 0, 0, 0, 0, 0, 0, 394, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -613, 0, 0, 0, 0, 0, 0, 394, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 383 - 0, 0, 0, 0, 0, 0, 0, 0, -588, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -589, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 384 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 385 - 0, 0, 0, 0, 0, 0, 0, 339, 0, 340, 0, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1006, 1007, 1008, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 340, 0, 341, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1007, 1008, 1009, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 386 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 398, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1066, 1067, 1068, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1149, 0, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 398, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1069, 1070, 1071, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1152, 0, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 387 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 388 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 389 - 717, 0, 0, 0, 0, 0, 0, 14, 0, 15, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 16, 0, 0, 0, 0, 0, 56, 0, 17, 526, 0, 0, 527, 0, 59, 0, 0, 0, 0, 0, 61, 62, 0, 64, 0, 0, 18, 0, 66, 19, 0, 528, 67, 68, 0, 69, 0, 0, 40, 20, 0, 0, 0, 431, 0, 0, 21, 0, 0, 0, 432, 433, 0, 434, 530, 435, 436, + 719, 0, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 425, 0, 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 429, 430, 17, 0, 0, 0, 0, 0, 57, 0, 18, 527, 0, 0, 528, 0, 60, 0, 0, 0, 0, 0, 62, 63, 0, 65, 0, 0, 19, 0, 67, 20, 0, 529, 68, 69, 0, 70, 0, 0, 41, 21, 0, 0, 0, 431, 0, 0, 22, 0, 0, 0, 432, 433, 0, 434, 531, 435, 436, // State 390 - 0, 0, 0, 0, 0, 0, 0, 0, -613, 0, 0, 0, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -614, 0, 0, 0, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 391 - 0, 0, 0, 0, 0, 0, 0, 0, -589, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -590, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 392 - 0, 0, 0, 0, 0, 0, 0, 0, -594, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -595, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 393 - 0, 0, 0, 0, 0, 0, 0, 0, -585, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -586, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 394 - 0, 0, 0, 0, 0, 0, 0, 339, 0, 340, 0, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1006, 1007, 1008, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 340, 0, 341, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1007, 1008, 1009, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 395 - 0, 0, 0, 0, 0, 0, 0, 0, 1165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 396 - 0, 0, 0, 0, 0, 0, 0, 339, 1168, 340, 0, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1006, 1007, 1008, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, + 0, 0, 0, 0, 0, 0, 0, 340, 1171, 341, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1007, 1008, 1009, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 433, 0, 434, 0, 435, 436, // State 397 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 398 - 0, 0, 0, 0, 0, 0, 0, 0, -595, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -596, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 399 - 0, 0, 0, 0, 0, 0, 0, 0, -586, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -587, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 400 - 0, 0, 0, 0, 0, 0, 0, 0, -591, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, - // State 401 0, 0, 0, 0, 0, 0, 0, 0, -592, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + // State 401 + 0, 0, 0, 0, 0, 0, 0, 0, -593, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 402 - 0, 0, 0, 0, 0, 0, 0, 0, 1185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 435, 0, // State 403 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 404 - -943, -943, -943, 0, -943, 23, -943, 0, -943, 0, 0, -943, -943, 0, -943, -943, 0, -943, 0, 0, 0, 0, 0, -943, -943, -943, 0, -943, -943, 0, -943, -943, -943, -943, -943, -943, 0, -943, -943, 0, -943, 0, 0, 0, 0, -943, -943, -943, -943, -943, 0, -943, 0, 0, 0, 0, 0, 0, 0, 0, -943, 0, 0, -943, -943, 0, -943, 0, -943, -943, 0, 0, 0, -943, -943, 0, 0, 0, 0, 0, 0, 0, 0, 0, -943, -943, -943, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -946, -946, -946, 0, -946, 24, -946, 0, -946, 0, 0, -946, -946, 0, -946, -946, 0, -946, 0, 0, 0, 0, 0, -946, -946, -946, 0, -946, -946, 0, -946, -946, -946, -946, -946, -946, 0, -946, -946, 0, -946, 0, 0, 0, 0, -946, -946, -946, -946, -946, 0, -946, 0, 0, 0, 0, 0, 0, 0, 0, -946, 0, 0, -946, -946, 0, -946, 0, -946, -946, 0, 0, 0, -946, -946, 0, 0, 0, 0, 0, 0, 0, 0, 0, -946, -946, -946, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 405 - -559, -559, 0, 0, -559, 0, -559, 0, -559, 0, 0, -559, -559, 0, -559, -559, 0, -559, 0, 0, 0, 0, 0, -559, -559, -559, 0, -559, 0, 0, -559, 0, -559, 0, 0, 0, 0, -559, 0, 0, -559, 0, 0, 0, 0, -559, 0, -559, 0, -559, 0, -559, 0, 0, 0, 0, 0, 0, 0, 0, -559, 0, 0, -559, -559, 0, -559, 0, 0, 0, 0, 0, 0, 0, 439, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -559, -559, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -560, -560, 0, 0, -560, 0, -560, 0, -560, 0, 0, -560, -560, 0, -560, -560, 0, -560, 0, 0, 0, 0, 0, -560, -560, -560, 0, -560, 0, 0, -560, 0, -560, 0, 0, 0, 0, -560, 0, 0, -560, 0, 0, 0, 0, -560, 0, -560, 0, -560, 0, -560, 0, 0, 0, 0, 0, 0, 0, 0, -560, 0, 0, -560, -560, 0, -560, 0, 0, 0, 0, 0, 0, 0, 439, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -560, -560, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 406 -239, -239, -239, -239, -239, -239, -239, -239, -239, -239, -239, -239, -239, -239, -239, -239, -239, -239, 0, -239, 0, -239, -239, -239, -239, -239, 0, -239, -239, -239, -239, -239, -239, -239, -239, -239, -239, -239, -239, -239, -239, 0, 0, 0, -239, -239, -239, -239, -239, -239, 0, -239, 0, 0, 0, 0, 0, 0, 0, 0, -239, 0, 0, -239, -239, 0, -239, 0, -239, -239, 0, 0, 0, -239, -239, 0, 0, 0, 0, 0, 0, 0, 0, 0, -239, -239, -239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 407 - -765, -765, -765, -765, -765, -765, -765, 0, -765, -765, 28, -765, -765, -765, -765, -765, -765, -765, 0, 0, 0, -765, -765, -765, -765, -765, 0, -765, -765, -765, -765, -765, -765, -765, -765, -765, -765, -765, -765, -765, -765, 0, 0, 0, 0, -765, -765, -765, -765, -765, 0, -765, 0, 0, 0, 0, 0, 0, 0, 0, -765, 0, 0, -765, -765, 0, -765, 0, -765, -765, 0, 0, 0, -765, -765, 0, 0, 0, 0, 0, 0, 0, 0, 0, -765, -765, -765, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -766, -766, -766, -766, -766, -766, -766, 0, -766, -766, 29, -766, -766, -766, -766, -766, -766, -766, 0, 0, 0, -766, -766, -766, -766, -766, 0, -766, -766, -766, -766, -766, -766, -766, -766, -766, -766, -766, -766, -766, -766, 0, 0, 0, 0, -766, -766, -766, -766, -766, 0, -766, 0, 0, 0, 0, 0, 0, 0, 0, -766, 0, 0, -766, -766, 0, -766, 0, -766, -766, 0, 0, 0, -766, -766, 0, 0, 0, 0, 0, 0, 0, 0, 0, -766, -766, -766, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 408 - -515, -515, 0, 0, -515, 0, -515, 0, -515, 0, 0, -515, -515, 0, -515, -515, 0, -515, 0, 0, 0, 0, 0, -515, -515, -515, 0, -515, 0, 0, -515, 0, -515, 0, 0, 0, 0, -515, 0, 0, -515, 0, 0, 0, 0, -515, 0, -515, -515, -515, 0, -515, 0, 0, 0, 0, 0, 0, 0, 0, -515, 0, 0, -515, -515, 0, -515, 0, 0, 0, 0, 0, 0, 0, -515, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -515, -515, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -516, -516, 0, 0, -516, 0, -516, 0, -516, 0, 0, -516, -516, 0, -516, -516, 0, -516, 0, 0, 0, 0, 0, -516, -516, -516, 0, -516, 0, 0, -516, 0, -516, 0, 0, 0, 0, -516, 0, 0, -516, 0, 0, 0, 0, -516, 0, -516, -516, -516, 0, -516, 0, 0, 0, 0, 0, 0, 0, 0, -516, 0, 0, -516, -516, 0, -516, 0, 0, 0, 0, 0, 0, 0, -516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -516, -516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 409 - -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, 0, -839, 0, -839, -839, -839, -839, -839, 0, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, 0, 0, 0, -839, -839, -839, -839, -839, -839, 0, -839, 0, 0, 0, 0, 0, 0, 0, 0, -839, 0, 0, -839, -839, 0, -839, 0, -839, -839, 0, 0, 0, -839, -839, 0, 0, 0, 0, 0, 0, 0, 0, 0, -839, -839, -839, 0, 0, 0, -839, 0, 0, 0, 0, 0, 0, 0, 0, 0, -839, + -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, 0, -840, 0, -840, -840, -840, -840, -840, 0, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, 0, 0, 0, -840, -840, -840, -840, -840, -840, 0, -840, 0, 0, 0, 0, 0, 0, 0, 0, -840, 0, 0, -840, -840, 0, -840, 0, -840, -840, 0, 0, 0, -840, -840, 0, 0, 0, 0, 0, 0, 0, 0, 0, -840, -840, -840, 0, 0, 0, -840, 0, 0, 0, 0, 0, 0, 0, 0, 0, -840, // State 410 - -861, -861, -861, -861, -861, -861, -861, 0, -861, -861, 0, -861, -861, -861, -861, -861, -861, -861, 0, 0, 0, -861, -861, -861, -861, -861, 0, -861, -861, -861, -861, -861, -861, -861, -861, -861, -861, -861, -861, -861, -861, 0, 0, 0, 0, -861, -861, -861, -861, -861, 0, -861, 0, 0, 0, 0, 0, 0, 0, 0, -861, 0, 0, -861, -861, 0, -861, 0, -861, -861, 0, 0, 0, -861, -861, 0, 0, 0, 0, 0, 0, 0, 0, 0, -861, -861, -861, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -860, -860, -860, -860, -860, -860, -860, 0, -860, -860, 0, -860, -860, -860, -860, -860, -860, -860, 0, 0, 0, -860, -860, -860, -860, -860, 0, -860, -860, -860, -860, -860, -860, -860, -860, -860, -860, -860, -860, -860, -860, 0, 0, 0, 0, -860, -860, -860, -860, -860, 0, -860, 0, 0, 0, 0, 0, 0, 0, 0, -860, 0, 0, -860, -860, 0, -860, 0, -860, -860, 0, 0, 0, -860, -860, 0, 0, 0, 0, 0, 0, 0, 0, 0, -860, -860, -860, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 411 -185, -185, -185, -185, -185, -185, -185, -185, -185, -185, -185, -185, -185, -185, -185, -185, -185, -185, 0, -185, 0, -185, -185, -185, -185, -185, 0, -185, -185, -185, -185, -185, -185, -185, -185, -185, -185, -185, -185, -185, -185, 0, 0, 0, -185, -185, -185, -185, -185, -185, 0, -185, 0, 0, 0, 0, 0, 0, 0, 0, -185, 0, 0, -185, -185, 0, -185, 0, -185, -185, 0, 0, 0, -185, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, -185, -185, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 412 - -866, -866, 0, 0, -866, 0, -866, 0, -866, 0, 0, -866, -866, 0, -866, -866, 0, -866, 0, 0, 0, 0, 0, -866, -866, -866, 0, -866, 0, 0, -866, 0, -866, 0, 0, 0, 0, -866, 0, 0, -866, 0, 0, 0, 0, -866, 0, -866, 0, -866, 0, -866, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -866, -866, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -866, -866, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -865, -865, 0, 0, -865, 0, -865, 0, -865, 0, 0, -865, -865, 0, -865, -865, 0, -865, 0, 0, 0, 0, 0, -865, -865, -865, 0, -865, 0, 0, -865, 0, -865, 0, 0, 0, 0, -865, 0, 0, -865, 0, 0, 0, 0, -865, 0, -865, 0, -865, 0, -865, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -865, -865, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -865, -865, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 413 -159, -159, 0, 0, -159, 0, -159, 0, -159, 0, 0, -159, -159, 0, -159, -159, 0, -159, 0, 0, 0, 0, 0, -159, -159, -159, 0, -159, 0, 0, -159, 0, -159, 0, 0, 0, 0, -159, 0, 0, -159, 0, 0, 0, 0, -159, 0, -159, 454, -159, 0, -159, 0, 0, 0, 0, 0, 0, 0, 0, -159, 0, 0, -159, -159, 0, -159, 0, 0, 0, 0, 0, 0, 0, -159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -159, -159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 414 -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, 0, -184, 0, -184, -184, -184, -184, -184, 0, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, -184, 0, 0, 0, -184, -184, -184, -184, -184, -184, 0, -184, 0, 0, 0, 0, 0, 0, 0, 0, -184, 0, 0, -184, -184, 0, -184, 0, -184, -184, 0, 0, 0, -184, -184, 0, 0, 0, 0, 0, 0, 0, 0, 0, -184, -184, -184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 415 - -427, -427, 0, 0, -427, 0, -427, 0, -427, 0, 0, -427, -427, 0, -427, 32, 0, -427, 0, 0, 0, 0, 0, -427, -427, -427, 0, -427, 0, 0, -427, 0, -427, 0, 0, 0, 0, -427, 0, 0, -427, 0, 0, 0, 0, 0, 0, -427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -427, -427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -427, -427, 0, 0, -427, 0, -427, 0, -427, 0, 0, -427, -427, 0, -427, 33, 0, -427, 0, 0, 0, 0, 0, -427, -427, -427, 0, -427, 0, 0, -427, 0, -427, 0, 0, 0, 0, -427, 0, 0, -427, 0, 0, 0, 0, 0, 0, -427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -427, -427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 416 - -865, -865, 0, 0, -865, 0, -865, 0, -865, 0, 0, -865, -865, 0, -865, -865, 0, -865, 0, 0, 0, 0, 0, -865, -865, -865, 0, -865, 0, 0, -865, 0, -865, 0, 0, 0, 0, -865, 0, 0, -865, 0, 0, 0, 0, -865, 0, -865, 0, -865, 0, -865, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -865, -865, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -865, -865, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -864, -864, 0, 0, -864, 0, -864, 0, -864, 0, 0, -864, -864, 0, -864, -864, 0, -864, 0, 0, 0, 0, 0, -864, -864, -864, 0, -864, 0, 0, -864, 0, -864, 0, 0, 0, 0, -864, 0, 0, -864, 0, 0, 0, 0, -864, 0, -864, 0, -864, 0, -864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -864, -864, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -864, -864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 417 -388, -388, -388, -388, -388, -388, -388, 0, -388, -388, 0, -388, -388, -388, -388, -388, -388, -388, 0, 0, 0, -388, -388, -388, -388, -388, 0, -388, -388, -388, -388, -388, -388, -388, -388, -388, -388, -388, -388, -388, -388, 0, 0, 0, 0, -388, -388, -388, -388, -388, 0, -388, 0, 0, 0, 0, 0, 0, 0, 0, -388, 0, 0, -388, -388, 0, -388, 0, -388, -388, 0, 0, 0, -388, -388, 0, 0, 0, 0, 0, 0, 0, 0, 0, -388, -388, -388, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 418 - -878, -878, 0, 0, -878, 0, -878, 0, -878, 0, 0, -878, -878, 0, -878, -878, 0, -878, 0, 0, 0, 0, 0, -878, -878, -878, 0, -878, 0, 0, -878, 0, -878, 0, 0, 0, 0, -878, 0, 0, -878, 0, 0, 0, 0, 0, 0, -878, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -878, -878, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -877, -877, 0, 0, -877, 0, -877, 0, -877, 0, 0, -877, -877, 0, -877, -877, 0, -877, 0, 0, 0, 0, 0, -877, -877, -877, 0, -877, 0, 0, -877, 0, -877, 0, 0, 0, 0, -877, 0, 0, -877, 0, 0, 0, 0, 0, 0, -877, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -877, -877, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 419 - -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, 0, -838, 0, -838, -838, -838, -838, -838, 0, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, 0, 0, 0, -838, -838, -838, -838, -838, -838, 0, -838, 0, 0, 0, 0, 0, 0, 0, 0, -838, 0, 0, -838, -838, 0, -838, 0, -838, -838, 0, 0, 0, -838, -838, 0, 0, 0, 0, 0, 0, 0, 0, 0, -838, -838, -838, 0, 0, 0, -838, 0, 0, 0, 0, 0, 0, 0, 0, 0, -838, + -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, 0, -183, 0, -183, -183, -183, -183, -183, 0, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, -183, 0, 0, 0, -183, -183, -183, -183, -183, -183, 0, -183, 0, 0, 0, 0, 0, 0, 0, 0, -183, 0, 0, -183, -183, 0, -183, 0, -183, -183, 0, 0, 0, -183, -183, 0, 0, 0, 0, 0, 0, 0, 0, 0, -183, -183, -183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 420 - -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, 0, -840, 0, -840, -840, -840, -840, -840, 0, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, -840, 0, 0, 0, -840, -840, -840, -840, -840, -840, 0, -840, 0, 0, 0, 0, 0, 0, 0, 0, -840, 0, 0, -840, -840, 0, -840, 0, -840, -840, 0, 0, 0, -840, -840, 0, 0, 0, 0, 0, 0, 0, 0, 0, -840, -840, -840, 0, 0, 0, -840, 0, 0, 0, 0, 0, 0, 0, 0, 0, -840, + -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, 0, -839, 0, -839, -839, -839, -839, -839, 0, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, -839, 0, 0, 0, -839, -839, -839, -839, -839, -839, 0, -839, 0, 0, 0, 0, 0, 0, 0, 0, -839, 0, 0, -839, -839, 0, -839, 0, -839, -839, 0, 0, 0, -839, -839, 0, 0, 0, 0, 0, 0, 0, 0, 0, -839, -839, -839, 0, 0, 0, -839, 0, 0, 0, 0, 0, 0, 0, 0, 0, -839, // State 421 - -877, -877, 0, 0, -877, 0, -877, 0, -877, 0, 0, -877, -877, 0, -877, -877, 0, -877, 0, 0, 0, 0, 0, -877, -877, -877, 0, -877, 0, 0, -877, 0, -877, 0, 0, 0, 0, -877, 0, 0, -877, 0, 0, 0, 0, 0, 0, -877, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -877, -877, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -876, -876, 0, 0, -876, 0, -876, 0, -876, 0, 0, -876, -876, 0, -876, -876, 0, -876, 0, 0, 0, 0, 0, -876, -876, -876, 0, -876, 0, 0, -876, 0, -876, 0, 0, 0, 0, -876, 0, 0, -876, 0, 0, 0, 0, 0, 0, -876, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -876, -876, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 422 - -550, -550, 0, 0, -550, 0, -550, 0, -550, 0, 0, -550, -550, 0, -550, -550, 0, -550, 0, 0, 0, 0, 0, -550, -550, -550, 0, -550, 0, 0, -550, 0, -550, 0, 0, 0, 0, -550, 0, 0, -550, 0, 0, 0, 0, 0, 0, -550, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -550, -550, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -551, -551, 0, 0, -551, 0, -551, 0, -551, 0, 0, -551, -551, 0, -551, -551, 0, -551, 0, 0, 0, 0, 0, -551, -551, -551, 0, -551, 0, 0, -551, 0, -551, 0, 0, 0, 0, -551, 0, 0, -551, 0, 0, 0, 0, 0, 0, -551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -551, -551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 423 - -349, -349, -349, 0, -349, 0, -349, 0, -349, 0, 0, -349, -349, 0, -349, -349, 0, -349, 0, 0, 0, 0, 0, -349, -349, -349, 0, -349, -349, 0, -349, -349, -349, -349, -349, -349, 0, -349, -349, 0, -349, 0, 0, 0, 0, -349, 36, -349, -349, -349, 0, -349, 0, 0, 0, 0, 0, 0, 0, 0, -349, 0, 0, -349, -349, 0, -349, 0, -349, -349, 0, 0, 0, -349, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, -349, -349, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -349, -349, -349, 0, -349, 0, -349, 0, -349, 0, 0, -349, -349, 0, -349, -349, 0, -349, 0, 0, 0, 0, 0, -349, -349, -349, 0, -349, -349, 0, -349, -349, -349, -349, -349, -349, 0, -349, -349, 0, -349, 0, 0, 0, 0, -349, 37, -349, -349, -349, 0, -349, 0, 0, 0, 0, 0, 0, 0, 0, -349, 0, 0, -349, -349, 0, -349, 0, -349, -349, 0, 0, 0, -349, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, -349, -349, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 424 - 0, 0, 0, 0, 0, 0, 0, -915, 0, 0, 0, 0, 0, -915, 0, 0, -915, 0, 0, 0, -915, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -915, -915, -915, -915, 0, 0, 0, 0, 0, 0, 0, -915, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -915, 0, 0, 0, -915, 0, 0, -915, 0, 0, 0, -915, -915, 0, -915, 0, -915, -915, + 0, 0, 0, 0, 0, 0, 0, -918, 0, 0, 0, 0, 0, -918, 0, 0, -918, 0, 0, 0, -918, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -918, -918, -918, -918, 0, 0, 0, 0, 0, 0, 0, -918, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -918, 0, 0, 0, -918, 0, 0, -918, 0, 0, 0, -918, -918, 0, -918, 0, -918, -918, // State 425 - 0, 0, 0, 0, 0, 0, 0, -916, 0, 0, 0, 0, 0, -916, 0, 0, -916, 0, 0, 0, -916, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -916, -916, -916, -916, 0, 0, 0, 0, 0, 0, 0, -916, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -916, 0, 0, 0, -916, 0, 0, -916, 0, 0, 0, -916, -916, 0, -916, 0, -916, -916, + 0, 0, 0, 0, 0, 0, 0, -919, 0, 0, 0, 0, 0, -919, 0, 0, -919, 0, 0, 0, -919, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -919, -919, -919, -919, 0, 0, 0, 0, 0, 0, 0, -919, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -919, 0, 0, 0, -919, 0, 0, -919, 0, 0, 0, -919, -919, 0, -919, 0, -919, -919, // State 426 -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, 0, -211, 0, -211, -211, -211, -211, -211, 0, -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, 0, 0, 0, -211, -211, -211, -211, -211, -211, 0, -211, 0, 0, 0, 0, 0, 0, 0, 0, -211, 0, 0, -211, -211, 0, -211, 0, -211, -211, 0, 0, 0, -211, -211, 0, 0, 0, 0, 0, 0, 0, 0, 0, -211, -211, -211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 427 @@ -1012,21 +1012,21 @@ mod __parse__Top { // State 429 -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, 0, -208, 0, -208, -208, -208, -208, -208, 0, -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, -208, 0, 0, 0, -208, -208, -208, -208, -208, -208, 0, -208, 0, 0, 0, 0, 0, 0, 0, 0, -208, 0, 0, -208, -208, 0, -208, 0, -208, -208, 0, 0, 0, -208, -208, 0, 0, 0, 0, 0, 0, 0, 0, 0, -208, -208, -208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 430 - 0, 0, 0, 0, 0, 0, 0, -917, 0, 0, 0, 0, 0, -917, 0, 0, -917, 0, 0, 0, -917, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -917, -917, -917, -917, 0, 0, 0, 0, 0, 0, 0, -917, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -917, 0, 0, 0, -917, 0, 0, -917, 0, 0, 0, -917, -917, 0, -917, 0, -917, -917, + 0, 0, 0, 0, 0, 0, 0, -920, 0, 0, 0, 0, 0, -920, 0, 0, -920, 0, 0, 0, -920, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -920, -920, -920, -920, 0, 0, 0, 0, 0, 0, 0, -920, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -920, 0, 0, 0, -920, 0, 0, -920, 0, 0, 0, -920, -920, 0, -920, 0, -920, -920, // State 431 - -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, 0, -520, 0, -520, -520, -520, -520, -520, 0, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, 0, 0, 0, -520, -520, -520, -520, -520, -520, 0, -520, 0, 0, 0, 0, 0, 0, 0, 0, -520, 0, 0, -520, -520, 0, -520, 0, -520, -520, 0, 0, 0, -520, -520, 0, 0, 0, 0, 0, 0, 0, 0, 0, -520, -520, -520, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -521, -521, -521, -521, -521, -521, -521, -521, -521, -521, -521, -521, -521, -521, -521, -521, -521, -521, 0, -521, 0, -521, -521, -521, -521, -521, 0, -521, -521, -521, -521, -521, -521, -521, -521, -521, -521, -521, -521, -521, -521, 0, 0, 0, -521, -521, -521, -521, -521, -521, 0, -521, 0, 0, 0, 0, 0, 0, 0, 0, -521, 0, 0, -521, -521, 0, -521, 0, -521, -521, 0, 0, 0, -521, -521, 0, 0, 0, 0, 0, 0, 0, 0, 0, -521, -521, -521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 432 - -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, 0, -519, 0, -519, -519, -519, -519, -519, 0, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, 0, 0, 0, -519, -519, -519, -519, -519, -519, 0, -519, 0, 0, 0, 0, 0, 0, 0, 0, -519, 0, 0, -519, -519, 0, -519, 0, -519, -519, 0, 0, 0, -519, -519, 0, 0, 0, 0, 0, 0, 0, 0, 0, -519, -519, -519, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, 0, -520, 0, -520, -520, -520, -520, -520, 0, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, -520, 0, 0, 0, -520, -520, -520, -520, -520, -520, 0, -520, 0, 0, 0, 0, 0, 0, 0, 0, -520, 0, 0, -520, -520, 0, -520, 0, -520, -520, 0, 0, 0, -520, -520, 0, 0, 0, 0, 0, 0, 0, 0, 0, -520, -520, -520, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 433 - -518, -518, -518, -518, -518, -518, -518, -518, -518, -518, -518, -518, -518, -518, -518, -518, -518, -518, 0, -518, 0, -518, -518, -518, -518, -518, 0, -518, -518, -518, -518, -518, -518, -518, -518, -518, -518, -518, -518, -518, -518, 0, 0, 0, -518, -518, -518, -518, -518, -518, 0, -518, 0, 0, 0, 0, 0, 0, 0, 0, -518, 0, 0, -518, -518, 0, -518, 0, -518, -518, 0, 0, 0, -518, -518, 0, 0, 0, 0, 0, 0, 0, 0, 0, -518, -518, -518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, 0, -519, 0, -519, -519, -519, -519, -519, 0, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, -519, 0, 0, 0, -519, -519, -519, -519, -519, -519, 0, -519, 0, 0, 0, 0, 0, 0, 0, 0, -519, 0, 0, -519, -519, 0, -519, 0, -519, -519, 0, 0, 0, -519, -519, 0, 0, 0, 0, 0, 0, 0, 0, 0, -519, -519, -519, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 434 -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, 0, -430, 0, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, -430, 0, 0, 0, -430, -430, -430, -430, -430, -430, 0, -430, 0, 0, 0, 0, 0, 0, 0, 0, -430, 0, 0, -430, -430, 0, -430, -430, -430, -430, 0, 0, 0, -430, -430, 0, 0, 0, 0, 0, 0, 0, 0, 0, -430, -430, -430, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 435 - -835, -835, -835, -835, -835, -835, -835, -835, -835, -835, -835, -835, -835, -835, -835, -835, -835, -835, 0, -835, 0, -835, -835, -835, -835, -835, 0, -835, -835, -835, -835, -835, -835, -835, -835, -835, -835, -835, -835, -835, -835, 0, 0, 0, -835, -835, -835, -835, -835, -835, 0, -835, 0, 0, 0, 0, 0, 0, 0, 0, -835, 0, 0, -835, -835, 0, -835, 0, -835, -835, 0, 0, 0, -835, -835, 0, 0, 0, 0, 0, 0, 0, 0, 0, -835, -835, -835, 0, 0, 0, -835, 0, 0, 0, 0, 0, 0, 0, 0, 0, -835, + -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, 0, -838, 0, -838, -838, -838, -838, -838, 0, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, -838, 0, 0, 0, -838, -838, -838, -838, -838, -838, 0, -838, 0, 0, 0, 0, 0, 0, 0, 0, -838, 0, 0, -838, -838, 0, -838, 0, -838, -838, 0, 0, 0, -838, -838, 0, 0, 0, 0, 0, 0, 0, 0, 0, -838, -838, -838, 0, 0, 0, -838, 0, 0, 0, 0, 0, 0, 0, 0, 0, -838, // State 436 - -558, -558, 0, 0, -558, 0, -558, 0, -558, 0, 0, -558, -558, 0, -558, -558, 0, -558, 0, 0, 0, 0, 0, -558, -558, -558, 0, -558, 0, 0, -558, 0, -558, 0, 0, 0, 0, -558, 0, 0, -558, 0, 0, 0, 0, -558, 0, -558, 0, -558, 0, -558, 0, 0, 0, 0, 0, 0, 0, 0, -558, 0, 0, -558, -558, 0, -558, 0, 0, 0, 0, 0, 0, 0, 531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -558, -558, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -559, -559, 0, 0, -559, 0, -559, 0, -559, 0, 0, -559, -559, 0, -559, -559, 0, -559, 0, 0, 0, 0, 0, -559, -559, -559, 0, -559, 0, 0, -559, 0, -559, 0, 0, 0, 0, -559, 0, 0, -559, 0, 0, 0, 0, -559, 0, -559, 0, -559, 0, -559, 0, 0, 0, 0, 0, 0, 0, 0, -559, 0, 0, -559, -559, 0, -559, 0, 0, 0, 0, 0, 0, 0, 532, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -559, -559, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 437 - -158, -158, 0, 0, -158, 0, -158, 0, -158, 0, 0, -158, -158, 0, -158, -158, 0, -158, 0, 0, 0, 0, 0, -158, -158, -158, 0, -158, 0, 0, -158, 0, -158, 0, 0, 0, 0, -158, 0, 0, -158, 0, 0, 0, 0, -158, 0, -158, 532, -158, 0, -158, 0, 0, 0, 0, 0, 0, 0, 0, -158, 0, 0, -158, -158, 0, -158, 0, 0, 0, 0, 0, 0, 0, -158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -158, -158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -158, -158, 0, 0, -158, 0, -158, 0, -158, 0, 0, -158, -158, 0, -158, -158, 0, -158, 0, 0, 0, 0, 0, -158, -158, -158, 0, -158, 0, 0, -158, 0, -158, 0, 0, 0, 0, -158, 0, 0, -158, 0, 0, 0, 0, -158, 0, -158, 533, -158, 0, -158, 0, 0, 0, 0, 0, 0, 0, 0, -158, 0, 0, -158, -158, 0, -158, 0, 0, 0, 0, 0, 0, 0, -158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -158, -158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 438 0, 0, 0, 0, 0, 0, 0, -113, 0, 0, 0, 0, 0, -113, 0, 0, -113, 0, 0, 0, -113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -113, -113, -113, -113, 0, 0, 0, 0, 0, 0, 0, -113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -113, 0, 0, 0, 0, 0, 0, 0, 0, 0, -113, 0, 0, 0, -113, 0, 0, -113, 0, 0, 0, -113, -113, 0, -113, 0, -113, -113, // State 439 @@ -1050,1481 +1050,1487 @@ mod __parse__Top { // State 448 0, 0, 0, 0, 0, 0, 0, -299, 0, 0, 0, 0, 0, -299, 0, 0, -299, 0, 0, 0, -299, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -299, -299, -299, -299, 0, 0, 0, 0, 0, 0, 0, -299, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -299, 0, 0, 0, -299, 0, 0, -299, 0, 0, 0, -299, -299, 0, -299, 0, -299, -299, // State 449 - 0, 0, 0, 0, 0, 0, 0, -301, 0, 0, 0, 0, 0, -301, 0, 0, -301, 0, 0, 0, -301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -301, -301, -301, -301, 0, 0, 0, 0, 0, 0, 0, -301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 544, 0, 0, 0, 0, 0, 0, 0, 0, 0, -301, 0, 0, 0, -301, 0, 0, -301, 0, 0, 0, -301, -301, 0, -301, 0, -301, -301, + 0, 0, 0, 0, 0, 0, 0, -301, 0, 0, 0, 0, 0, -301, 0, 0, -301, 0, 0, 0, -301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -301, -301, -301, -301, 0, 0, 0, 0, 0, 0, 0, -301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 545, 0, 0, 0, 0, 0, 0, 0, 0, 0, -301, 0, 0, 0, -301, 0, 0, -301, 0, 0, 0, -301, -301, 0, -301, 0, -301, -301, // State 450 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 545, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 546, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 451 - 547, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 452 -90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 453 0, 0, 0, 0, 0, 0, 0, -121, 0, 0, 0, 0, 0, -121, 0, 0, -121, 0, 0, 0, -121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -121, -121, -121, -121, 0, 0, 0, 0, 0, 0, 0, -121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -121, 0, 0, 0, 0, 0, 0, 0, 0, 0, -121, 0, 0, 0, -121, 0, 0, -121, 0, 0, 0, -121, -121, 0, -121, 0, -121, -121, // State 454 - 0, 0, 0, 0, 0, 0, 0, -793, 0, 0, 0, 0, 0, -793, 0, 0, -793, 0, 0, 0, -793, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -793, -793, -793, -793, 0, 0, 0, 0, 0, 0, 0, -793, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -793, 0, 0, 0, -793, 0, 0, -793, 0, 0, 0, -793, -793, 0, -793, 0, -793, -793, - // State 455 0, 0, 0, 0, 0, 0, 0, -794, 0, 0, 0, 0, 0, -794, 0, 0, -794, 0, 0, 0, -794, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -794, -794, -794, -794, 0, 0, 0, 0, 0, 0, 0, -794, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -794, 0, 0, 0, -794, 0, 0, -794, 0, 0, 0, -794, -794, 0, -794, 0, -794, -794, + // State 455 + 0, 0, 0, 0, 0, 0, 0, -795, 0, 0, 0, 0, 0, -795, 0, 0, -795, 0, 0, 0, -795, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -795, -795, -795, -795, 0, 0, 0, 0, 0, 0, 0, -795, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -795, 0, 0, 0, -795, 0, 0, -795, 0, 0, 0, -795, -795, 0, -795, 0, -795, -795, // State 456 - -841, -841, -841, -841, -841, -841, -841, -841, -841, -841, -841, -841, -841, -841, -841, -841, -841, -841, 0, -841, 0, -841, -841, -841, -841, -841, 0, -841, -841, -841, -841, -841, -841, -841, -841, -841, -841, -841, -841, -841, -841, 0, 0, 0, -841, -841, -841, -841, -841, -841, 0, -841, 0, 0, 0, 0, 0, 0, 0, 0, -841, 0, 0, -841, -841, 0, -841, 0, -841, -841, 0, 0, 0, -841, -841, 0, 0, 0, 0, 0, 0, 0, 0, 0, -841, -841, -841, 0, 0, 0, -841, 0, 0, 0, 0, 0, 0, 0, 0, 0, -841, + -895, -895, -895, -895, -895, -895, -895, -895, -895, -895, -895, -895, -895, -895, -895, -895, -895, -895, 0, -895, 0, -895, -895, -895, -895, -895, 0, -895, -895, -895, -895, -895, -895, -895, -895, -895, -895, -895, -895, -895, -895, 0, 0, 0, -895, -895, -895, -895, -895, -895, 0, -895, 0, 0, 0, 0, 0, 0, 0, 0, -895, 0, 0, -895, -895, 0, -895, 0, -895, -895, 0, 0, 0, -895, -895, 0, 0, 0, 0, 0, 0, 0, 0, 0, -895, -895, -895, 0, 0, 0, -895, 0, 0, 0, 0, 0, 0, 0, 0, 0, -895, // State 457 - 0, 0, 0, 0, 0, 0, 0, -505, 0, 0, 0, 0, 0, -505, 0, 0, -505, 0, 0, 0, -505, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -505, -505, -505, -505, 0, 0, 0, 0, 0, 0, 0, -505, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -505, 0, 0, 0, -505, 0, 0, -505, 0, 0, 0, -505, -505, 0, -505, 0, -505, -505, + 0, 0, 0, 0, 0, 0, 0, -506, 0, 0, 0, 0, 0, -506, 0, 0, -506, 0, 0, 0, -506, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -506, -506, -506, -506, 0, 0, 0, 0, 0, 0, 0, -506, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -506, 0, 0, 0, -506, 0, 0, -506, 0, 0, 0, -506, -506, 0, -506, 0, -506, -506, // State 458 - 0, 0, 0, 0, 0, 0, 0, -502, 0, 0, 0, 0, 0, -502, 0, 0, -502, 0, 0, 0, -502, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -502, -502, -502, -502, 0, 0, 0, 0, 0, 0, 0, -502, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -502, 0, 0, 0, -502, 0, 0, -502, 0, 0, 0, -502, -502, 0, -502, 0, -502, -502, - // State 459 0, 0, 0, 0, 0, 0, 0, -503, 0, 0, 0, 0, 0, -503, 0, 0, -503, 0, 0, 0, -503, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -503, -503, -503, -503, 0, 0, 0, 0, 0, 0, 0, -503, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -503, 0, 0, 0, -503, 0, 0, -503, 0, 0, 0, -503, -503, 0, -503, 0, -503, -503, - // State 460 + // State 459 0, 0, 0, 0, 0, 0, 0, -504, 0, 0, 0, 0, 0, -504, 0, 0, -504, 0, 0, 0, -504, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -504, -504, -504, -504, 0, 0, 0, 0, 0, 0, 0, -504, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -504, 0, 0, 0, -504, 0, 0, -504, 0, 0, 0, -504, -504, 0, -504, 0, -504, -504, + // State 460 + 0, 0, 0, 0, 0, 0, 0, -505, 0, 0, 0, 0, 0, -505, 0, 0, -505, 0, 0, 0, -505, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -505, -505, -505, -505, 0, 0, 0, 0, 0, 0, 0, -505, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -505, 0, 0, 0, -505, 0, 0, -505, 0, 0, 0, -505, -505, 0, -505, 0, -505, -505, // State 461 - 0, 0, 0, 0, 0, 0, 0, -506, 0, 0, 0, 0, 0, -506, 0, 0, -506, 0, 0, 0, -506, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -506, -506, -506, -506, 0, 0, 0, 0, 0, 0, 0, -506, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -506, 0, 0, 0, -506, 0, 0, -506, 0, 0, 0, -506, -506, 0, -506, 0, -506, -506, + 0, 0, 0, 0, 0, 0, 0, -507, 0, 0, 0, 0, 0, -507, 0, 0, -507, 0, 0, 0, -507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -507, -507, -507, -507, 0, 0, 0, 0, 0, 0, 0, -507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -507, 0, 0, 0, -507, 0, 0, -507, 0, 0, 0, -507, -507, 0, -507, 0, -507, -507, // State 462 - -387, -387, -387, -387, -387, -387, -387, 0, -387, -387, 0, -387, -387, -387, -387, -387, -387, -387, 0, 0, 0, -387, -387, -387, -387, -387, 0, -387, -387, -387, -387, -387, -387, -387, -387, -387, -387, -387, -387, -387, -387, 0, 0, 0, 0, -387, -387, -387, -387, -387, 0, -387, 0, 0, 0, 0, 0, 0, 0, 0, -387, 0, 0, -387, -387, 0, -387, 0, -387, -387, 0, 0, 0, -387, -387, 0, 0, 0, 0, 0, 0, 0, 0, 0, -387, -387, -387, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -896, -896, -896, -896, -896, -896, -896, -896, -896, -896, -896, -896, -896, -896, -896, -896, -896, -896, 0, -896, 0, -896, -896, -896, -896, -896, 0, -896, -896, -896, -896, -896, -896, -896, -896, -896, -896, -896, -896, -896, -896, 0, 0, 0, -896, -896, -896, -896, -896, -896, 0, -896, 0, 0, 0, 0, 0, 0, 0, 0, -896, 0, 0, -896, -896, 0, -896, 0, -896, -896, 0, 0, 0, -896, -896, 0, 0, 0, 0, 0, 0, 0, 0, 0, -896, -896, -896, 0, 0, 0, -896, 0, 0, 0, 0, 0, 0, 0, 0, 0, -896, // State 463 - -185, 0, -185, -185, 0, -185, 0, -185, -185, -185, -185, 0, 0, -185, 0, -185, -185, 0, 0, -185, 0, -185, -185, 0, 0, -185, -508, 0, -185, -185, 0, -185, 0, -185, -185, -185, -185, 0, 0, -185, 0, 0, 0, 0, -185, -185, -185, 0, -185, -185, 0, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -185, 0, 0, -185, 0, -185, -185, 0, 0, 0, -185, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, -185, 0, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -387, -387, -387, -387, -387, -387, -387, 0, -387, -387, 0, -387, -387, -387, -387, -387, -387, -387, 0, 0, 0, -387, -387, -387, -387, -387, 0, -387, -387, -387, -387, -387, -387, -387, -387, -387, -387, -387, -387, -387, -387, 0, 0, 0, 0, -387, -387, -387, -387, -387, 0, -387, 0, 0, 0, 0, 0, 0, 0, 0, -387, 0, 0, -387, -387, 0, -387, 0, -387, -387, 0, 0, 0, -387, -387, 0, 0, 0, 0, 0, 0, 0, 0, 0, -387, -387, -387, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 464 - 0, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -509, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -509, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -185, 0, -185, -185, 0, -185, 0, -185, -185, -185, -185, 0, 0, -185, 0, -185, -185, 0, 0, -185, 0, -185, -185, 0, 0, -185, -509, 0, -185, -185, 0, -185, 0, -185, -185, -185, -185, 0, 0, -185, 0, 0, 0, 0, -185, -185, -185, 0, -185, -185, 0, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -185, 0, 0, -185, 0, -185, -185, 0, 0, 0, -185, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, -185, 0, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 465 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -512, 0, 0, 0, 0, 0, 0, -512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 466 - 0, 0, 0, 0, 0, 0, 0, 0, 557, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 467 - 0, 0, 0, 0, 0, 0, 0, 0, -512, 0, 0, 0, 0, 0, 0, -512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 558, 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 468 - 0, 0, 0, 0, 0, 0, 0, 0, -548, 0, 0, 0, 0, 0, 0, -548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -513, 0, 0, 0, 0, 0, 0, -513, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 469 - 0, 0, 0, 0, 0, 0, 0, 0, 558, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -549, 0, 0, 0, 0, 0, 0, -549, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 470 - -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, 0, -199, 0, -199, -199, -199, -199, -199, 0, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, 0, 0, 0, -199, -199, -199, -199, -199, -199, 0, -199, 0, 0, 0, 0, 0, 0, 0, 0, -199, 0, 0, -199, -199, 0, -199, 0, -199, -199, 0, 0, 0, -199, -199, 0, 0, 0, 0, 0, 0, 0, 0, 0, -199, -199, -199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 559, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 471 - -816, -816, 0, 0, -816, 0, -816, 0, -816, 0, 0, -816, -816, 0, -816, -816, 0, -816, 0, 0, 0, 0, 0, -816, -816, -816, 0, -816, 0, 0, -816, 0, -816, 0, 0, 0, 0, -816, 0, 0, -816, 0, 0, 0, 0, -816, 0, -816, 0, 0, 0, -816, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -816, 0, 0, 0, 0, -816, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, -816, -816, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, 0, -199, 0, -199, -199, -199, -199, -199, 0, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, -199, 0, 0, 0, -199, -199, -199, -199, -199, -199, 0, -199, 0, 0, 0, 0, 0, 0, 0, 0, -199, 0, 0, -199, -199, 0, -199, 0, -199, -199, 0, 0, 0, -199, -199, 0, 0, 0, 0, 0, 0, 0, 0, 0, -199, -199, -199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 472 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 561, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -817, -817, 0, 0, -817, 0, -817, 0, -817, 0, 0, -817, -817, 0, -817, -817, 0, -817, 0, 0, 0, 0, 0, -817, -817, -817, 0, -817, 0, 0, -817, 0, -817, 0, 0, 0, 0, -817, 0, 0, -817, 0, 0, 0, 0, -817, 0, -817, 0, 0, 0, -817, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -817, 0, 0, 0, 0, -817, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, -817, -817, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 473 - -509, 0, 0, 0, 0, 0, 0, 0, -509, 0, 0, 0, 0, 0, 0, -509, 0, 0, 0, 0, 0, 0, 0, 0, 0, -509, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -509, 0, 0, 0, 0, 0, -509, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -509, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -509, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 562, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 474 - 0, 0, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -510, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 475 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -466, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -879, 0, 0, 0, 0, 0, 0, -879, 0, 0, 0, 0, 0, 0, 0, 0, 0, -879, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -879, 0, 0, 0, 0, 0, -879, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -879, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -879, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 476 - 0, 0, 0, 0, 0, 0, 0, 0, -881, 0, 0, 0, 0, 0, 0, -881, 0, 0, 0, 0, 0, 0, 0, 0, 0, -881, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -881, 0, 0, 0, 0, 0, -881, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -881, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -881, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -466, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 477 - -510, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -880, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 478 - -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, 0, -187, 0, -187, -187, -187, -187, -187, 0, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, 0, 0, 0, -187, -187, -187, -187, -187, -187, 0, -187, 0, 0, 0, 0, 0, 0, 0, 0, -187, 0, 0, -187, -187, 0, -187, 0, -187, -187, 0, 0, 0, -187, -187, 0, 0, 0, 0, 0, 0, 0, 0, 0, -187, -187, -187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -511, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 479 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -918, 0, 0, 0, 0, 0, 0, 0, 0, 0, -918, 0, 0, 0, 0, 0, 0, -918, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, 0, -187, 0, -187, -187, -187, -187, -187, 0, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, -187, 0, 0, 0, -187, -187, -187, -187, -187, -187, 0, -187, 0, 0, 0, 0, 0, 0, 0, 0, -187, 0, 0, -187, -187, 0, -187, 0, -187, -187, 0, 0, 0, -187, -187, 0, 0, 0, 0, 0, 0, 0, 0, 0, -187, -187, -187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 480 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 563, 0, 0, 0, 0, 0, 0, 0, 0, 0, -727, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -921, 0, 0, 0, 0, 0, 0, 0, 0, 0, -921, 0, 0, 0, 0, 0, 0, -921, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 481 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, -701, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 564, 0, 0, 0, 0, 0, 0, 0, 0, 0, -728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 482 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -544, 0, 0, 0, 0, 0, 0, 0, 0, 0, -544, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, -702, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 483 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -545, 0, 0, 0, 0, 0, 0, 0, 0, 0, -545, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 484 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -564, 0, 0, 0, 0, 0, 0, 0, 0, 0, -564, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 485 - -514, -514, 0, 0, -514, 0, -514, 0, -514, 0, 0, -514, -514, 0, -514, -514, 0, -514, 0, 0, 0, 0, 0, -514, -514, -514, 0, -514, 0, 0, -514, 0, -514, 0, 0, 0, 0, -514, 0, 0, -514, 0, 0, 0, 0, -514, 0, -514, -514, -514, 0, -514, 0, 0, 0, 0, 0, 0, 0, 0, -514, 0, 0, -514, -514, 0, -514, 0, 0, 0, 0, 0, 0, 0, -514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -514, -514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -565, 0, 0, 0, 0, 0, 0, 0, 0, 0, -565, 0, 0, 0, 0, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 486 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -524, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -524, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -515, -515, 0, 0, -515, 0, -515, 0, -515, 0, 0, -515, -515, 0, -515, -515, 0, -515, 0, 0, 0, 0, 0, -515, -515, -515, 0, -515, 0, 0, -515, 0, -515, 0, 0, 0, 0, -515, 0, 0, -515, 0, 0, 0, 0, -515, 0, -515, -515, -515, 0, -515, 0, 0, 0, 0, 0, 0, 0, 0, -515, 0, 0, -515, -515, 0, -515, 0, 0, 0, 0, 0, 0, 0, -515, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -515, -515, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 487 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 569, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -525, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -525, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 488 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 570, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 489 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -788, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 490 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 571, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -789, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 491 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 572, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 492 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -552, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -552, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 493 - -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, 0, -204, 0, -204, -204, -204, -204, -204, 0, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, 0, 0, 0, -204, -204, -204, -204, -204, -204, 0, -204, 0, 0, 0, 0, 0, 0, 0, 0, -204, 0, 0, -204, -204, 0, -204, 0, -204, -204, 0, 0, 0, -204, -204, 0, 0, 0, 0, 0, 0, 0, 0, 0, -204, -204, -204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -553, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -553, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 494 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -377, 0, 0, -377, 0, 0, -377, 0, 0, 0, 0, 0, 0, -377, 0, 0, 0, 0, + -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, 0, -204, 0, -204, -204, -204, -204, -204, 0, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, -204, 0, 0, 0, -204, -204, -204, -204, -204, -204, 0, -204, 0, 0, 0, 0, 0, 0, 0, 0, -204, 0, 0, -204, -204, 0, -204, 0, -204, -204, 0, 0, 0, -204, -204, 0, 0, 0, 0, 0, 0, 0, 0, 0, -204, -204, -204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 495 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -373, 0, 0, -373, 0, 0, -373, 0, 0, 0, 0, 0, 0, -373, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -377, 0, 0, -377, 0, 0, -377, 0, 0, 0, 0, 0, 0, -377, 0, 0, 0, 0, // State 496 - -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, 0, -366, 0, -366, -366, -366, -366, -366, 0, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, 0, 0, 0, -366, -366, -366, -366, -366, -366, 0, -366, 0, 0, 0, 0, 0, 0, 0, 0, -366, 0, 0, -366, -366, 0, -366, 0, -366, -366, 0, 0, 0, -366, -366, 0, 0, 0, 0, 0, 0, 0, 0, 0, -366, -366, -366, 0, 0, 0, -366, 0, 0, 0, 0, 0, 0, 0, 0, 0, -366, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -373, 0, 0, -373, 0, 0, -373, 0, 0, 0, 0, 0, 0, -373, 0, 0, 0, 0, // State 497 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -374, 0, 0, -374, 0, 0, -374, 0, 0, 0, 0, 0, 0, -374, 0, 0, 0, 0, + -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, 0, -366, 0, -366, -366, -366, -366, -366, 0, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, -366, 0, 0, 0, -366, -366, -366, -366, -366, -366, 0, -366, 0, 0, 0, 0, 0, 0, 0, 0, -366, 0, 0, -366, -366, 0, -366, 0, -366, -366, 0, 0, 0, -366, -366, 0, 0, 0, 0, 0, 0, 0, 0, 0, -366, -366, -366, 0, 0, 0, -366, 0, 0, 0, 0, 0, 0, 0, 0, 0, -366, // State 498 - -812, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -812, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -374, 0, 0, -374, 0, 0, -374, 0, 0, 0, 0, 0, 0, -374, 0, 0, 0, 0, // State 499 - -314, 0, 0, 0, 0, 0, 0, -314, 0, -314, 0, 0, 0, -314, 0, 0, -314, 0, 0, 0, -314, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -314, 0, -314, -314, -314, -314, 0, 0, 0, 0, 0, -314, -314, -314, -314, 0, -314, -314, -314, -314, 0, 0, 0, 0, -314, -314, -314, -314, -314, 0, 0, -314, -314, -314, -314, 0, -314, -314, -314, -314, -314, -314, -314, -314, -314, 0, 0, 0, -314, -314, 0, -314, 0, 0, 0, -314, -314, 0, -314, -314, -314, -314, + -813, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -813, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 500 - -769, 0, 0, 0, 0, 0, 0, -769, 0, -769, 0, 0, 0, -769, 0, 0, -769, 0, 0, 0, -769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -769, 0, -769, -769, -769, -769, 0, 0, 0, 0, 0, -769, -769, -769, -769, 0, -769, -769, -769, -769, 0, 0, 0, 0, -769, -769, -769, -769, -769, 0, 0, -769, -769, -769, -769, 0, -769, -769, -769, -769, -769, -769, -769, -769, -769, 0, 0, 0, -769, 0, 0, -769, 0, 0, 0, -769, -769, 0, -769, -769, -769, -769, + -314, 0, 0, 0, 0, 0, 0, -314, 0, -314, 0, 0, 0, -314, 0, 0, -314, 0, 0, 0, -314, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -314, 0, -314, -314, -314, -314, 0, 0, 0, 0, 0, -314, -314, -314, -314, 0, -314, -314, -314, -314, 0, 0, 0, 0, -314, -314, -314, -314, -314, 0, 0, -314, -314, -314, -314, 0, -314, -314, -314, -314, -314, -314, -314, -314, -314, 0, 0, 0, -314, -314, 0, -314, 0, 0, 0, -314, -314, 0, -314, -314, -314, -314, // State 501 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -323, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -323, 0, 0, 0, -323, 0, -323, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -770, 0, 0, 0, 0, 0, 0, -770, 0, -770, 0, 0, 0, -770, 0, 0, -770, 0, 0, 0, -770, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -770, 0, -770, -770, -770, -770, 0, 0, 0, 0, 0, -770, -770, -770, -770, 0, -770, -770, -770, -770, 0, 0, 0, 0, -770, -770, -770, -770, -770, 0, 0, -770, -770, -770, -770, 0, -770, -770, -770, -770, -770, -770, -770, -770, -770, 0, 0, 0, -770, 0, 0, -770, 0, 0, 0, -770, -770, 0, -770, -770, -770, -770, // State 502 - -807, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -807, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -323, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -323, 0, 0, 0, -323, 0, -323, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 503 - -805, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -805, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - // State 504 -808, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -808, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 504 + -806, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -806, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 505 - -310, 0, 0, 0, 0, 0, 0, -310, 0, -310, 0, 0, 0, -310, 0, 0, -310, 0, 0, 0, -310, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -310, 0, -310, -310, -310, -310, 0, 0, 0, 0, 0, -310, -310, -310, -310, 0, -310, -310, -310, -310, 0, 0, 0, 0, -310, -310, -310, -310, -310, 0, 0, -310, -310, -310, -310, 0, -310, -310, -310, -310, -310, -310, -310, -310, -310, 0, 0, 0, -310, -310, 0, -310, 0, 0, 0, -310, -310, 0, -310, -310, -310, -310, + -809, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -809, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 506 - -313, 0, 0, 0, 0, 0, 0, -313, 0, -313, 0, 0, 0, -313, 0, 0, -313, 0, 0, 0, -313, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -313, 0, -313, -313, -313, -313, 0, 0, 0, 0, 0, -313, -313, -313, -313, 0, -313, -313, -313, -313, 0, 0, 0, 0, -313, -313, -313, -313, -313, 0, 0, -313, -313, -313, -313, 0, -313, -313, -313, -313, -313, -313, -313, -313, -313, 0, 0, 0, -313, -313, 0, -313, 0, 0, 0, -313, -313, 0, -313, -313, -313, -313, + -310, 0, 0, 0, 0, 0, 0, -310, 0, -310, 0, 0, 0, -310, 0, 0, -310, 0, 0, 0, -310, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -310, 0, -310, -310, -310, -310, 0, 0, 0, 0, 0, -310, -310, -310, -310, 0, -310, -310, -310, -310, 0, 0, 0, 0, -310, -310, -310, -310, -310, 0, 0, -310, -310, -310, -310, 0, -310, -310, -310, -310, -310, -310, -310, -310, -310, 0, 0, 0, -310, -310, 0, -310, 0, 0, 0, -310, -310, 0, -310, -310, -310, -310, // State 507 - -810, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -810, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -313, 0, 0, 0, 0, 0, 0, -313, 0, -313, 0, 0, 0, -313, 0, 0, -313, 0, 0, 0, -313, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -313, 0, -313, -313, -313, -313, 0, 0, 0, 0, 0, -313, -313, -313, -313, 0, -313, -313, -313, -313, 0, 0, 0, 0, -313, -313, -313, -313, -313, 0, 0, -313, -313, -313, -313, 0, -313, -313, -313, -313, -313, -313, -313, -313, -313, 0, 0, 0, -313, -313, 0, -313, 0, 0, 0, -313, -313, 0, -313, -313, -313, -313, // State 508 - -308, 0, 0, 0, 0, 0, 0, -308, 0, -308, 0, 0, 0, -308, 0, 0, -308, 0, 0, 0, -308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -308, 0, -308, -308, -308, -308, 0, 0, 0, 0, 0, -308, -308, -308, -308, 0, -308, -308, -308, -308, 0, 0, 0, 0, -308, -308, -308, -308, -308, 0, 0, -308, -308, -308, -308, 0, -308, -308, -308, -308, -308, -308, -308, -308, -308, 0, 0, 0, -308, -308, 0, -308, 0, 0, 0, -308, -308, 0, -308, -308, -308, -308, + -811, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -811, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 509 - -809, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -809, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -308, 0, 0, 0, 0, 0, 0, -308, 0, -308, 0, 0, 0, -308, 0, 0, -308, 0, 0, 0, -308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -308, 0, -308, -308, -308, -308, 0, 0, 0, 0, 0, -308, -308, -308, -308, 0, -308, -308, -308, -308, 0, 0, 0, 0, -308, -308, -308, -308, -308, 0, 0, -308, -308, -308, -308, 0, -308, -308, -308, -308, -308, -308, -308, -308, -308, 0, 0, 0, -308, -308, 0, -308, 0, 0, 0, -308, -308, 0, -308, -308, -308, -308, // State 510 - -814, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -814, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -810, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -810, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 511 -815, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -815, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 512 - -307, 0, 0, 0, 0, 0, 0, -307, 0, -307, 0, 0, 0, -307, 0, 0, -307, 0, 0, 0, -307, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -307, 0, -307, -307, -307, -307, 0, 0, 0, 0, 0, -307, -307, -307, -307, 0, -307, -307, -307, -307, 0, 0, 0, 0, -307, -307, -307, -307, -307, 0, 0, -307, -307, -307, -307, 0, -307, -307, -307, -307, -307, -307, -307, -307, -307, 0, 0, 0, -307, -307, 0, -307, 0, 0, 0, -307, -307, 0, -307, -307, -307, -307, + -816, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -816, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 513 - -811, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -811, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -307, 0, 0, 0, 0, 0, 0, -307, 0, -307, 0, 0, 0, -307, 0, 0, -307, 0, 0, 0, -307, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -307, 0, -307, -307, -307, -307, 0, 0, 0, 0, 0, -307, -307, -307, -307, 0, -307, -307, -307, -307, 0, 0, 0, 0, -307, -307, -307, -307, -307, 0, 0, -307, -307, -307, -307, 0, -307, -307, -307, -307, -307, -307, -307, -307, -307, 0, 0, 0, -307, -307, 0, -307, 0, 0, 0, -307, -307, 0, -307, -307, -307, -307, // State 514 - -806, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -806, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -812, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -812, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 515 - -396, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -396, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -807, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -807, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 516 - 596, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 597, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -396, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -396, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 517 - -877, 0, 0, 0, -877, 0, -877, 0, 0, 0, 0, -877, -877, 0, -877, -877, 0, -877, 0, 0, 0, 0, 0, -877, -877, 103, 0, -877, 0, 0, -877, 0, -877, 0, 0, 0, 0, -877, 0, 0, -877, 0, 0, 0, 0, 0, 0, -877, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -877, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 597, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 598, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 518 - -311, 0, 0, 0, 0, 0, 0, -311, 0, -311, 0, 0, 0, -311, 0, 0, -311, 0, 0, 0, -311, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -311, 0, -311, -311, -311, -311, 0, 0, 0, 0, 0, -311, -311, -311, -311, 0, -311, -311, -311, -311, 0, 0, 0, 0, -311, -311, -311, -311, -311, 0, 0, -311, -311, -311, -311, 0, -311, -311, -311, -311, -311, -311, -311, -311, -311, 0, 0, 0, -311, -311, 0, -311, 0, 0, 0, -311, -311, 0, -311, -311, -311, -311, + -876, 0, 0, 0, -876, 0, -876, 0, 0, 0, 0, -876, -876, 0, -876, -876, 0, -876, 0, 0, 0, 0, 0, -876, -876, 104, 0, -876, 0, 0, -876, 0, -876, 0, 0, 0, 0, -876, 0, 0, -876, 0, 0, 0, 0, 0, 0, -876, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -876, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 519 - -813, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -813, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -311, 0, 0, 0, 0, 0, 0, -311, 0, -311, 0, 0, 0, -311, 0, 0, -311, 0, 0, 0, -311, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -311, 0, -311, -311, -311, -311, 0, 0, 0, 0, 0, -311, -311, -311, -311, 0, -311, -311, -311, -311, 0, 0, 0, 0, -311, -311, -311, -311, -311, 0, 0, -311, -311, -311, -311, 0, -311, -311, -311, -311, -311, -311, -311, -311, -311, 0, 0, 0, -311, -311, 0, -311, 0, 0, 0, -311, -311, 0, -311, -311, -311, -311, // State 520 - -309, 0, 0, 0, 0, 0, 0, -309, 0, -309, 0, 0, 0, -309, 0, 0, -309, 0, 0, 0, -309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -309, 0, -309, -309, -309, -309, 0, 0, 0, 0, 0, -309, -309, -309, -309, 0, -309, -309, -309, -309, 0, 0, 0, 0, -309, -309, -309, -309, -309, 0, 0, -309, -309, -309, -309, 0, -309, -309, -309, -309, -309, -309, -309, -309, -309, 0, 0, 0, -309, -309, 0, -309, 0, 0, 0, -309, -309, 0, -309, -309, -309, -309, + -814, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -814, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 521 - -312, 0, 0, 0, 0, 0, 0, -312, 0, -312, 0, 0, 0, -312, 0, 0, -312, 0, 0, 0, -312, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -312, 0, -312, -312, -312, -312, 0, 0, 0, 0, 0, -312, -312, -312, -312, 0, -312, -312, -312, -312, 0, 0, 0, 0, -312, -312, -312, -312, -312, 0, 0, -312, -312, -312, -312, 0, -312, -312, -312, -312, -312, -312, -312, -312, -312, 0, 0, 0, -312, -312, 0, -312, 0, 0, 0, -312, -312, 0, -312, -312, -312, -312, + -309, 0, 0, 0, 0, 0, 0, -309, 0, -309, 0, 0, 0, -309, 0, 0, -309, 0, 0, 0, -309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -309, 0, -309, -309, -309, -309, 0, 0, 0, 0, 0, -309, -309, -309, -309, 0, -309, -309, -309, -309, 0, 0, 0, 0, -309, -309, -309, -309, -309, 0, 0, -309, -309, -309, -309, 0, -309, -309, -309, -309, -309, -309, -309, -309, -309, 0, 0, 0, -309, -309, 0, -309, 0, 0, 0, -309, -309, 0, -309, -309, -309, -309, // State 522 - -395, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -395, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -312, 0, 0, 0, 0, 0, 0, -312, 0, -312, 0, 0, 0, -312, 0, 0, -312, 0, 0, 0, -312, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -312, 0, -312, -312, -312, -312, 0, 0, 0, 0, 0, -312, -312, -312, -312, 0, -312, -312, -312, -312, 0, 0, 0, 0, -312, -312, -312, -312, -312, 0, 0, -312, -312, -312, -312, 0, -312, -312, -312, -312, -312, -312, -312, -312, -312, 0, 0, 0, -312, -312, 0, -312, 0, 0, 0, -312, -312, 0, -312, -312, -312, -312, // State 523 - -774, 0, 0, 0, 0, 0, 0, -774, 0, -774, 0, 0, 0, -774, 0, 0, -774, 0, 0, 0, -774, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -774, 0, -774, -774, -774, -774, 0, 0, 0, 0, 0, -774, -774, -774, -774, 0, -774, -774, -774, -774, 0, 0, 0, 0, -774, -774, -774, -774, -774, 0, 0, -774, -774, -774, -774, 0, -774, -774, -774, -774, -774, -774, -774, -774, -774, 0, 0, 0, -774, 0, 0, -774, 0, 0, 0, -774, -774, 0, -774, -774, -774, -774, + -395, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -395, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 524 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 0, 0, 0, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -775, 0, 0, 0, 0, 0, 0, -775, 0, -775, 0, 0, 0, -775, 0, 0, -775, 0, 0, 0, -775, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -775, 0, -775, -775, -775, -775, 0, 0, 0, 0, 0, -775, -775, -775, -775, 0, -775, -775, -775, -775, 0, 0, 0, 0, -775, -775, -775, -775, -775, 0, 0, -775, -775, -775, -775, 0, -775, -775, -775, -775, -775, -775, -775, -775, -775, 0, 0, 0, -775, 0, 0, -775, 0, 0, 0, -775, -775, 0, -775, -775, -775, -775, // State 525 - -391, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -391, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105, 0, 0, 0, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 526 - -392, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -392, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -391, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -391, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 527 - -748, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -748, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -392, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -392, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 528 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -749, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -749, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 529 - -455, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -455, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 530 - 0, 0, 0, 0, 0, 0, 0, -114, 0, 0, 0, 0, 0, -114, 0, 0, -114, 0, 0, 0, -114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -114, -114, -114, -114, 0, 0, 0, 0, 0, 0, 0, -114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -114, 0, 0, 0, 0, 0, 0, 0, 0, 0, -114, 0, 0, 0, -114, 0, 0, -114, 0, 0, 0, -114, -114, 0, -114, 0, -114, -114, + -455, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -455, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 531 - 0, 0, 0, 0, 0, 0, 0, -122, 0, 0, 0, 0, 0, -122, 0, 0, -122, 0, 0, 0, -122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -122, -122, -122, -122, 0, 0, 0, 0, 0, 0, 0, -122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -122, 0, 0, 0, 0, 0, 0, 0, 0, 0, -122, 0, 0, 0, -122, 0, 0, -122, 0, 0, 0, -122, -122, 0, -122, 0, -122, -122, + 0, 0, 0, 0, 0, 0, 0, -114, 0, 0, 0, 0, 0, -114, 0, 0, -114, 0, 0, 0, -114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -114, -114, -114, -114, 0, 0, 0, 0, 0, 0, 0, -114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -114, 0, 0, 0, 0, 0, 0, 0, 0, 0, -114, 0, 0, 0, -114, 0, 0, -114, 0, 0, 0, -114, -114, 0, -114, 0, -114, -114, // State 532 - 0, 0, 0, 0, 0, 0, 0, 0, 658, 0, 0, 0, 0, 0, 0, 659, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -122, 0, 0, 0, 0, 0, -122, 0, 0, -122, 0, 0, 0, -122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -122, -122, -122, -122, 0, 0, 0, 0, 0, 0, 0, -122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -122, 0, 0, 0, 0, 0, 0, 0, 0, 0, -122, 0, 0, 0, -122, 0, 0, -122, 0, 0, 0, -122, -122, 0, -122, 0, -122, -122, // State 533 - 0, 0, -185, -185, 0, -185, 0, -185, -185, -185, -185, 0, 0, -185, 0, -185, -185, 0, 0, -185, 0, -185, -185, 0, 0, 0, -508, 0, -185, -185, 0, -185, 128, -185, -185, -185, -185, 0, 0, -185, 0, 0, 0, 0, -185, 0, -185, 0, -185, 0, 0, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -185, 0, 0, -185, 0, -185, -185, 0, 0, 0, -185, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 660, 0, 0, 0, 0, 0, 0, 661, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 534 - -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, 0, -163, 0, -163, -163, -163, -163, -163, 0, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, 0, 0, 0, -163, -163, -163, -163, -163, -163, 0, -163, 0, 0, 0, 0, 0, 0, 0, 0, -163, 0, 0, -163, -163, 0, -163, 0, -163, -163, 0, 0, 0, -163, -163, 0, 0, 0, 0, 0, 0, 0, 0, 0, -163, -163, -163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -185, -185, 0, -185, 0, -185, -185, -185, -185, 0, 0, -185, 0, -185, -185, 0, 0, -185, 0, -185, -185, 0, 0, 0, -509, 0, -185, -185, 0, -185, 128, -185, -185, -185, -185, 0, 0, -185, 0, 0, 0, 0, -185, 0, -185, 0, -185, 0, 0, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -185, 0, 0, -185, 0, -185, -185, 0, 0, 0, -185, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 535 - -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, 0, -242, 0, -242, -242, -242, -242, -242, 0, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, 0, 0, 0, -242, -242, -242, -242, -242, -242, 0, -242, 0, 0, 0, 0, 0, 0, 0, 0, -242, 0, 0, -242, -242, 0, -242, 0, -242, -242, 0, 0, 0, -242, -242, 0, 0, 0, 0, 0, 0, 0, 0, 0, -242, -242, -242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, 0, -163, 0, -163, -163, -163, -163, -163, 0, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, 0, 0, 0, -163, -163, -163, -163, -163, -163, 0, -163, 0, 0, 0, 0, 0, 0, 0, 0, -163, 0, 0, -163, -163, 0, -163, 0, -163, -163, 0, 0, 0, -163, -163, 0, 0, 0, 0, 0, 0, 0, 0, 0, -163, -163, -163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 536 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -851, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, 0, -242, 0, -242, -242, -242, -242, -242, 0, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, -242, 0, 0, 0, -242, -242, -242, -242, -242, -242, 0, -242, 0, 0, 0, 0, 0, 0, 0, 0, -242, 0, 0, -242, -242, 0, -242, 0, -242, -242, 0, 0, 0, -242, -242, 0, 0, 0, 0, 0, 0, 0, 0, 0, -242, -242, -242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 537 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 538 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 665, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 539 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -842, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -842, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 540 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -854, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -841, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -841, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 541 - -764, -764, -764, -764, -764, -764, -764, 0, -764, -764, 0, -764, -764, -764, -764, -764, -764, -764, 0, 0, 0, -764, -764, -764, -764, -764, 0, -764, -764, -764, -764, -764, -764, -764, -764, -764, -764, -764, -764, -764, -764, 0, 0, 0, 0, -764, -764, -764, -764, -764, 0, -764, 0, 0, 0, 0, 0, 0, 0, 0, -764, 0, 0, -764, -764, 0, -764, 0, -764, -764, 0, 0, 0, -764, -764, 0, 0, 0, 0, 0, 0, 0, 0, 0, -764, -764, -764, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -853, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 542 - -141, -141, -141, 0, -141, 0, -141, 0, -141, 0, 0, -141, -141, 0, -141, -141, 0, -141, 0, 0, 0, 0, 0, -141, -141, -141, 0, -141, -141, 0, -141, -141, -141, -141, -141, -141, 0, -141, 0, 0, -141, 0, 0, 0, 0, -141, 0, -141, -141, -141, 0, -141, 0, 0, 0, 0, 0, 0, 0, 0, -141, 0, 0, -141, -141, 0, -141, 0, -141, -141, 0, 0, 0, -141, -141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, -141, -141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -765, -765, -765, -765, -765, -765, -765, 0, -765, -765, 0, -765, -765, -765, -765, -765, -765, -765, 0, 0, 0, -765, -765, -765, -765, -765, 0, -765, -765, -765, -765, -765, -765, -765, -765, -765, -765, -765, -765, -765, -765, 0, 0, 0, 0, -765, -765, -765, -765, -765, 0, -765, 0, 0, 0, 0, 0, 0, 0, 0, -765, 0, 0, -765, -765, 0, -765, 0, -765, -765, 0, 0, 0, -765, -765, 0, 0, 0, 0, 0, 0, 0, 0, 0, -765, -765, -765, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 543 - 0, 0, 0, 0, 0, 0, 0, -302, 0, 0, 0, 0, 0, -302, 0, 0, -302, 0, 0, 0, -302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -302, -302, -302, -302, 0, 0, 0, 0, 0, 0, 0, -302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -302, 0, 0, 0, -302, 0, 0, -302, 0, 0, 0, -302, -302, 0, -302, 0, -302, -302, + -141, -141, -141, 0, -141, 0, -141, 0, -141, 0, 0, -141, -141, 0, -141, -141, 0, -141, 0, 0, 0, 0, 0, -141, -141, -141, 0, -141, -141, 0, -141, -141, -141, -141, -141, -141, 0, -141, 0, 0, -141, 0, 0, 0, 0, -141, 0, -141, -141, -141, 0, -141, 0, 0, 0, 0, 0, 0, 0, 0, -141, 0, 0, -141, -141, 0, -141, 0, -141, -141, 0, 0, 0, -141, -141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, -141, -141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 544 - 0, 0, 0, 0, 0, 0, 0, -300, 0, 0, 0, 0, 0, -300, 0, 0, -300, 0, 0, 0, -300, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -300, -300, -300, -300, 0, 0, 0, 0, 0, 0, 0, -300, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -300, 0, 0, 0, -300, 0, 0, -300, 0, 0, 0, -300, -300, 0, -300, 0, -300, -300, + 0, 0, 0, 0, 0, 0, 0, -302, 0, 0, 0, 0, 0, -302, 0, 0, -302, 0, 0, 0, -302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -302, -302, -302, -302, 0, 0, 0, 0, 0, 0, 0, -302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -302, 0, 0, 0, -302, 0, 0, -302, 0, 0, 0, -302, -302, 0, -302, 0, -302, -302, // State 545 - -348, -348, -348, 0, -348, 0, -348, 0, -348, 0, 0, -348, -348, 0, -348, -348, 0, -348, 0, 0, 0, 0, 0, -348, -348, -348, 0, -348, -348, 0, -348, -348, -348, -348, -348, -348, 0, -348, -348, 0, -348, 0, 0, 0, 0, -348, 36, -348, -348, -348, 0, -348, 0, 0, 0, 0, 0, 0, 0, 0, -348, 0, 0, -348, -348, 0, -348, 0, -348, -348, 0, 0, 0, -348, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, -348, -348, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -300, 0, 0, 0, 0, 0, -300, 0, 0, -300, 0, 0, 0, -300, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -300, -300, -300, -300, 0, 0, 0, 0, 0, 0, 0, -300, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -300, 0, 0, 0, -300, 0, 0, -300, 0, 0, 0, -300, -300, 0, -300, 0, -300, -300, // State 546 - -91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -348, -348, -348, 0, -348, 0, -348, 0, -348, 0, 0, -348, -348, 0, -348, -348, 0, -348, 0, 0, 0, 0, 0, -348, -348, -348, 0, -348, -348, 0, -348, -348, -348, -348, -348, -348, 0, -348, -348, 0, -348, 0, 0, 0, 0, -348, 37, -348, -348, -348, 0, -348, 0, 0, 0, 0, 0, 0, 0, 0, -348, 0, 0, -348, -348, 0, -348, 0, -348, -348, 0, 0, 0, -348, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, -348, -348, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 547 - -551, -551, 0, 0, -551, 0, -551, 0, -551, 0, 0, -551, -551, 0, -551, -551, 0, -551, 0, 0, 0, 0, 0, -551, -551, -551, 0, -551, 0, 0, -551, 0, -551, 0, 0, 0, 0, -551, 0, 0, -551, 0, 0, 0, 0, 0, 0, -551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -551, -551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 548 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -552, -552, 0, 0, -552, 0, -552, 0, -552, 0, 0, -552, -552, 0, -552, -552, 0, -552, 0, 0, 0, 0, 0, -552, -552, -552, 0, -552, 0, 0, -552, 0, -552, 0, 0, 0, 0, -552, 0, 0, -552, 0, 0, 0, 0, 0, 0, -552, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -552, -552, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 549 - -860, -860, -860, -860, -860, -860, -860, 0, -860, -860, 0, -860, -860, -860, -860, -860, -860, -860, 0, 0, 0, -860, -860, -860, -860, -860, 0, -860, -860, -860, -860, -860, -860, -860, -860, -860, -860, -860, -860, -860, -860, 0, 0, 0, 0, -860, -860, -860, -860, -860, 0, -860, 0, 0, 0, 0, 0, 0, 0, 0, -860, 0, 0, -860, -860, 0, -860, 0, -860, -860, 0, 0, 0, -860, -860, 0, 0, 0, 0, 0, 0, 0, 0, 0, -860, -860, -860, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 550 - -942, -942, -942, 0, -942, 23, -942, 0, -942, 0, 0, -942, -942, 0, -942, -942, 0, -942, 0, 0, 0, 0, 0, -942, -942, -942, 0, -942, -942, 0, -942, -942, -942, -942, -942, -942, 0, -942, -942, 0, -942, 0, 0, 0, 0, -942, -942, -942, -942, -942, 0, -942, 0, 0, 0, 0, 0, 0, 0, 0, -942, 0, 0, -942, -942, 0, -942, 0, -942, -942, 0, 0, 0, -942, -942, 0, 0, 0, 0, 0, 0, 0, 0, 0, -942, -942, -942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -859, -859, -859, -859, -859, -859, -859, 0, -859, -859, 0, -859, -859, -859, -859, -859, -859, -859, 0, 0, 0, -859, -859, -859, -859, -859, 0, -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, 0, 0, 0, 0, -859, -859, -859, -859, -859, 0, -859, 0, 0, 0, 0, 0, 0, 0, 0, -859, 0, 0, -859, -859, 0, -859, 0, -859, -859, 0, 0, 0, -859, -859, 0, 0, 0, 0, 0, 0, 0, 0, 0, -859, -859, -859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 551 - 0, 0, 0, 0, 0, 0, 0, 0, 667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -945, -945, -945, 0, -945, 24, -945, 0, -945, 0, 0, -945, -945, 0, -945, -945, 0, -945, 0, 0, 0, 0, 0, -945, -945, -945, 0, -945, -945, 0, -945, -945, -945, -945, -945, -945, 0, -945, -945, 0, -945, 0, 0, 0, 0, -945, -945, -945, -945, -945, 0, -945, 0, 0, 0, 0, 0, 0, 0, 0, -945, 0, 0, -945, -945, 0, -945, 0, -945, -945, 0, 0, 0, -945, -945, 0, 0, 0, 0, 0, 0, 0, 0, 0, -945, -945, -945, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 552 - 0, 0, 0, 0, 0, 0, 0, 0, -799, 0, 0, 0, 0, 0, 0, -799, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -799, 0, 0, 0, 0, 0, -799, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -799, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -799, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 669, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 553 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -800, 0, 0, 0, 0, 0, 0, -800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -800, 0, 0, 0, 0, 0, -800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 554 - 0, 0, 0, 0, 0, 0, 0, 0, 670, 0, 0, 0, 0, 0, 0, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 555 - -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, 0, -196, 0, -196, -196, -196, -196, -196, 0, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, 0, 0, 0, -196, -196, -196, -196, -196, -196, 0, -196, 0, 0, 0, 0, 0, 0, 0, 0, -196, 0, 0, -196, -196, 0, -196, 0, -196, -196, 0, 0, 0, -196, -196, 0, 0, 0, 0, 0, 0, 0, 0, 0, -196, -196, -196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 672, 0, 0, 0, 0, 0, 0, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 556 - -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, 0, -190, 0, -190, -190, -190, -190, -190, 0, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, 0, 0, 0, -190, -190, -190, -190, -190, -190, 0, -190, 0, 0, 0, 0, 0, 0, 0, 0, -190, 0, 0, -190, -190, 0, -190, 0, -190, -190, 0, 0, 0, -190, -190, 0, 0, 0, 0, 0, 0, 0, 0, 0, -190, -190, -190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, 0, -196, 0, -196, -196, -196, -196, -196, 0, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, -196, 0, 0, 0, -196, -196, -196, -196, -196, -196, 0, -196, 0, 0, 0, 0, 0, 0, 0, 0, -196, 0, 0, -196, -196, 0, -196, 0, -196, -196, 0, 0, 0, -196, -196, 0, 0, 0, 0, 0, 0, 0, 0, 0, -196, -196, -196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 557 - -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, 0, -200, 0, -200, -200, -200, -200, -200, 0, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, 0, 0, 0, -200, -200, -200, -200, -200, -200, 0, -200, 0, 0, 0, 0, 0, 0, 0, 0, -200, 0, 0, -200, -200, 0, -200, 0, -200, -200, 0, 0, 0, -200, -200, 0, 0, 0, 0, 0, 0, 0, 0, 0, -200, -200, -200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, 0, -190, 0, -190, -190, -190, -190, -190, 0, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, -190, 0, 0, 0, -190, -190, -190, -190, -190, -190, 0, -190, 0, 0, 0, 0, 0, 0, 0, 0, -190, 0, 0, -190, -190, 0, -190, 0, -190, -190, 0, 0, 0, -190, -190, 0, 0, 0, 0, 0, 0, 0, 0, 0, -190, -190, -190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 558 - 0, 0, 0, 0, 0, 0, 0, 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, 0, -200, 0, -200, -200, -200, -200, -200, 0, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, -200, 0, 0, 0, -200, -200, -200, -200, -200, -200, 0, -200, 0, 0, 0, 0, 0, 0, 0, 0, -200, 0, 0, -200, -200, 0, -200, 0, -200, -200, 0, 0, 0, -200, -200, 0, 0, 0, 0, 0, 0, 0, 0, 0, -200, -200, -200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 559 - -946, -946, 0, 0, 0, 0, 0, 0, -946, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -946, 0, -946, 0, 0, 0, 0, -946, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -946, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 678, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 560 - -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, 0, -186, 0, -186, -186, -186, -186, -186, 0, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, 0, 0, 0, -186, -186, -186, -186, -186, -186, 0, -186, 0, 0, 0, 0, 0, 0, 0, 0, -186, 0, 0, -186, -186, 0, -186, 0, -186, -186, 0, 0, 0, -186, -186, 0, 0, 0, 0, 0, 0, 0, 0, 0, -186, -186, -186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -949, -949, 0, 0, 0, 0, 0, 0, -949, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -949, 0, -949, 0, 0, 0, 0, -949, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -949, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 561 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 679, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, 0, -186, 0, -186, -186, -186, -186, -186, 0, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, -186, 0, 0, 0, -186, -186, -186, -186, -186, -186, 0, -186, 0, 0, 0, 0, 0, 0, 0, 0, -186, 0, 0, -186, -186, 0, -186, 0, -186, -186, 0, 0, 0, -186, -186, 0, 0, 0, 0, 0, 0, 0, 0, 0, -186, -186, -186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 562 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -726, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 563 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, -725, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -727, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 564 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -822, 0, 0, 0, 0, 0, 0, 0, 0, 0, -822, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, -726, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 565 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -459, 0, 0, 0, 0, 0, 0, 0, 0, 0, -459, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -823, 0, 0, 0, 0, 0, 0, 0, 0, 0, -823, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 566 - -464, -464, 0, 0, -464, 0, -464, 0, -464, 0, 0, -464, -464, 0, -464, -464, 0, -464, 0, 0, 0, 0, 0, -464, -464, -464, 0, -464, 0, 0, -464, 0, -464, 0, 0, 0, 0, -464, 0, 0, -464, 0, 0, 0, 0, -464, 0, -464, 0, -464, 0, -464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -464, -464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -464, -464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -459, 0, 0, 0, 0, 0, 0, 0, 0, 0, -459, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 567 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 688, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -464, -464, 0, 0, -464, 0, -464, 0, -464, 0, 0, -464, -464, 0, -464, -464, 0, -464, 0, 0, 0, 0, 0, -464, -464, -464, 0, -464, 0, 0, -464, 0, -464, 0, 0, 0, 0, -464, 0, 0, -464, 0, 0, 0, 0, -464, 0, -464, 0, -464, 0, -464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -464, -464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -464, -464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 568 - -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, 0, -203, 0, -203, -203, -203, -203, -203, 0, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, 0, 0, 0, -203, -203, -203, -203, -203, -203, 0, -203, 0, 0, 0, 0, 0, 0, 0, 0, -203, 0, 0, -203, -203, 0, -203, 0, -203, -203, 0, 0, 0, -203, -203, 0, 0, 0, 0, 0, 0, 0, 0, 0, -203, -203, -203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 690, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 569 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 689, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, 0, -203, 0, -203, -203, -203, -203, -203, 0, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, -203, 0, 0, 0, -203, -203, -203, -203, -203, -203, 0, -203, 0, 0, 0, 0, 0, 0, 0, 0, -203, 0, 0, -203, -203, 0, -203, 0, -203, -203, 0, 0, 0, -203, -203, 0, 0, 0, 0, 0, 0, 0, 0, 0, -203, -203, -203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 570 - -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, 0, -206, 0, -206, -206, -206, -206, -206, 0, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, 0, 0, 0, -206, -206, -206, -206, -206, -206, 0, -206, 0, 0, 0, 0, 0, 0, 0, 0, -206, 0, 0, -206, -206, 0, -206, 0, -206, -206, 0, 0, 0, -206, -206, 0, 0, 0, 0, 0, 0, 0, 0, 0, -206, -206, -206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 691, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 571 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -327, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, -327, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, 0, -206, 0, -206, -206, -206, -206, -206, 0, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, 0, 0, 0, -206, -206, -206, -206, -206, -206, 0, -206, 0, 0, 0, 0, 0, 0, 0, 0, -206, 0, 0, -206, -206, 0, -206, 0, -206, -206, 0, 0, 0, -206, -206, 0, 0, 0, 0, 0, 0, 0, 0, 0, -206, -206, -206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 572 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -378, 0, 0, -378, 0, 0, -378, 0, 0, 0, 0, 0, 0, -378, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -327, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, -327, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 573 - -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, 0, -367, 0, -367, -367, -367, -367, -367, 0, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, 0, 0, 0, -367, -367, -367, -367, -367, -367, 0, -367, 0, 0, 0, 0, 0, 0, 0, 0, -367, 0, 0, -367, -367, 0, -367, 0, -367, -367, 0, 0, 0, -367, -367, 0, 0, 0, 0, 0, 0, 0, 0, 0, -367, -367, -367, 0, 0, 0, -367, 0, 0, 0, 0, 0, 0, 0, 0, 0, -367, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -378, 0, 0, -378, 0, 0, -378, 0, 0, 0, 0, 0, 0, -378, 0, 0, 0, 0, // State 574 - -875, -875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -875, 0, -875, 0, 0, 0, 0, -875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, 0, -367, 0, -367, -367, -367, -367, -367, 0, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, 0, 0, 0, -367, -367, -367, -367, -367, -367, 0, -367, 0, 0, 0, 0, 0, 0, 0, 0, -367, 0, 0, -367, -367, 0, -367, 0, -367, -367, 0, 0, 0, -367, -367, 0, 0, 0, 0, 0, 0, 0, 0, 0, -367, -367, -367, 0, 0, 0, -367, 0, 0, 0, 0, 0, 0, 0, 0, 0, -367, // State 575 - -876, -876, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -876, 0, -876, 0, 0, 0, 0, -876, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -876, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -874, -874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -874, 0, -874, 0, 0, 0, 0, -874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 576 - 697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 698, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -875, -875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -875, 0, -875, 0, 0, 0, 0, -875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 577 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -324, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -324, 0, 0, 0, -324, 0, -324, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 699, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 578 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -324, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -324, 0, 0, 0, -324, 0, -324, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 579 - -456, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -456, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 699, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 580 - -85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -456, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -456, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 701, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 581 - -179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -179, 0, 0, 0, 0, -179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 582 - 0, 0, 0, 0, 0, 0, 0, -256, 0, -256, 0, 0, 0, -256, 0, 0, -256, 0, 0, 0, -256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -256, -256, -256, -256, 0, 0, 0, 0, 0, 0, 0, -256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -256, 0, 0, -256, 0, 0, 0, 0, 0, 0, 0, 0, -256, -256, 0, 0, 0, -256, 0, 0, -256, 0, 0, 0, -256, -256, 0, -256, 0, -256, -256, + -179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -179, 0, 0, 0, 0, -179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 583 - 0, 0, 0, 0, 0, 0, 0, -257, 0, -257, 0, 0, 0, -257, 0, 0, -257, 0, 0, 0, -257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -257, -257, -257, -257, 0, 0, 0, 0, 0, 0, 0, -257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -257, 0, 0, -257, 0, 0, 0, 0, 0, 0, 0, 0, -257, -257, 0, 0, 0, -257, 0, 0, -257, 0, 0, 0, -257, -257, 0, -257, 0, -257, -257, + 0, 0, 0, 0, 0, 0, 0, -256, 0, -256, 0, 0, 0, -256, 0, 0, -256, 0, 0, 0, -256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -256, -256, -256, -256, 0, 0, 0, 0, 0, 0, 0, -256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -256, 0, 0, -256, 0, 0, 0, 0, 0, 0, 0, 0, -256, -256, 0, 0, 0, -256, 0, 0, -256, 0, 0, 0, -256, -256, 0, -256, 0, -256, -256, // State 584 - 0, 0, 0, 0, 0, 0, 0, -262, 0, -262, 0, 0, 0, -262, 0, 0, -262, 0, 0, 0, -262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -262, -262, -262, -262, 0, 0, 0, 0, 0, 0, 0, -262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -262, 0, 0, -262, 0, 0, 0, 0, 0, 0, 0, 0, -262, -262, 0, 0, 0, -262, 0, 0, -262, 0, 0, 0, -262, -262, 0, -262, 0, -262, -262, + 0, 0, 0, 0, 0, 0, 0, -257, 0, -257, 0, 0, 0, -257, 0, 0, -257, 0, 0, 0, -257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -257, -257, -257, -257, 0, 0, 0, 0, 0, 0, 0, -257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -257, 0, 0, -257, 0, 0, 0, 0, 0, 0, 0, 0, -257, -257, 0, 0, 0, -257, 0, 0, -257, 0, 0, 0, -257, -257, 0, -257, 0, -257, -257, // State 585 - 0, 0, 0, 0, 0, 0, 0, -253, 0, -253, 0, 0, 0, -253, 0, 0, -253, 0, 0, 0, -253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -253, -253, -253, -253, 0, 0, 0, 0, 0, 0, 0, -253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -253, 0, 0, -253, 0, 0, 0, 0, 0, 0, 0, 0, -253, -253, 0, 0, 0, -253, 0, 0, -253, 0, 0, 0, -253, -253, 0, -253, 0, -253, -253, + 0, 0, 0, 0, 0, 0, 0, -262, 0, -262, 0, 0, 0, -262, 0, 0, -262, 0, 0, 0, -262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -262, -262, -262, -262, 0, 0, 0, 0, 0, 0, 0, -262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -262, 0, 0, -262, 0, 0, 0, 0, 0, 0, 0, 0, -262, -262, 0, 0, 0, -262, 0, 0, -262, 0, 0, 0, -262, -262, 0, -262, 0, -262, -262, // State 586 - 0, 0, 0, 0, 0, 0, 0, -251, 0, -251, 0, 0, 0, -251, 0, 0, -251, 0, 0, 0, -251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -251, -251, -251, -251, 0, 0, 0, 0, 0, 0, 0, -251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -251, 0, 0, -251, 0, 0, 0, 0, 0, 0, 0, 0, -251, -251, 0, 0, 0, -251, 0, 0, -251, 0, 0, 0, -251, -251, 0, -251, 0, -251, -251, + 0, 0, 0, 0, 0, 0, 0, -253, 0, -253, 0, 0, 0, -253, 0, 0, -253, 0, 0, 0, -253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -253, -253, -253, -253, 0, 0, 0, 0, 0, 0, 0, -253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -253, 0, 0, -253, 0, 0, 0, 0, 0, 0, 0, 0, -253, -253, 0, 0, 0, -253, 0, 0, -253, 0, 0, 0, -253, -253, 0, -253, 0, -253, -253, // State 587 - 0, 0, 0, 0, 0, 0, 0, -252, 0, -252, 0, 0, 0, -252, 0, 0, -252, 0, 0, 0, -252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -252, -252, -252, -252, 0, 0, 0, 0, 0, 0, 0, -252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -252, 0, 0, -252, 0, 0, 0, 0, 0, 0, 0, 0, -252, -252, 0, 0, 0, -252, 0, 0, -252, 0, 0, 0, -252, -252, 0, -252, 0, -252, -252, + 0, 0, 0, 0, 0, 0, 0, -251, 0, -251, 0, 0, 0, -251, 0, 0, -251, 0, 0, 0, -251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -251, -251, -251, -251, 0, 0, 0, 0, 0, 0, 0, -251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -251, 0, 0, -251, 0, 0, 0, 0, 0, 0, 0, 0, -251, -251, 0, 0, 0, -251, 0, 0, -251, 0, 0, 0, -251, -251, 0, -251, 0, -251, -251, // State 588 - 0, 0, 0, 0, 0, 0, 0, -263, 0, -263, 0, 0, 0, -263, 0, 0, -263, 0, 0, 0, -263, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -263, -263, -263, -263, 0, 0, 0, 0, 0, 0, 0, -263, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -263, 0, 0, -263, 0, 0, 0, 0, 0, 0, 0, 0, -263, -263, 0, 0, 0, -263, 0, 0, -263, 0, 0, 0, -263, -263, 0, -263, 0, -263, -263, + 0, 0, 0, 0, 0, 0, 0, -252, 0, -252, 0, 0, 0, -252, 0, 0, -252, 0, 0, 0, -252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -252, -252, -252, -252, 0, 0, 0, 0, 0, 0, 0, -252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -252, 0, 0, -252, 0, 0, 0, 0, 0, 0, 0, 0, -252, -252, 0, 0, 0, -252, 0, 0, -252, 0, 0, 0, -252, -252, 0, -252, 0, -252, -252, // State 589 - 0, 0, 0, 0, 0, 0, 0, -255, 0, -255, 0, 0, 0, -255, 0, 0, -255, 0, 0, 0, -255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -255, -255, -255, -255, 0, 0, 0, 0, 0, 0, 0, -255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -255, 0, 0, -255, 0, 0, 0, 0, 0, 0, 0, 0, -255, -255, 0, 0, 0, -255, 0, 0, -255, 0, 0, 0, -255, -255, 0, -255, 0, -255, -255, + 0, 0, 0, 0, 0, 0, 0, -263, 0, -263, 0, 0, 0, -263, 0, 0, -263, 0, 0, 0, -263, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -263, -263, -263, -263, 0, 0, 0, 0, 0, 0, 0, -263, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -263, 0, 0, -263, 0, 0, 0, 0, 0, 0, 0, 0, -263, -263, 0, 0, 0, -263, 0, 0, -263, 0, 0, 0, -263, -263, 0, -263, 0, -263, -263, // State 590 - 0, 0, 0, 0, 0, 0, 0, -260, 0, -260, 0, 0, 0, -260, 0, 0, -260, 0, 0, 0, -260, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -260, -260, -260, -260, 0, 0, 0, 0, 0, 0, 0, -260, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -260, 0, 0, -260, 0, 0, 0, 0, 0, 0, 0, 0, -260, -260, 0, 0, 0, -260, 0, 0, -260, 0, 0, 0, -260, -260, 0, -260, 0, -260, -260, + 0, 0, 0, 0, 0, 0, 0, -255, 0, -255, 0, 0, 0, -255, 0, 0, -255, 0, 0, 0, -255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -255, -255, -255, -255, 0, 0, 0, 0, 0, 0, 0, -255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -255, 0, 0, -255, 0, 0, 0, 0, 0, 0, 0, 0, -255, -255, 0, 0, 0, -255, 0, 0, -255, 0, 0, 0, -255, -255, 0, -255, 0, -255, -255, // State 591 - 0, 0, 0, 0, 0, 0, 0, -261, 0, -261, 0, 0, 0, -261, 0, 0, -261, 0, 0, 0, -261, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -261, -261, -261, -261, 0, 0, 0, 0, 0, 0, 0, -261, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -261, 0, 0, -261, 0, 0, 0, 0, 0, 0, 0, 0, -261, -261, 0, 0, 0, -261, 0, 0, -261, 0, 0, 0, -261, -261, 0, -261, 0, -261, -261, + 0, 0, 0, 0, 0, 0, 0, -260, 0, -260, 0, 0, 0, -260, 0, 0, -260, 0, 0, 0, -260, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -260, -260, -260, -260, 0, 0, 0, 0, 0, 0, 0, -260, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -260, 0, 0, -260, 0, 0, 0, 0, 0, 0, 0, 0, -260, -260, 0, 0, 0, -260, 0, 0, -260, 0, 0, 0, -260, -260, 0, -260, 0, -260, -260, // State 592 - 0, 0, 0, 0, 0, 0, 0, -254, 0, -254, 0, 0, 0, -254, 0, 0, -254, 0, 0, 0, -254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -254, -254, -254, -254, 0, 0, 0, 0, 0, 0, 0, -254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -254, 0, 0, -254, 0, 0, 0, 0, 0, 0, 0, 0, -254, -254, 0, 0, 0, -254, 0, 0, -254, 0, 0, 0, -254, -254, 0, -254, 0, -254, -254, + 0, 0, 0, 0, 0, 0, 0, -261, 0, -261, 0, 0, 0, -261, 0, 0, -261, 0, 0, 0, -261, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -261, -261, -261, -261, 0, 0, 0, 0, 0, 0, 0, -261, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -261, 0, 0, -261, 0, 0, 0, 0, 0, 0, 0, 0, -261, -261, 0, 0, 0, -261, 0, 0, -261, 0, 0, 0, -261, -261, 0, -261, 0, -261, -261, // State 593 - 0, 0, 0, 0, 0, 0, 0, -259, 0, -259, 0, 0, 0, -259, 0, 0, -259, 0, 0, 0, -259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -259, -259, -259, -259, 0, 0, 0, 0, 0, 0, 0, -259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -259, 0, 0, -259, 0, 0, 0, 0, 0, 0, 0, 0, -259, -259, 0, 0, 0, -259, 0, 0, -259, 0, 0, 0, -259, -259, 0, -259, 0, -259, -259, + 0, 0, 0, 0, 0, 0, 0, -254, 0, -254, 0, 0, 0, -254, 0, 0, -254, 0, 0, 0, -254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -254, -254, -254, -254, 0, 0, 0, 0, 0, 0, 0, -254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -254, 0, 0, -254, 0, 0, 0, 0, 0, 0, 0, 0, -254, -254, 0, 0, 0, -254, 0, 0, -254, 0, 0, 0, -254, -254, 0, -254, 0, -254, -254, // State 594 - 0, 0, 0, 0, 0, 0, 0, -258, 0, -258, 0, 0, 0, -258, 0, 0, -258, 0, 0, 0, -258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -258, -258, -258, -258, 0, 0, 0, 0, 0, 0, 0, -258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -258, 0, 0, -258, 0, 0, 0, 0, 0, 0, 0, 0, -258, -258, 0, 0, 0, -258, 0, 0, -258, 0, 0, 0, -258, -258, 0, -258, 0, -258, -258, + 0, 0, 0, 0, 0, 0, 0, -259, 0, -259, 0, 0, 0, -259, 0, 0, -259, 0, 0, 0, -259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -259, -259, -259, -259, 0, 0, 0, 0, 0, 0, 0, -259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -259, 0, 0, -259, 0, 0, 0, 0, 0, 0, 0, 0, -259, -259, 0, 0, 0, -259, 0, 0, -259, 0, 0, 0, -259, -259, 0, -259, 0, -259, -259, // State 595 - -772, 0, 0, 0, 0, 0, 0, -772, 0, -772, 0, 0, 0, -772, 0, 0, -772, 0, 0, 0, -772, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -772, 0, -772, -772, -772, -772, 0, 0, 0, 0, 0, -772, -772, -772, -772, 0, -772, -772, -772, -772, 0, 0, 0, 0, -772, -772, -772, -772, -772, 0, 0, -772, -772, -772, -772, 0, -772, -772, -772, -772, -772, -772, -772, -772, -772, 0, 0, 0, -772, 0, 0, -772, 0, 0, 0, -772, -772, 0, -772, -772, -772, -772, + 0, 0, 0, 0, 0, 0, 0, -258, 0, -258, 0, 0, 0, -258, 0, 0, -258, 0, 0, 0, -258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -258, -258, -258, -258, 0, 0, 0, 0, 0, 0, 0, -258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -258, 0, 0, -258, 0, 0, 0, 0, 0, 0, 0, 0, -258, -258, 0, 0, 0, -258, 0, 0, -258, 0, 0, 0, -258, -258, 0, -258, 0, -258, -258, // State 596 - 705, 0, 0, 0, 0, 0, 0, -134, 0, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -134, -134, -134, -134, 0, 0, 0, 0, 0, -134, 0, -134, -134, 0, 0, -134, 0, -134, 0, 0, 0, 0, 0, -134, -134, 0, -134, 0, 0, -134, 0, -134, -134, 0, -134, -134, -134, 0, -134, 0, 0, -134, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, -134, 0, -134, -134, -134, -134, + -773, 0, 0, 0, 0, 0, 0, -773, 0, -773, 0, 0, 0, -773, 0, 0, -773, 0, 0, 0, -773, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -773, 0, -773, -773, -773, -773, 0, 0, 0, 0, 0, -773, -773, -773, -773, 0, -773, -773, -773, -773, 0, 0, 0, 0, -773, -773, -773, -773, -773, 0, 0, -773, -773, -773, -773, 0, -773, -773, -773, -773, -773, -773, -773, -773, -773, 0, 0, 0, -773, 0, 0, -773, 0, 0, 0, -773, -773, 0, -773, -773, -773, -773, // State 597 - 706, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 707, 0, 0, 0, 0, 0, 0, -134, 0, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -134, -134, -134, -134, 0, 0, 0, 0, 0, -134, 0, -134, -134, 0, 0, -134, 0, -134, 0, 0, 0, 0, 0, -134, -134, 0, -134, 0, 0, -134, 0, -134, -134, 0, -134, -134, -134, 0, -134, 0, 0, -134, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, -134, 0, -134, -134, -134, -134, // State 598 - -174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 708, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 599 - -356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 600 - -325, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -325, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 601 - -526, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -526, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -526, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -526, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -325, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -325, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 602 - -354, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -354, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -527, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -527, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -527, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -527, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 603 - -357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -354, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -354, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 604 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 605 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 606 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 607 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -449, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 608 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -447, -447, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -447, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -447, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -449, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 609 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -447, -447, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -447, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -447, 0, // State 610 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -444, -444, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -444, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -444, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 611 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -443, -443, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -443, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -443, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -444, -444, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -444, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -444, 0, // State 612 - -528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -443, -443, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -443, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -443, 0, // State 613 - -428, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -428, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -529, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -529, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -529, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 614 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -428, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -428, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 615 - -531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 616 - -452, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -452, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -532, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -532, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -532, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 617 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 714, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -452, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -452, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 618 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 715, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 716, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 619 - -513, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -513, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 717, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 620 - -777, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -777, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 621 - -393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -778, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -778, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 622 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -902, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -902, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 623 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -905, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -905, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 624 - 0, 0, -943, 0, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, -943, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -943, 0, 0, -943, 0, -943, -943, -943, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -943, 0, -943, -943, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -943, 0, -943, -943, 0, 0, 0, -943, -943, 0, 0, 0, 0, 0, 0, 0, 0, 0, -943, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 625 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -945, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -946, 0, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, -946, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -946, 0, 0, -946, 0, -946, -946, -946, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -946, 0, -946, -946, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -946, 0, -946, -946, 0, 0, 0, -946, -946, 0, 0, 0, 0, 0, 0, 0, 0, 0, -946, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 626 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -561, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 627 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -792, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -562, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 628 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -793, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 629 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 630 - 0, 0, -765, -765, 0, -765, 0, 0, 0, -765, 177, 0, 0, -765, 0, -765, -765, 0, 0, 0, 0, -765, -765, 0, 0, 0, 0, 0, -765, -765, 0, -765, 0, -765, -765, -765, -765, 0, 0, -765, 0, 0, 0, 0, 0, 0, -765, 0, -765, -765, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -765, 0, -765, -765, 0, 0, 0, -765, -765, 0, 0, 0, 0, 0, 0, 0, 0, 0, -765, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 631 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -767, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -766, -766, 0, -766, 0, 0, 0, -766, 177, 0, 0, -766, 0, -766, -766, 0, 0, 0, 0, -766, -766, 0, 0, 0, 0, 0, -766, -766, 0, -766, 0, -766, -766, -766, -766, 0, 0, -766, 0, 0, 0, 0, 0, 0, -766, 0, -766, -766, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -766, 0, -766, -766, 0, 0, 0, -766, -766, 0, 0, 0, 0, 0, 0, 0, 0, 0, -766, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 632 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -768, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 633 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -306, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 634 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -863, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -306, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 635 - 0, 0, -185, -185, 0, -185, 0, -185, 0, -185, -185, 0, 0, -185, 0, -185, -185, 0, 0, -185, 0, -185, -185, 0, 0, -214, 0, 0, -185, -185, 0, -185, 0, -185, -185, -185, -185, 0, 0, -185, 0, 0, 0, 0, -185, 0, -185, 0, -185, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -185, 0, -185, -185, 0, 0, 0, -185, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -862, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 636 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -866, 0, 0, 0, 0, 0, 0, 0, 0, 0, -871, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -866, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -185, -185, 0, -185, 0, -185, 0, -185, -185, 0, 0, -185, 0, -185, -185, 0, 0, -185, 0, -185, -185, 0, 0, -214, 0, 0, -185, -185, 0, -185, 0, -185, -185, -185, -185, 0, 0, -185, 0, 0, 0, 0, -185, 0, -185, 0, -185, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -185, 0, -185, -185, 0, 0, 0, -185, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, -185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 637 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -865, 0, 0, 0, 0, 0, 0, 0, 0, 0, -870, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -865, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 638 - 0, 0, -184, -184, 0, -184, 0, -184, 0, -184, -184, 0, 0, -184, 0, -184, -184, 0, 0, -184, 0, -184, -184, 0, 0, -213, 0, 0, -184, -184, 0, -184, 0, -184, -184, -184, -184, 0, 0, -184, 0, 0, 0, 0, -184, 0, -184, 0, -184, -184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -184, 0, -184, -184, 0, 0, 0, -184, -184, 0, 0, 0, 0, 0, 0, 0, 0, 0, -184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 639 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -865, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -865, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -184, -184, 0, -184, 0, -184, 0, -184, -184, 0, 0, -184, 0, -184, -184, 0, 0, -184, 0, -184, -184, 0, 0, -213, 0, 0, -184, -184, 0, -184, 0, -184, -184, -184, -184, 0, 0, -184, 0, 0, 0, 0, -184, 0, -184, 0, -184, -184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -184, 0, -184, -184, 0, 0, 0, -184, -184, 0, 0, 0, 0, 0, 0, 0, 0, 0, -184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 640 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -870, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 641 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -390, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -869, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 642 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -390, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 643 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 644 - 0, 0, 0, 0, 0, 0, 0, 0, -922, 0, 0, 0, 0, 0, 0, -922, 0, 0, 0, 0, 0, 0, 0, 0, 0, -922, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -183, -183, 0, -183, 0, -183, 0, -183, -183, 0, 0, -183, 0, -183, -183, 0, 0, -183, 0, -183, -183, 0, 0, -212, 0, 0, -183, -183, 0, -183, 0, -183, -183, -183, -183, 0, 0, -183, 0, 0, 0, 0, -183, 0, -183, 0, -183, -183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -183, 0, -183, -183, 0, 0, 0, -183, -183, 0, 0, 0, 0, 0, 0, 0, 0, 0, -183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 645 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -924, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 646 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -925, 0, 0, 0, 0, 0, 0, -925, 0, 0, 0, 0, 0, 0, 0, 0, 0, -925, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 647 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -923, 0, 0, 0, 0, 0, 0, 0, 0, 0, -925, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -927, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 648 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -940, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 649 - 0, 0, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -349, 0, 0, -349, 0, -349, -349, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 186, 0, -349, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -349, 0, -349, -349, 0, 0, 0, -349, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -926, 0, 0, 0, 0, 0, 0, 0, 0, 0, -928, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 650 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -351, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 651 - 0, 0, -211, -211, 0, -211, 0, -211, 0, -211, -211, 0, 0, -211, 0, -211, -211, 0, 0, -211, 0, -211, -211, 0, 0, -238, 0, 0, -211, -211, 0, -211, 0, -211, -211, -211, -211, 0, 0, -211, 0, 0, 0, 0, -211, 0, -211, 0, -211, -211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -211, 0, -211, -211, 0, 0, 0, -211, -211, 0, 0, 0, 0, 0, 0, 0, 0, 0, -211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -349, 0, 0, -349, 0, -349, -349, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 186, 0, -349, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -349, 0, -349, -349, 0, 0, 0, -349, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 652 - 0, 0, -209, -209, 0, -209, 0, -209, 0, -209, -209, 0, 0, -209, 0, -209, -209, 0, 0, -209, 0, -209, -209, 0, 0, -236, 0, 0, -209, -209, 0, -209, 0, -209, -209, -209, -209, 0, 0, -209, 0, 0, 0, 0, -209, 0, -209, 0, -209, -209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -209, 0, -209, -209, 0, 0, 0, -209, -209, 0, 0, 0, 0, 0, 0, 0, 0, 0, -209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -351, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 653 - 0, 0, -210, -210, 0, -210, 0, -210, 0, -210, -210, 0, 0, -210, 0, -210, -210, 0, 0, -210, 0, -210, -210, 0, 0, -237, 0, 0, -210, -210, 0, -210, 0, -210, -210, -210, -210, 0, 0, -210, 0, 0, 0, 0, -210, 0, -210, 0, -210, -210, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -210, 0, -210, -210, 0, 0, 0, -210, -210, 0, 0, 0, 0, 0, 0, 0, 0, 0, -210, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -211, -211, 0, -211, 0, -211, 0, -211, -211, 0, 0, -211, 0, -211, -211, 0, 0, -211, 0, -211, -211, 0, 0, -238, 0, 0, -211, -211, 0, -211, 0, -211, -211, -211, -211, 0, 0, -211, 0, 0, 0, 0, -211, 0, -211, 0, -211, -211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -211, 0, -211, -211, 0, 0, 0, -211, -211, 0, 0, 0, 0, 0, 0, 0, 0, 0, -211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 654 - 0, 0, -208, -208, 0, -208, 0, -208, 0, -208, -208, 0, 0, -208, 0, -208, -208, 0, 0, -208, 0, -208, -208, 0, 0, -235, 0, 0, -208, -208, 0, -208, 0, -208, -208, -208, -208, 0, 0, -208, 0, 0, 0, 0, -208, 0, -208, 0, -208, -208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -208, 0, -208, -208, 0, 0, 0, -208, -208, 0, 0, 0, 0, 0, 0, 0, 0, 0, -208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -209, -209, 0, -209, 0, -209, 0, -209, -209, 0, 0, -209, 0, -209, -209, 0, 0, -209, 0, -209, -209, 0, 0, -236, 0, 0, -209, -209, 0, -209, 0, -209, -209, -209, -209, 0, 0, -209, 0, 0, 0, 0, -209, 0, -209, 0, -209, -209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -209, 0, -209, -209, 0, 0, 0, -209, -209, 0, 0, 0, 0, 0, 0, 0, 0, 0, -209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 655 - 0, 0, 0, 0, 0, 0, 0, 0, 734, 0, 0, 0, 0, 0, 0, 735, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -210, -210, 0, -210, 0, -210, 0, -210, -210, 0, 0, -210, 0, -210, -210, 0, 0, -210, 0, -210, -210, 0, 0, -237, 0, 0, -210, -210, 0, -210, 0, -210, -210, -210, -210, 0, 0, -210, 0, 0, 0, 0, -210, 0, -210, 0, -210, -210, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -210, 0, -210, -210, 0, 0, 0, -210, -210, 0, 0, 0, 0, 0, 0, 0, 0, 0, -210, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 656 - -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, 0, -165, 0, -165, -165, -165, -165, -165, 0, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, 0, 0, 0, -165, -165, -165, -165, -165, -165, 0, -165, 0, 0, 0, 0, 0, 0, 0, 0, -165, 0, 0, -165, -165, 0, -165, 0, -165, -165, 0, 0, 0, -165, -165, 0, 0, 0, 0, 0, 0, 0, 0, 0, -165, -165, -165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -208, -208, 0, -208, 0, -208, 0, -208, -208, 0, 0, -208, 0, -208, -208, 0, 0, -208, 0, -208, -208, 0, 0, -235, 0, 0, -208, -208, 0, -208, 0, -208, -208, -208, -208, 0, 0, -208, 0, 0, 0, 0, -208, 0, -208, 0, -208, -208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -208, 0, -208, -208, 0, 0, 0, -208, -208, 0, 0, 0, 0, 0, 0, 0, 0, 0, -208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 657 - -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, 0, -162, 0, -162, -162, -162, -162, -162, 0, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, 0, 0, 0, -162, -162, -162, -162, -162, -162, 0, -162, 0, 0, 0, 0, 0, 0, 0, 0, -162, 0, 0, -162, -162, 0, -162, 0, -162, -162, 0, 0, 0, -162, -162, 0, 0, 0, 0, 0, 0, 0, 0, 0, -162, -162, -162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 736, 0, 0, 0, 0, 0, 0, 737, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 658 - 0, 0, 0, 0, 0, 0, 0, -118, -118, -118, -118, 0, 0, -118, 0, 0, -118, 0, 0, 0, -118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -118, -118, -118, -118, 0, 0, 0, 0, 0, 0, 0, -118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -118, 0, 0, -118, 0, 0, 0, 0, 0, 0, 0, 0, 0, -118, 0, 0, 0, -118, 0, 0, -118, 0, 0, 0, -118, -118, 0, -118, 0, -118, -118, + -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, 0, -165, 0, -165, -165, -165, -165, -165, 0, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, 0, 0, 0, -165, -165, -165, -165, -165, -165, 0, -165, 0, 0, 0, 0, 0, 0, 0, 0, -165, 0, 0, -165, -165, 0, -165, 0, -165, -165, 0, 0, 0, -165, -165, 0, 0, 0, 0, 0, 0, 0, 0, 0, -165, -165, -165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 659 - 0, 0, 0, 0, 0, 0, 0, 0, -417, 0, 0, 0, 0, 0, 0, -417, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, 0, -162, 0, -162, -162, -162, -162, -162, 0, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, 0, 0, 0, -162, -162, -162, -162, -162, -162, 0, -162, 0, 0, 0, 0, 0, 0, 0, 0, -162, 0, 0, -162, -162, 0, -162, 0, -162, -162, 0, 0, 0, -162, -162, 0, 0, 0, 0, 0, 0, 0, 0, 0, -162, -162, -162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 660 - 0, 0, 0, 0, 0, 0, 0, 0, -420, 0, 0, 0, 0, 0, 0, -420, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -118, -118, -118, -118, 0, 0, -118, 0, 0, -118, 0, 0, 0, -118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -118, -118, -118, -118, 0, 0, 0, 0, 0, 0, 0, -118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -118, 0, 0, -118, 0, 0, 0, 0, 0, 0, 0, 0, 0, -118, 0, 0, 0, -118, 0, 0, -118, 0, 0, 0, -118, -118, 0, -118, 0, -118, -118, // State 661 - 0, 0, 0, 0, 0, 0, 0, 0, -421, 0, 0, 0, 0, 0, 0, -421, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -417, 0, 0, 0, 0, 0, 0, -417, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 662 - -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, 0, -241, 0, -241, -241, -241, -241, -241, 0, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, 0, 0, 0, -241, -241, -241, -241, -241, -241, 0, -241, 0, 0, 0, 0, 0, 0, 0, 0, -241, 0, 0, -241, -241, 0, -241, 0, -241, -241, 0, 0, 0, -241, -241, 0, 0, 0, 0, 0, 0, 0, 0, 0, -241, -241, -241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -420, 0, 0, 0, 0, 0, 0, -420, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 663 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -846, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -846, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -421, 0, 0, 0, 0, 0, 0, -421, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 664 - -142, -142, -142, 0, -142, 0, -142, 0, -142, 0, 0, -142, -142, 0, -142, -142, 0, -142, 0, 0, 0, 0, 0, -142, -142, -142, 0, -142, -142, 0, -142, -142, -142, -142, -142, -142, 0, -142, 0, 0, -142, 0, 0, 0, 0, -142, 0, -142, -142, -142, 0, -142, 0, 0, 0, 0, 0, 0, 0, 0, -142, 0, 0, -142, -142, 0, -142, 0, -142, -142, 0, 0, 0, -142, -142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, -142, -142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, 0, -241, 0, -241, -241, -241, -241, -241, 0, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, 0, 0, 0, -241, -241, -241, -241, -241, -241, 0, -241, 0, 0, 0, 0, 0, 0, 0, 0, -241, 0, 0, -241, -241, 0, -241, 0, -241, -241, 0, 0, 0, -241, -241, 0, 0, 0, 0, 0, 0, 0, 0, 0, -241, -241, -241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 665 - -507, 0, 0, 0, 0, 0, 0, 0, -507, 0, 0, 0, 0, 0, 0, -507, 0, 0, 0, 0, 0, 0, 0, 0, 0, -507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -507, 0, 0, 0, 0, 0, -507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 666 - -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, 0, -201, 0, -201, -201, -201, -201, -201, 0, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, 0, 0, 0, -201, -201, -201, -201, -201, -201, 0, -201, 0, 0, 0, 0, 0, 0, 0, 0, -201, 0, 0, -201, -201, 0, -201, 0, -201, -201, 0, 0, 0, -201, -201, 0, 0, 0, 0, 0, 0, 0, 0, 0, -201, -201, -201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -142, -142, -142, 0, -142, 0, -142, 0, -142, 0, 0, -142, -142, 0, -142, -142, 0, -142, 0, 0, 0, 0, 0, -142, -142, -142, 0, -142, -142, 0, -142, -142, -142, -142, -142, -142, 0, -142, 0, 0, -142, 0, 0, 0, 0, -142, 0, -142, -142, -142, 0, -142, 0, 0, 0, 0, 0, 0, 0, 0, -142, 0, 0, -142, -142, 0, -142, 0, -142, -142, 0, 0, 0, -142, -142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, -142, -142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 667 - 0, 0, 0, 0, 0, 0, 0, 0, -800, 0, 0, 0, 0, 0, 0, -800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -800, 0, 0, 0, 0, 0, -800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -508, 0, 0, 0, 0, 0, 0, 0, -508, 0, 0, 0, 0, 0, 0, -508, 0, 0, 0, 0, 0, 0, 0, 0, 0, -508, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -508, 0, 0, 0, 0, 0, -508, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -508, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -508, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 668 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, 0, -201, 0, -201, -201, -201, -201, -201, 0, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, -201, 0, 0, 0, -201, -201, -201, -201, -201, -201, 0, -201, 0, 0, 0, 0, 0, 0, 0, 0, -201, 0, 0, -201, -201, 0, -201, 0, -201, -201, 0, 0, 0, -201, -201, 0, 0, 0, 0, 0, 0, 0, 0, 0, -201, -201, -201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 669 - -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, 0, -198, 0, -198, -198, -198, -198, -198, 0, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, 0, 0, 0, -198, -198, -198, -198, -198, -198, 0, -198, 0, 0, 0, 0, 0, 0, 0, 0, -198, 0, 0, -198, -198, 0, -198, 0, -198, -198, 0, 0, 0, -198, -198, 0, 0, 0, 0, 0, 0, 0, 0, 0, -198, -198, -198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -801, 0, 0, 0, 0, 0, 0, -801, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -801, 0, 0, 0, 0, 0, -801, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -801, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -801, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 670 - 0, 0, 0, 0, 0, 0, 0, 0, -65, 0, 0, 0, 0, 0, 0, -65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 671 - -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, 0, -192, 0, -192, -192, -192, -192, -192, 0, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, 0, 0, 0, -192, -192, -192, -192, -192, -192, 0, -192, 0, 0, 0, 0, 0, 0, 0, 0, -192, 0, 0, -192, -192, 0, -192, 0, -192, -192, 0, 0, 0, -192, -192, 0, 0, 0, 0, 0, 0, 0, 0, 0, -192, -192, -192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, 0, -198, 0, -198, -198, -198, -198, -198, 0, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, -198, 0, 0, 0, -198, -198, -198, -198, -198, -198, 0, -198, 0, 0, 0, 0, 0, 0, 0, 0, -198, 0, 0, -198, -198, 0, -198, 0, -198, -198, 0, 0, 0, -198, -198, 0, 0, 0, 0, 0, 0, 0, 0, 0, -198, -198, -198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 672 - 0, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -65, 0, 0, 0, 0, 0, 0, -65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 673 - 0, 0, 0, 0, 0, 0, 0, 0, -549, 0, 0, 0, 0, 0, 0, -549, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, 0, -192, 0, -192, -192, -192, -192, -192, 0, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, 0, 0, 0, -192, -192, -192, -192, -192, -192, 0, -192, 0, 0, 0, 0, 0, 0, 0, 0, -192, 0, 0, -192, -192, 0, -192, 0, -192, -192, 0, 0, 0, -192, -192, 0, 0, 0, 0, 0, 0, 0, 0, 0, -192, -192, -192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 674 - -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, 0, -189, 0, -189, -189, -189, -189, -189, 0, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, 0, 0, 0, -189, -189, -189, -189, -189, -189, 0, -189, 0, 0, 0, 0, 0, 0, 0, 0, -189, 0, 0, -189, -189, 0, -189, 0, -189, -189, 0, 0, 0, -189, -189, 0, 0, 0, 0, 0, 0, 0, 0, 0, -189, -189, -189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -512, 0, 0, 0, 0, 0, 0, -512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 675 - -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, 0, -202, 0, -202, -202, -202, -202, -202, 0, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, 0, 0, 0, -202, -202, -202, -202, -202, -202, 0, -202, 0, 0, 0, 0, 0, 0, 0, 0, -202, 0, 0, -202, -202, 0, -202, 0, -202, -202, 0, 0, 0, -202, -202, 0, 0, 0, 0, 0, 0, 0, 0, 0, -202, -202, -202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -550, 0, 0, 0, 0, 0, 0, -550, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 676 - -948, -948, 0, 0, 0, 0, 0, 0, -948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -948, 0, -948, 0, 0, 0, 0, -948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, 0, -189, 0, -189, -189, -189, -189, -189, 0, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, -189, 0, 0, 0, -189, -189, -189, -189, -189, -189, 0, -189, 0, 0, 0, 0, 0, 0, 0, 0, -189, 0, 0, -189, -189, 0, -189, 0, -189, -189, 0, 0, 0, -189, -189, 0, 0, 0, 0, 0, 0, 0, 0, 0, -189, -189, -189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 677 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -553, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -553, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -553, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, 0, -202, 0, -202, -202, -202, -202, -202, 0, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, -202, 0, 0, 0, -202, -202, -202, -202, -202, -202, 0, -202, 0, 0, 0, 0, 0, 0, 0, 0, -202, 0, 0, -202, -202, 0, -202, 0, -202, -202, 0, 0, 0, -202, -202, 0, 0, 0, 0, 0, 0, 0, 0, 0, -202, -202, -202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 678 - -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, 0, -188, 0, -188, -188, -188, -188, -188, 0, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, 0, 0, 0, -188, -188, -188, -188, -188, -188, 0, -188, 0, 0, 0, 0, 0, 0, 0, 0, -188, 0, 0, -188, -188, 0, -188, 0, -188, -188, 0, 0, 0, -188, -188, 0, 0, 0, 0, 0, 0, 0, 0, 0, -188, -188, -188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -951, -951, 0, 0, 0, 0, 0, 0, -951, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -951, 0, -951, 0, 0, 0, 0, -951, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -951, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 679 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 748, 0, 0, 0, 0, 0, 0, 0, 0, 0, -707, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 680 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -545, 0, 0, 0, 0, 0, 0, 0, 0, 0, -545, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, 0, -188, 0, -188, -188, -188, -188, -188, 0, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, -188, 0, 0, 0, -188, -188, -188, -188, -188, -188, 0, -188, 0, 0, 0, 0, 0, 0, 0, 0, -188, 0, 0, -188, -188, 0, -188, 0, -188, -188, 0, 0, 0, -188, -188, 0, 0, 0, 0, 0, 0, 0, 0, 0, -188, -188, -188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 681 - -462, -462, 0, 0, -462, 0, -462, 0, -462, 0, 0, -462, -462, 0, -462, -462, 0, -462, 0, 0, 0, 0, 0, -462, -462, -462, 0, -462, 0, 0, -462, 0, -462, 0, 0, 0, 0, -462, 0, 0, -462, 0, 0, 0, 0, -462, 0, -462, 0, -462, 0, -462, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -462, -462, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -462, -462, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, 0, 0, 0, 0, 0, 0, 0, -708, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 682 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -565, 0, 0, 0, 0, 0, 0, 0, 0, 0, -565, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -546, 0, 0, 0, 0, 0, 0, 0, 0, 0, -546, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 683 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, -724, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -462, -462, 0, 0, -462, 0, -462, 0, -462, 0, 0, -462, -462, 0, -462, -462, 0, -462, 0, 0, 0, 0, 0, -462, -462, -462, 0, -462, 0, 0, -462, 0, -462, 0, 0, 0, 0, -462, 0, 0, -462, 0, 0, 0, 0, -462, 0, -462, 0, -462, 0, -462, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -462, -462, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -462, -462, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 684 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 755, 0, 0, 0, 0, 0, 0, 0, 0, 0, -719, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -566, 0, 0, 0, 0, 0, 0, 0, 0, 0, -566, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 685 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -23, 0, 0, 0, 0, 0, 0, 0, 0, 0, -23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, -725, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 686 - -463, -463, 0, 0, -463, 0, -463, 0, -463, 0, 0, -463, -463, 0, -463, -463, 0, -463, 0, 0, 0, 0, 0, -463, -463, -463, 0, -463, 0, 0, -463, 0, -463, 0, 0, 0, 0, -463, 0, 0, -463, 0, 0, 0, 0, -463, 0, -463, 0, -463, 0, -463, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -463, -463, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -463, -463, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 757, 0, 0, 0, 0, 0, 0, 0, 0, 0, -720, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 687 - -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, 0, -205, 0, -205, -205, -205, -205, -205, 0, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, 0, 0, 0, -205, -205, -205, -205, -205, -205, 0, -205, 0, 0, 0, 0, 0, 0, 0, 0, -205, 0, 0, -205, -205, 0, -205, 0, -205, -205, 0, 0, 0, -205, -205, 0, 0, 0, 0, 0, 0, 0, 0, 0, -205, -205, -205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -23, 0, 0, 0, 0, 0, 0, 0, 0, 0, -23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 688 - -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, 0, -207, 0, -207, -207, -207, -207, -207, 0, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, 0, 0, 0, -207, -207, -207, -207, -207, -207, 0, -207, 0, 0, 0, 0, 0, 0, 0, 0, -207, 0, 0, -207, -207, 0, -207, 0, -207, -207, 0, 0, 0, -207, -207, 0, 0, 0, 0, 0, 0, 0, 0, 0, -207, -207, -207, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -463, -463, 0, 0, -463, 0, -463, 0, -463, 0, 0, -463, -463, 0, -463, -463, 0, -463, 0, 0, 0, 0, 0, -463, -463, -463, 0, -463, 0, 0, -463, 0, -463, 0, 0, 0, 0, -463, 0, 0, -463, 0, 0, 0, 0, -463, 0, -463, 0, -463, 0, -463, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -463, -463, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -463, -463, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 689 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -525, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -525, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, 0, -205, 0, -205, -205, -205, -205, -205, 0, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, 0, 0, 0, -205, -205, -205, -205, -205, -205, 0, -205, 0, 0, 0, 0, 0, 0, 0, 0, -205, 0, 0, -205, -205, 0, -205, 0, -205, -205, 0, 0, 0, -205, -205, 0, 0, 0, 0, 0, 0, 0, 0, 0, -205, -205, -205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 690 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, 0, -207, 0, -207, -207, -207, -207, -207, 0, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, -207, 0, 0, 0, -207, -207, -207, -207, -207, -207, 0, -207, 0, 0, 0, 0, 0, 0, 0, 0, -207, 0, 0, -207, -207, 0, -207, 0, -207, -207, 0, 0, 0, -207, -207, 0, 0, 0, 0, 0, 0, 0, 0, 0, -207, -207, -207, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 691 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -526, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -526, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 692 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 693 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 758, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 694 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 759, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 695 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -386, 0, 0, -386, 0, 0, -386, 0, 0, 0, 0, 0, 0, -386, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 760, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 696 - -773, 0, 0, 0, 0, 0, 0, -773, 0, -773, 0, 0, 0, -773, 0, 0, -773, 0, 0, 0, -773, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -773, 0, -773, -773, -773, -773, 0, 0, 0, 0, 0, -773, -773, -773, -773, 0, -773, -773, -773, -773, 0, 0, 0, 0, -773, -773, -773, -773, -773, 0, 0, -773, -773, -773, -773, 0, -773, -773, -773, -773, -773, -773, -773, -773, -773, 0, 0, 0, -773, 0, 0, -773, 0, 0, 0, -773, -773, 0, -773, -773, -773, -773, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 761, 0, // State 697 - 763, 0, 0, 0, 0, 0, 0, -135, 0, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -135, -135, -135, -135, 0, 0, 0, 0, 0, -135, 0, -135, -135, 0, 0, -135, 0, -135, 0, 0, 0, 0, 0, -135, -135, 0, -135, 0, 0, -135, 0, -135, -135, 0, -135, -135, -135, 0, -135, 0, 0, -135, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, -135, 0, -135, -135, -135, -135, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -386, 0, 0, -386, 0, 0, -386, 0, 0, 0, 0, 0, 0, -386, 0, 0, 0, 0, // State 698 - -86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -774, 0, 0, 0, 0, 0, 0, -774, 0, -774, 0, 0, 0, -774, 0, 0, -774, 0, 0, 0, -774, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -774, 0, -774, -774, -774, -774, 0, 0, 0, 0, 0, -774, -774, -774, -774, 0, -774, -774, -774, -774, 0, 0, 0, 0, -774, -774, -774, -774, -774, 0, 0, -774, -774, -774, -774, 0, -774, -774, -774, -774, -774, -774, -774, -774, -774, 0, 0, 0, -774, 0, 0, -774, 0, 0, 0, -774, -774, 0, -774, -774, -774, -774, // State 699 - -180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -180, 0, 0, 0, 0, -180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 765, 0, 0, 0, 0, 0, 0, -135, 0, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -135, -135, -135, -135, 0, 0, 0, 0, 0, -135, 0, -135, -135, 0, 0, -135, 0, -135, 0, 0, 0, 0, 0, -135, -135, 0, -135, 0, 0, -135, 0, -135, -135, 0, -135, -135, -135, 0, -135, 0, 0, -135, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, -135, 0, -135, -135, -135, -135, // State 700 - -360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 701 - -176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -176, 0, 0, 0, 0, -176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -180, 0, 0, 0, 0, -180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 702 - -175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -175, 0, 0, 0, 0, -175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 703 - -454, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -454, 0, 0, 0, 0, -454, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -176, 0, 0, 0, 0, -176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 704 - -770, 0, 0, 0, 0, 0, 0, -770, 0, -770, 0, 0, 0, -770, 0, 0, -770, 0, 0, 0, -770, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -770, 0, -770, -770, -770, -770, 0, 0, 0, 0, 0, -770, -770, -770, -770, 0, -770, -770, -770, -770, 0, 0, 0, 0, -770, -770, -770, -770, -770, 0, 0, -770, -770, -770, -770, 0, -770, -770, -770, -770, -770, -770, -770, -770, -770, 0, 0, 0, -770, 0, 0, -770, 0, 0, 0, -770, -770, 0, -770, -770, -770, -770, + -175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -175, 0, 0, 0, 0, -175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 705 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -320, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -320, 0, 0, 0, -320, 0, -320, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -454, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -454, 0, 0, 0, 0, -454, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 706 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -771, 0, 0, 0, 0, 0, 0, -771, 0, -771, 0, 0, 0, -771, 0, 0, -771, 0, 0, 0, -771, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -771, 0, -771, -771, -771, -771, 0, 0, 0, 0, 0, -771, -771, -771, -771, 0, -771, -771, -771, -771, 0, 0, 0, 0, -771, -771, -771, -771, -771, 0, 0, -771, -771, -771, -771, 0, -771, -771, -771, -771, -771, -771, -771, -771, -771, 0, 0, 0, -771, 0, 0, -771, 0, 0, 0, -771, -771, 0, -771, -771, -771, -771, // State 707 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 210, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -320, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -320, 0, 0, 0, -320, 0, -320, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 708 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 709 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 215, 0, 0, 0, 0, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 210, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 710 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -450, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 711 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -448, -448, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -448, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -448, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 215, 0, 0, 0, 0, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 712 - -334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -334, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0, -334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -450, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 713 - 794, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -448, -448, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -448, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -448, 0, // State 714 - 797, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -334, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0, -334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 715 - 800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 801, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 796, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 716 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 799, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 717 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 802, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 803, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 718 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -558, 0, 0, 0, 0, 0, 0, 0, 0, 0, -560, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -558, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -558, 0, 0, 0, 0, 0, 0, 0, 531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 719 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -158, 0, 0, 0, 0, 0, 0, 0, 0, 0, -160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 532, -158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -158, 0, 0, 0, 0, 0, 0, 0, -158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 720 - 0, 0, -240, -240, 0, -240, 0, -240, 0, -240, -240, 0, 0, -240, 0, -240, -240, 0, 0, -240, 0, -240, -240, 0, 0, -244, 0, 0, -240, -240, 0, -240, 0, -240, -240, -240, -240, 0, 0, -240, 0, 0, 0, 0, -240, 0, -240, 0, -240, -240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -240, 0, -240, -240, 0, 0, 0, -240, -240, 0, 0, 0, 0, 0, 0, 0, 0, 0, -240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -559, 0, 0, 0, 0, 0, 0, 0, 0, 0, -561, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -559, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -559, 0, 0, 0, 0, 0, 0, 0, 532, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 721 - 0, 0, -387, -387, 0, -387, 0, 0, 0, -387, 0, 0, 0, -387, 0, -387, -387, 0, 0, 0, 0, -387, -387, 0, 0, -389, 0, 0, -387, -387, 0, -387, 0, -387, -387, -387, -387, 0, 0, -387, 0, 0, 0, 0, 0, 0, -387, 0, -387, -387, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -387, 0, -387, -387, 0, 0, 0, -387, -387, 0, 0, 0, 0, 0, 0, 0, 0, 0, -387, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -158, 0, 0, 0, 0, 0, 0, 0, 0, 0, -160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 533, -158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -158, 0, 0, 0, 0, 0, 0, 0, -158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 722 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, -938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -240, -240, 0, -240, 0, -240, 0, -240, -240, 0, 0, -240, 0, -240, -240, 0, 0, -240, 0, -240, -240, 0, 0, -244, 0, 0, -240, -240, 0, -240, 0, -240, -240, -240, -240, 0, 0, -240, 0, 0, 0, 0, -240, 0, -240, 0, -240, -240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -240, 0, -240, -240, 0, 0, 0, -240, -240, 0, 0, 0, 0, 0, 0, 0, 0, 0, -240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 723 - 0, 0, 0, 0, 0, 0, 0, 0, 821, 0, 0, 0, 0, 0, 0, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -387, -387, 0, -387, 0, 0, 0, -387, 0, 0, 0, -387, 0, -387, -387, 0, 0, 0, 0, -387, -387, 0, 0, -389, 0, 0, -387, -387, 0, -387, 0, -387, -387, -387, -387, 0, 0, -387, 0, 0, 0, 0, 0, 0, -387, 0, -387, -387, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -387, 0, -387, -387, 0, 0, 0, -387, -387, 0, 0, 0, 0, 0, 0, 0, 0, 0, -387, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 724 - 0, 0, 0, 0, 0, 0, 0, 0, -548, 0, 0, 0, 0, 0, 0, -548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 183, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, -941, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 725 - 0, 0, 0, 0, 0, 0, 0, 0, 824, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 823, 0, 0, 0, 0, 0, 0, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 726 - 0, 0, -199, -199, 0, -199, 0, -199, 0, -199, -199, 0, 0, -199, 0, -199, -199, 0, 0, -199, 0, -199, -199, 0, 0, -226, 0, 0, -199, -199, 0, -199, 0, -199, -199, -199, -199, 0, 0, -199, 0, 0, 0, 0, -199, 0, -199, 0, -199, -199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -199, 0, -199, -199, 0, 0, 0, -199, -199, 0, 0, 0, 0, 0, 0, 0, 0, 0, -199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -549, 0, 0, 0, 0, 0, 0, -549, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 183, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 727 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 826, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 826, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 728 - 0, 0, -187, -187, 0, -187, 0, -187, 0, -187, -187, 0, 0, -187, 0, -187, -187, 0, 0, -187, 0, -187, -187, 0, 0, -216, 0, 0, -187, -187, 0, -187, 0, -187, -187, -187, -187, 0, 0, -187, 0, 0, 0, 0, -187, 0, -187, 0, -187, -187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -187, 0, -187, -187, 0, 0, 0, -187, -187, 0, 0, 0, 0, 0, 0, 0, 0, 0, -187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -199, -199, 0, -199, 0, -199, 0, -199, -199, 0, 0, -199, 0, -199, -199, 0, 0, -199, 0, -199, -199, 0, 0, -226, 0, 0, -199, -199, 0, -199, 0, -199, -199, -199, -199, 0, 0, -199, 0, 0, 0, 0, -199, 0, -199, 0, -199, -199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -199, 0, -199, -199, 0, 0, 0, -199, -199, 0, 0, 0, 0, 0, 0, 0, 0, 0, -199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 729 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -514, 0, 0, 0, 0, 0, 0, 0, 0, 0, -516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -514, -514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -514, 0, 0, 0, 0, 0, 0, 0, -514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 828, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 730 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 829, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -187, -187, 0, -187, 0, -187, 0, -187, -187, 0, 0, -187, 0, -187, -187, 0, 0, -187, 0, -187, -187, 0, 0, -216, 0, 0, -187, -187, 0, -187, 0, -187, -187, -187, -187, 0, 0, -187, 0, 0, 0, 0, -187, 0, -187, 0, -187, -187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -187, 0, -187, -187, 0, 0, 0, -187, -187, 0, 0, 0, 0, 0, 0, 0, 0, 0, -187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 731 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -515, 0, 0, 0, 0, 0, 0, 0, 0, 0, -517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -515, -515, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -515, 0, 0, 0, 0, 0, 0, 0, -515, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 732 - 0, 0, -204, -204, 0, -204, 0, -204, 0, -204, -204, 0, 0, -204, 0, -204, -204, 0, 0, -204, 0, -204, -204, 0, 0, -231, 0, 0, -204, -204, 0, -204, 0, -204, -204, -204, -204, 0, 0, -204, 0, 0, 0, 0, -204, 0, -204, 0, -204, -204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -204, 0, -204, -204, 0, 0, 0, -204, -204, 0, 0, 0, 0, 0, 0, 0, 0, 0, -204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 733 - -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, 0, -164, 0, -164, -164, -164, -164, -164, 0, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, 0, 0, 0, -164, -164, -164, -164, -164, -164, 0, -164, 0, 0, 0, 0, 0, 0, 0, 0, -164, 0, 0, -164, -164, 0, -164, 0, -164, -164, 0, 0, 0, -164, -164, 0, 0, 0, 0, 0, 0, 0, 0, 0, -164, -164, -164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 833, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 734 - 0, 0, 0, 0, 0, 0, 0, -119, -119, -119, -119, 0, 0, -119, 0, 0, -119, 0, 0, 0, -119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -119, -119, -119, -119, 0, 0, 0, 0, 0, 0, 0, -119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -119, 0, 0, -119, 0, 0, 0, 0, 0, 0, 0, 0, 0, -119, 0, 0, 0, -119, 0, 0, -119, 0, 0, 0, -119, -119, 0, -119, 0, -119, -119, + 0, 0, -204, -204, 0, -204, 0, -204, 0, -204, -204, 0, 0, -204, 0, -204, -204, 0, 0, -204, 0, -204, -204, 0, 0, -231, 0, 0, -204, -204, 0, -204, 0, -204, -204, -204, -204, 0, 0, -204, 0, 0, 0, 0, -204, 0, -204, 0, -204, -204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -204, 0, -204, -204, 0, 0, 0, -204, -204, 0, 0, 0, 0, 0, 0, 0, 0, 0, -204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 735 - 0, 0, 0, 0, 0, 0, 0, 0, -419, 0, 0, 0, 0, 0, 0, -419, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, 0, -164, 0, -164, -164, -164, -164, -164, 0, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, 0, 0, 0, -164, -164, -164, -164, -164, -164, 0, -164, 0, 0, 0, 0, 0, 0, 0, 0, -164, 0, 0, -164, -164, 0, -164, 0, -164, -164, 0, 0, 0, -164, -164, 0, 0, 0, 0, 0, 0, 0, 0, 0, -164, -164, -164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 736 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -119, -119, -119, -119, 0, 0, -119, 0, 0, -119, 0, 0, 0, -119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -119, -119, -119, -119, 0, 0, 0, 0, 0, 0, 0, -119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -119, 0, 0, -119, 0, 0, 0, 0, 0, 0, 0, 0, 0, -119, 0, 0, 0, -119, 0, 0, -119, 0, 0, 0, -119, -119, 0, -119, 0, -119, -119, // State 737 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -844, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -844, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -419, 0, 0, 0, 0, 0, 0, -419, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 738 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -899, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -899, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -901, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -901, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 739 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -843, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -843, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 740 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -801, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -801, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -902, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -902, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 741 - -864, -864, 0, 0, -864, 0, -864, 0, -864, 0, 0, -864, -864, 0, -864, -864, 0, -864, 0, 0, 0, 0, 0, -864, -864, -864, 0, -864, 0, 0, -864, 0, -864, 0, 0, 0, 0, -864, 0, 0, -864, 0, 0, 0, 0, -864, 0, -864, 0, -864, 0, -864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -864, -864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -864, -864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -844, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -844, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 742 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -802, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -802, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 743 - 0, 0, 0, 0, 0, 0, 0, 0, -66, 0, 0, 0, 0, 0, 0, -66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -863, -863, 0, 0, -863, 0, -863, 0, -863, 0, 0, -863, -863, 0, -863, -863, 0, -863, 0, 0, 0, 0, 0, -863, -863, -863, 0, -863, 0, 0, -863, 0, -863, 0, 0, 0, 0, -863, 0, 0, -863, 0, 0, 0, 0, -863, 0, -863, 0, -863, 0, -863, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -863, -863, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -863, -863, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 744 - -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, 0, -194, 0, -194, -194, -194, -194, -194, 0, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, 0, 0, 0, -194, -194, -194, -194, -194, -194, 0, -194, 0, 0, 0, 0, 0, 0, 0, 0, -194, 0, 0, -194, -194, 0, -194, 0, -194, -194, 0, 0, 0, -194, -194, 0, 0, 0, 0, 0, 0, 0, 0, 0, -194, -194, -194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 745 - 0, 0, 0, 0, 0, 0, 0, 0, 833, 0, 0, 0, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -66, 0, 0, 0, 0, 0, 0, -66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 746 - -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, 0, -195, 0, -195, -195, -195, -195, -195, 0, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, 0, 0, 0, -195, -195, -195, -195, -195, -195, 0, -195, 0, 0, 0, 0, 0, 0, 0, 0, -195, 0, 0, -195, -195, 0, -195, 0, -195, -195, 0, 0, 0, -195, -195, 0, 0, 0, 0, 0, 0, 0, 0, 0, -195, -195, -195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, 0, -194, 0, -194, -194, -194, -194, -194, 0, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, -194, 0, 0, 0, -194, -194, -194, -194, -194, -194, 0, -194, 0, 0, 0, 0, 0, 0, 0, 0, -194, 0, 0, -194, -194, 0, -194, 0, -194, -194, 0, 0, 0, -194, -194, 0, 0, 0, 0, 0, 0, 0, 0, 0, -194, -194, -194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 747 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -704, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 835, 0, 0, 0, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 748 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, -698, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, 0, -195, 0, -195, -195, -195, -195, -195, 0, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, -195, 0, 0, 0, -195, -195, -195, -195, -195, -195, 0, -195, 0, 0, 0, 0, 0, 0, 0, 0, -195, 0, 0, -195, -195, 0, -195, 0, -195, -195, 0, 0, 0, -195, -195, 0, 0, 0, 0, 0, 0, 0, 0, 0, -195, -195, -195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 749 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, -703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -705, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 750 - -461, -461, 0, 0, -461, 0, -461, 0, -461, 0, 0, -461, -461, 0, -461, -461, 0, -461, 0, 0, 0, 0, 0, -461, -461, -461, 0, -461, 0, 0, -461, 0, -461, 0, 0, 0, 0, -461, 0, 0, -461, 0, 0, 0, 0, -461, 0, -461, 0, -461, 0, -461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -461, -461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -461, -461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, -699, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 751 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 838, 0, 0, 0, 0, 0, 0, 0, 0, 0, -721, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, -704, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 752 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -24, 0, 0, 0, 0, 0, 0, 0, 0, 0, -24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -461, -461, 0, 0, -461, 0, -461, 0, -461, 0, 0, -461, -461, 0, -461, -461, 0, -461, 0, 0, 0, 0, 0, -461, -461, -461, 0, -461, 0, 0, -461, 0, -461, 0, 0, 0, 0, -461, 0, 0, -461, 0, 0, 0, 0, -461, 0, -461, 0, -461, 0, -461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -461, -461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -461, -461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 753 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 840, 0, 0, 0, 0, 0, 0, 0, 0, 0, -718, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 840, 0, 0, 0, 0, 0, 0, 0, 0, 0, -722, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 754 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -711, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -24, 0, 0, 0, 0, 0, 0, 0, 0, 0, -24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 755 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 841, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 842, 0, 0, 0, 0, 0, 0, 0, 0, 0, -719, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 756 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -384, 0, 0, -384, 0, 0, -384, 0, 0, 0, 0, 0, 0, -384, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -712, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 757 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -385, 0, 0, -385, 0, 0, -385, 0, 0, 0, 0, 0, 0, -385, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 843, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 758 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -363, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -363, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -384, 0, 0, -384, 0, 0, -384, 0, 0, 0, 0, 0, 0, -384, 0, 0, 0, 0, // State 759 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -370, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -385, 0, 0, -385, 0, 0, -385, 0, 0, 0, 0, 0, 0, -385, 0, 0, 0, 0, // State 760 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 844, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -363, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -363, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 761 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -382, 0, 0, -382, 0, 0, -382, 0, 0, 0, 0, 0, 0, -382, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -370, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 762 - -771, 0, 0, 0, 0, 0, 0, -771, 0, -771, 0, 0, 0, -771, 0, 0, -771, 0, 0, 0, -771, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -771, 0, -771, -771, -771, -771, 0, 0, 0, 0, 0, -771, -771, -771, -771, 0, -771, -771, -771, -771, 0, 0, 0, 0, -771, -771, -771, -771, -771, 0, 0, -771, -771, -771, -771, 0, -771, -771, -771, -771, -771, -771, -771, -771, -771, 0, 0, 0, -771, 0, 0, -771, 0, 0, 0, -771, -771, 0, -771, -771, -771, -771, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 846, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 763 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -382, 0, 0, -382, 0, 0, -382, 0, 0, 0, 0, 0, 0, -382, 0, 0, 0, 0, // State 764 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 0, 0, 0, 0, 0, 0, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -772, 0, 0, 0, 0, 0, 0, -772, 0, -772, 0, 0, 0, -772, 0, 0, -772, 0, 0, 0, -772, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -772, 0, -772, -772, -772, -772, 0, 0, 0, 0, 0, -772, -772, -772, -772, 0, -772, -772, -772, -772, 0, 0, 0, 0, -772, -772, -772, -772, -772, 0, 0, -772, -772, -772, -772, 0, -772, -772, -772, -772, -772, -772, -772, -772, -772, 0, 0, 0, -772, 0, 0, -772, 0, 0, 0, -772, -772, 0, -772, -772, -772, -772, // State 765 - -361, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -361, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 766 - -173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 0, 0, 0, 0, 0, 0, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 767 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 0, 0, 0, 0, 0, 0, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -361, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -361, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 768 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 769 - -270, 0, 0, 0, 0, 0, 0, -270, 0, -270, 0, 0, 0, -270, 0, 0, -270, 0, 0, 0, -270, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -270, 0, -270, -270, -270, -270, 0, 0, 0, 0, 0, -270, -270, -270, -270, 0, -270, -270, -270, -270, 0, 0, 0, 0, -270, -270, -270, -270, -270, 0, 0, -270, -270, -270, -270, 0, -270, -270, -270, -270, -270, -270, -270, -270, -270, 0, 0, 0, -270, -270, 0, -270, 0, 0, 0, -270, -270, 0, -270, -270, -270, -270, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 0, 0, 0, 0, 0, 0, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 770 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -906, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -906, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 771 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 854, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -270, 0, 0, 0, 0, 0, 0, -270, 0, -270, 0, 0, 0, -270, 0, 0, -270, 0, 0, 0, -270, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -270, 0, -270, -270, -270, -270, 0, 0, 0, 0, 0, -270, -270, -270, -270, 0, -270, -270, -270, -270, 0, 0, 0, 0, -270, -270, -270, -270, -270, 0, 0, -270, -270, -270, -270, 0, -270, -270, -270, -270, -270, -270, -270, -270, -270, 0, 0, 0, -270, -270, 0, -270, 0, 0, 0, -270, -270, 0, -270, -270, -270, -270, // State 772 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -909, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -909, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 773 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 251, 0, 0, 0, 0, 0, 0, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 856, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 774 - 0, 0, 0, 0, 0, 0, 0, 0, -914, 0, 0, 0, 0, 0, 0, -914, 0, 0, 0, 0, 0, 0, 0, 0, 0, 253, 0, 0, 0, 0, 0, 0, -914, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 775 - 0, 0, 0, 0, 0, 0, 0, 0, -649, 0, 0, 0, 0, 0, 0, 859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 251, 0, 0, 0, 0, 0, 0, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 776 - 0, 0, 0, 0, 0, 0, 0, 0, -623, 0, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -917, 0, 0, 0, 0, 0, 0, -917, 0, 0, 0, 0, 0, 0, 0, 0, 0, 253, 0, 0, 0, 0, 0, 0, -917, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 777 - 0, 0, 0, 0, 0, 0, 0, 0, -542, 0, 0, 0, 0, 0, 0, -542, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -650, 0, 0, 0, 0, 0, 0, 861, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 778 - 0, 0, 0, 0, 0, 0, 0, 0, 860, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -624, 0, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 779 - 0, 0, 0, 0, 0, 0, 0, 0, -562, 0, 0, 0, 0, 0, 0, -562, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -543, 0, 0, 0, 0, 0, 0, -543, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 780 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -747, 0, 0, 0, 0, 0, 0, -747, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 862, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 781 - -527, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -527, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -527, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -527, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -563, 0, 0, 0, 0, 0, 0, -563, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 782 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -748, 0, 0, 0, 0, 0, 0, -748, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 783 - -535, 0, 0, 0, 0, 0, 0, 0, -535, 0, 0, 0, 0, 0, 0, -535, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -535, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 784 - -453, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -453, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 785 - -439, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 260, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -439, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -536, 0, 0, 0, 0, 0, 0, 0, -536, 0, 0, 0, 0, 0, 0, -536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 786 - -442, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -442, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -453, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -453, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 787 - -76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -76, 0, 0, 0, -76, 0, 0, 0, 0, 0, 0, 0, -76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -439, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 260, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -439, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 788 - -529, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -529, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -529, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -442, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -442, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 789 - -530, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -530, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -530, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -76, 0, 0, 0, -76, 0, 0, 0, 0, 0, 0, 0, -76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 790 - -533, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -533, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -533, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -530, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -530, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -530, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 791 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -900, 0, 0, 0, 0, 0, 0, 0, 0, 0, -900, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 792 - 869, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 793 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 263, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -903, 0, 0, 0, 0, 0, 0, 0, 0, 0, -903, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 794 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -901, 0, 0, 0, 0, 0, 0, 0, 0, 0, -901, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 871, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 795 - 870, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 263, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 796 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 264, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -904, 0, 0, 0, 0, 0, 0, 0, 0, 0, -904, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 797 - -776, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -776, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 872, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 798 - 871, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 872, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 264, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 799 - -857, 0, 0, 0, 0, 0, 0, -857, 0, -857, 0, 0, 0, -857, 0, 0, -857, 0, 0, 0, -857, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -857, 0, -857, -857, -857, -857, 0, 0, 0, 0, 0, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, 0, 0, -857, -857, -857, -857, 0, -857, -857, -857, -857, -857, -857, -857, -857, -857, 0, 0, 0, -857, -857, 0, -857, 0, 0, 0, -857, -857, 0, -857, -857, -857, -857, + -777, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -777, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 800 - 873, 0, 0, 0, 0, 0, 0, -134, 0, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -134, -134, -134, -134, 0, 0, 0, 0, 0, -134, 0, -134, -134, 0, 0, -134, 0, -134, 0, 0, 0, 0, 0, -134, -134, 0, -134, 0, 0, -134, 0, -134, -134, 0, -134, -134, -134, 0, -134, 0, 0, -134, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, -134, 0, -134, -134, -134, -134, + 873, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 801 - -342, 0, 0, 0, 0, 0, 0, -342, 0, -342, 0, 0, 0, -342, 0, 0, -342, 0, 0, 0, -342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -342, 0, -342, -342, -342, -342, 0, 0, 0, 0, 0, -342, -342, -342, -342, 0, -342, -342, -342, -342, 0, -342, -342, -342, -342, -342, -342, -342, -342, 0, 0, -342, -342, -342, -342, 0, -342, -342, -342, -342, -342, -342, -342, -342, -342, 0, 0, 0, -342, -342, 0, -342, 0, 0, 0, -342, -342, 0, -342, -342, -342, -342, + -856, 0, 0, 0, 0, 0, 0, -856, 0, -856, 0, 0, 0, -856, 0, 0, -856, 0, 0, 0, -856, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -856, 0, -856, -856, -856, -856, 0, 0, 0, 0, 0, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, 0, 0, -856, -856, -856, -856, 0, -856, -856, -856, -856, -856, -856, -856, -856, -856, 0, 0, 0, -856, -856, 0, -856, 0, 0, 0, -856, -856, 0, -856, -856, -856, -856, // State 802 - -346, 0, 0, 0, 0, 0, 0, -346, 0, -346, 0, 0, 0, -346, 0, 0, -346, 0, 0, 0, -346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -346, 0, -346, -346, -346, -346, 0, 0, 0, 0, 0, -346, -346, -346, -346, 0, -346, -346, -346, -346, 0, -346, -346, -346, -346, -346, -346, -346, -346, 0, 0, -346, -346, -346, -346, 0, -346, -346, -346, -346, -346, -346, -346, -346, -346, 0, 0, 0, -346, -346, 0, -346, 0, 0, 0, -346, -346, 0, -346, -346, -346, -346, + 875, 0, 0, 0, 0, 0, 0, -134, 0, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -134, -134, -134, -134, 0, 0, 0, 0, 0, -134, 0, -134, -134, 0, 0, -134, 0, -134, 0, 0, 0, 0, 0, -134, -134, 0, -134, 0, 0, -134, 0, -134, -134, 0, -134, -134, -134, 0, -134, 0, 0, -134, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, -134, 0, -134, -134, -134, -134, // State 803 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -342, 0, 0, 0, 0, 0, 0, -342, 0, -342, 0, 0, 0, -342, 0, 0, -342, 0, 0, 0, -342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -342, 0, -342, -342, -342, -342, 0, 0, 0, 0, 0, -342, -342, -342, -342, 0, -342, -342, -342, -342, 0, -342, -342, -342, -342, -342, -342, -342, -342, 0, 0, -342, -342, -342, -342, 0, -342, -342, -342, -342, -342, -342, -342, -342, -342, 0, 0, 0, -342, -342, 0, -342, 0, 0, 0, -342, -342, 0, -342, -342, -342, -342, // State 804 - -904, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -904, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -346, 0, 0, 0, 0, 0, 0, -346, 0, -346, 0, 0, 0, -346, 0, 0, -346, 0, 0, 0, -346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -346, 0, -346, -346, -346, -346, 0, 0, 0, 0, 0, -346, -346, -346, -346, 0, -346, -346, -346, -346, 0, -346, -346, -346, -346, -346, -346, -346, -346, 0, 0, -346, -346, -346, -346, 0, -346, -346, -346, -346, -346, -346, -346, -346, -346, 0, 0, 0, -346, -346, 0, -346, 0, 0, 0, -346, -346, 0, -346, -346, -346, -346, // State 805 - -921, 0, 0, 0, 0, 0, 0, -921, 0, -921, 0, 0, 0, -921, 0, 0, -921, 0, 0, 0, -921, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -921, 0, -921, -921, -921, -921, 0, 0, 0, 0, 0, -921, -921, -921, -921, 0, -921, -921, -921, -921, 0, 885, 0, 0, -921, -921, -921, -921, -921, 0, 0, -921, -921, -921, -921, 0, -921, -921, -921, -921, -921, -921, -921, -921, -921, 0, 0, 0, -921, -921, 0, -921, 0, 0, 0, -921, -921, 0, -921, -921, -921, -921, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 806 - 0, 0, -242, -242, 0, -242, 0, -242, 0, -242, -242, 0, 0, -242, 0, -242, -242, 0, 0, -242, 0, -242, -242, 0, 0, -246, 0, 0, -242, -242, 0, -242, 0, -242, -242, -242, -242, 0, 0, -242, 0, 0, 0, 0, -242, 0, -242, 0, -242, -242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -242, 0, -242, -242, 0, 0, 0, -242, -242, 0, 0, 0, 0, 0, 0, 0, 0, 0, -242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -907, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -907, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 807 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 886, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -924, 0, 0, 0, 0, 0, 0, -924, 0, -924, 0, 0, 0, -924, 0, 0, -924, 0, 0, 0, -924, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -924, 0, -924, -924, -924, -924, 0, 0, 0, 0, 0, -924, -924, -924, -924, 0, -924, -924, -924, -924, 0, 887, 0, 0, -924, -924, -924, -924, -924, 0, 0, -924, -924, -924, -924, 0, -924, -924, -924, -924, -924, -924, -924, -924, -924, 0, 0, 0, -924, -924, 0, -924, 0, 0, 0, -924, -924, 0, -924, -924, -924, -924, // State 808 - 0, 0, -764, -764, 0, -764, 0, 0, 0, -764, 0, 0, 0, -764, 0, -764, -764, 0, 0, 0, 0, -764, -764, 0, 0, -766, 0, 0, -764, -764, 0, -764, 0, -764, -764, -764, -764, 0, 0, -764, 0, 0, 0, 0, 0, 0, -764, 0, -764, -764, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -764, 0, -764, -764, 0, 0, 0, -764, -764, 0, 0, 0, 0, 0, 0, 0, 0, 0, -764, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -242, -242, 0, -242, 0, -242, 0, -242, -242, 0, 0, -242, 0, -242, -242, 0, 0, -242, 0, -242, -242, 0, 0, -246, 0, 0, -242, -242, 0, -242, 0, -242, -242, -242, -242, 0, 0, -242, 0, 0, 0, 0, -242, 0, -242, 0, -242, -242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -242, 0, -242, -242, 0, 0, 0, -242, -242, 0, 0, 0, 0, 0, 0, 0, 0, 0, -242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 809 - 0, 0, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, -350, 0, 0, -348, 0, 0, -348, 0, -348, -348, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, -348, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -348, 0, -348, -348, 0, 0, 0, -348, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 888, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 810 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 271, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -765, -765, 0, -765, 0, 0, 0, -765, 0, 0, 0, -765, 0, -765, -765, 0, 0, 0, 0, -765, -765, 0, 0, -767, 0, 0, -765, -765, 0, -765, 0, -765, -765, -765, -765, 0, 0, -765, 0, 0, 0, 0, 0, 0, -765, 0, -765, -765, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -765, 0, -765, -765, 0, 0, 0, -765, -765, 0, 0, 0, 0, 0, 0, 0, 0, 0, -765, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 811 - 0, 0, -860, -860, 0, -860, 0, 0, 0, -860, 0, 0, 0, -860, 0, -860, -860, 0, 0, 0, 0, -860, -860, 0, 0, -862, 0, 0, -860, -860, 0, -860, 0, -860, -860, -860, -860, 0, 0, -860, 0, 0, 0, 0, 0, 0, -860, 0, -860, -860, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -860, 0, -860, -860, 0, 0, 0, -860, -860, 0, 0, 0, 0, 0, 0, 0, 0, 0, -860, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, -350, 0, 0, -348, 0, 0, -348, 0, -348, -348, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, -348, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -348, 0, -348, -348, 0, 0, 0, -348, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, -348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 812 - 0, 0, 0, 0, 0, 0, 0, 0, -926, 0, 0, 0, 0, 0, 0, -926, 0, 0, 0, 0, 0, 0, 0, 0, 0, -926, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 271, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 813 - 0, 0, 0, 0, 0, 0, 0, 0, -70, 0, 0, 0, 0, 0, 0, -70, 0, 0, 0, 0, 0, 0, 0, 0, 0, -70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -859, -859, 0, -859, 0, 0, 0, -859, 0, 0, 0, -859, 0, -859, -859, 0, 0, 0, 0, -859, -859, 0, 0, -861, 0, 0, -859, -859, 0, -859, 0, -859, -859, -859, -859, 0, 0, -859, 0, 0, 0, 0, 0, 0, -859, 0, -859, -859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -859, 0, -859, -859, 0, 0, 0, -859, -859, 0, 0, 0, 0, 0, 0, 0, 0, 0, -859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 814 - 0, 0, 0, 0, 0, 0, 0, 0, -923, 0, 0, 0, 0, 0, 0, -923, 0, 0, 0, 0, 0, 0, 0, 0, 0, -923, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -929, 0, 0, 0, 0, 0, 0, -929, 0, 0, 0, 0, 0, 0, 0, 0, 0, -929, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 815 - -941, 0, 0, 0, 0, 0, 0, -941, 0, -941, 0, 0, 0, -941, 0, 0, -941, 0, 0, 0, -941, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -941, 0, -941, -941, -941, -941, 0, 0, 0, 0, 0, -941, -941, -941, -941, 0, -941, -941, -941, -941, 0, 0, 0, 0, -941, -941, -941, -941, -941, 0, 0, -941, -941, -941, -941, 0, -941, -941, -941, -941, -941, -941, -941, -941, -941, 0, 0, 0, -941, -941, 0, -941, 0, 0, 0, -941, -941, 0, -941, -941, -941, -941, + 0, 0, 0, 0, 0, 0, 0, 0, -70, 0, 0, 0, 0, 0, 0, -70, 0, 0, 0, 0, 0, 0, 0, 0, 0, -70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 816 - 0, 0, -942, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, -942, 0, 0, 0, 0, 0, 0, 0, 0, 0, -944, 0, 0, -942, 0, 0, -942, 0, -942, -942, -942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -942, 0, -942, -942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -942, 0, -942, -942, 0, 0, 0, -942, -942, 0, 0, 0, 0, 0, 0, 0, 0, 0, -942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -926, 0, 0, 0, 0, 0, 0, -926, 0, 0, 0, 0, 0, 0, 0, 0, 0, -926, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 817 - 0, 0, 0, 0, 0, 0, 0, 0, 888, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -944, 0, 0, 0, 0, 0, 0, -944, 0, -944, 0, 0, 0, -944, 0, 0, -944, 0, 0, 0, -944, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -944, 0, -944, -944, -944, -944, 0, 0, 0, 0, 0, -944, -944, -944, -944, 0, -944, -944, -944, -944, 0, 0, 0, 0, -944, -944, -944, -944, -944, 0, 0, -944, -944, -944, -944, 0, -944, -944, -944, -944, -944, -944, -944, -944, -944, 0, 0, 0, -944, -944, 0, -944, 0, 0, 0, -944, -944, 0, -944, -944, -944, -944, // State 818 - 0, 0, 0, 0, 0, 0, 0, 0, 889, 0, 0, 0, 0, 0, 0, 272, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -945, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, -945, 0, 0, 0, 0, 0, 0, 0, 0, 0, -947, 0, 0, -945, 0, 0, -945, 0, -945, -945, -945, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -945, 0, -945, -945, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -945, 0, -945, -945, 0, 0, 0, -945, -945, 0, 0, 0, 0, 0, 0, 0, 0, 0, -945, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 819 - 0, 0, -196, -196, 0, -196, 0, -196, 0, -196, -196, 0, 0, -196, 0, -196, -196, 0, 0, -196, 0, -196, -196, 0, 0, -223, 0, 0, -196, -196, 0, -196, 0, -196, -196, -196, -196, 0, 0, -196, 0, 0, 0, 0, -196, 0, -196, 0, -196, -196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -196, 0, -196, -196, 0, 0, 0, -196, -196, 0, 0, 0, 0, 0, 0, 0, 0, 0, -196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 890, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 820 - 0, 0, -190, -190, 0, -190, 0, -190, 0, -190, -190, 0, 0, -190, 0, -190, -190, 0, 0, -190, 0, -190, -190, 0, 0, -928, 0, 0, -190, -190, 0, -190, 0, -190, -190, -190, -190, 0, 0, -190, 0, 0, 0, 0, -190, 0, -190, 0, -190, -190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -190, 0, -190, -190, 0, 0, 0, -190, -190, 0, 0, 0, 0, 0, 0, 0, 0, 0, -190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 891, 0, 0, 0, 0, 0, 0, 272, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 821 - 0, 0, 0, 0, 0, 0, 0, 0, 893, 0, 0, 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -196, -196, 0, -196, 0, -196, 0, -196, -196, 0, 0, -196, 0, -196, -196, 0, 0, -196, 0, -196, -196, 0, 0, -223, 0, 0, -196, -196, 0, -196, 0, -196, -196, -196, -196, 0, 0, -196, 0, 0, 0, 0, -196, 0, -196, 0, -196, -196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -196, 0, -196, -196, 0, 0, 0, -196, -196, 0, 0, 0, 0, 0, 0, 0, 0, 0, -196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 822 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -934, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -190, -190, 0, -190, 0, -190, 0, -190, -190, 0, 0, -190, 0, -190, -190, 0, 0, -190, 0, -190, -190, 0, 0, -931, 0, 0, -190, -190, 0, -190, 0, -190, -190, -190, -190, 0, 0, -190, 0, 0, 0, 0, -190, 0, -190, 0, -190, -190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -190, 0, -190, -190, 0, 0, 0, -190, -190, 0, 0, 0, 0, 0, 0, 0, 0, 0, -190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 823 - 0, 0, -200, -200, 0, -200, 0, -200, 0, -200, -200, 0, 0, -200, 0, -200, -200, 0, 0, -200, 0, -200, -200, 0, 0, -227, 0, 0, -200, -200, 0, -200, 0, -200, -200, -200, -200, 0, 0, -200, 0, 0, 0, 0, -200, 0, -200, 0, -200, -200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -200, 0, -200, -200, 0, 0, 0, -200, -200, 0, 0, 0, 0, 0, 0, 0, 0, 0, -200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 895, 0, 0, 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 824 - 0, 0, 0, 0, 0, 0, 0, 0, 895, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 825 - 0, 0, -186, -186, 0, -186, 0, -186, 0, -186, -186, 0, 0, -186, 0, -186, -186, 0, 0, -186, 0, -186, -186, 0, 0, -215, 0, 0, -186, -186, 0, -186, 0, -186, -186, -186, -186, 0, 0, -186, 0, 0, 0, 0, -186, 0, -186, 0, -186, -186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -186, 0, -186, -186, 0, 0, 0, -186, -186, 0, 0, 0, 0, 0, 0, 0, 0, 0, -186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -200, -200, 0, -200, 0, -200, 0, -200, -200, 0, 0, -200, 0, -200, -200, 0, 0, -200, 0, -200, -200, 0, 0, -227, 0, 0, -200, -200, 0, -200, 0, -200, -200, -200, -200, 0, 0, -200, 0, 0, 0, 0, -200, 0, -200, 0, -200, -200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -200, 0, -200, -200, 0, 0, 0, -200, -200, 0, 0, 0, 0, 0, 0, 0, 0, 0, -200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 826 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 896, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 897, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 827 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 897, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -186, -186, 0, -186, 0, -186, 0, -186, -186, 0, 0, -186, 0, -186, -186, 0, 0, -186, 0, -186, -186, 0, 0, -215, 0, 0, -186, -186, 0, -186, 0, -186, -186, -186, -186, 0, 0, -186, 0, 0, 0, 0, -186, 0, -186, 0, -186, -186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -186, 0, -186, -186, 0, 0, 0, -186, -186, 0, 0, 0, 0, 0, 0, 0, 0, 0, -186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 828 - 0, 0, -203, -203, 0, -203, 0, -203, 0, -203, -203, 0, 0, -203, 0, -203, -203, 0, 0, -203, 0, -203, -203, 0, 0, -230, 0, 0, -203, -203, 0, -203, 0, -203, -203, -203, -203, 0, 0, -203, 0, 0, 0, 0, -203, 0, -203, 0, -203, -203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -203, 0, -203, -203, 0, 0, 0, -203, -203, 0, 0, 0, 0, 0, 0, 0, 0, 0, -203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 829 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 899, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 830 - 0, 0, -206, -206, 0, -206, 0, -206, 0, -206, -206, 0, 0, -206, 0, -206, -206, 0, 0, -206, 0, -206, -206, 0, 0, -233, 0, 0, -206, -206, 0, -206, 0, -206, -206, -206, -206, 0, 0, -206, 0, 0, 0, 0, -206, 0, -206, 0, -206, -206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -206, 0, -206, -206, 0, 0, 0, -206, -206, 0, 0, 0, 0, 0, 0, 0, 0, 0, -206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -203, -203, 0, -203, 0, -203, 0, -203, -203, 0, 0, -203, 0, -203, -203, 0, 0, -203, 0, -203, -203, 0, 0, -230, 0, 0, -203, -203, 0, -203, 0, -203, -203, -203, -203, 0, 0, -203, 0, 0, 0, 0, -203, 0, -203, 0, -203, -203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -203, 0, -203, -203, 0, 0, 0, -203, -203, 0, 0, 0, 0, 0, 0, 0, 0, 0, -203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 831 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -843, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -843, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 900, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 832 - -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, 0, -197, 0, -197, -197, -197, -197, -197, 0, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, 0, 0, 0, -197, -197, -197, -197, -197, -197, 0, -197, 0, 0, 0, 0, 0, 0, 0, 0, -197, 0, 0, -197, -197, 0, -197, 0, -197, -197, 0, 0, 0, -197, -197, 0, 0, 0, 0, 0, 0, 0, 0, 0, -197, -197, -197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -206, -206, 0, -206, 0, -206, 0, -206, -206, 0, 0, -206, 0, -206, -206, 0, 0, -206, 0, -206, -206, 0, 0, -233, 0, 0, -206, -206, 0, -206, 0, -206, -206, -206, -206, 0, 0, -206, 0, 0, 0, 0, -206, 0, -206, 0, -206, -206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -206, 0, -206, -206, 0, 0, 0, -206, -206, 0, 0, 0, 0, 0, 0, 0, 0, 0, -206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 833 - -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, 0, -191, 0, -191, -191, -191, -191, -191, 0, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, 0, 0, 0, -191, -191, -191, -191, -191, -191, 0, -191, 0, 0, 0, 0, 0, 0, 0, 0, -191, 0, 0, -191, -191, 0, -191, 0, -191, -191, 0, 0, 0, -191, -191, 0, 0, 0, 0, 0, 0, 0, 0, 0, -191, -191, -191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -842, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -842, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 834 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 279, 0, 0, 0, 0, 0, 0, 0, 0, 0, -695, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, 0, -197, 0, -197, -197, -197, -197, -197, 0, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, -197, 0, 0, 0, -197, -197, -197, -197, -197, -197, 0, -197, 0, 0, 0, 0, 0, 0, 0, 0, -197, 0, 0, -197, -197, 0, -197, 0, -197, -197, 0, 0, 0, -197, -197, 0, 0, 0, 0, 0, 0, 0, 0, 0, -197, -197, -197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 835 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 903, 0, 0, 0, 0, 0, 0, 0, 0, 0, -680, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, 0, -191, 0, -191, -191, -191, -191, -191, 0, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, -191, 0, 0, 0, -191, -191, -191, -191, -191, -191, 0, -191, 0, 0, 0, 0, 0, 0, 0, 0, -191, 0, 0, -191, -191, 0, -191, 0, -191, -191, 0, 0, 0, -191, -191, 0, 0, 0, 0, 0, 0, 0, 0, 0, -191, -191, -191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 836 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 905, 0, 0, 0, 0, 0, 0, 0, 0, 0, -708, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 279, 0, 0, 0, 0, 0, 0, 0, 0, 0, -696, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 837 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -713, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 905, 0, 0, 0, 0, 0, 0, 0, 0, 0, -681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 838 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 907, 0, 0, 0, 0, 0, 0, 0, 0, 0, -720, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 907, 0, 0, 0, 0, 0, 0, 0, 0, 0, -709, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 839 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -710, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -714, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 840 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -383, 0, 0, -383, 0, 0, -383, 0, 0, 0, 0, 0, 0, -383, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 909, 0, 0, 0, 0, 0, 0, 0, 0, 0, -721, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 841 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 908, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -711, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 842 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -380, 0, 0, -380, 0, 0, -380, 0, 0, 0, 0, 0, 0, -380, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -383, 0, 0, -383, 0, 0, -383, 0, 0, 0, 0, 0, 0, -383, 0, 0, 0, 0, // State 843 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -381, 0, 0, -381, 0, 0, -381, 0, 0, 0, 0, 0, 0, -381, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 910, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 844 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 283, 0, 0, 0, 0, 0, 0, 284, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -380, 0, 0, -380, 0, 0, -380, 0, 0, 0, 0, 0, 0, -380, 0, 0, 0, 0, // State 845 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 285, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -381, 0, 0, -381, 0, 0, -381, 0, 0, 0, 0, 0, 0, -381, 0, 0, 0, 0, // State 846 - -272, 0, 0, 0, 0, 0, 0, -272, 0, -272, 0, 0, 0, -272, 0, 0, -272, 0, 0, 0, -272, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -272, 0, -272, -272, -272, -272, 0, 0, 0, 0, 0, -272, -272, -272, -272, 0, -272, -272, -272, -272, 0, 0, 0, 0, -272, -272, -272, -272, -272, 0, 0, -272, -272, -272, -272, 0, -272, -272, -272, -272, -272, -272, -272, -272, -272, 0, 0, 0, -272, -272, 0, -272, 0, 0, 0, -272, -272, 0, -272, -272, -272, -272, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 283, 0, 0, 0, 0, 0, 0, 284, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 847 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 286, 0, 0, 0, 0, 0, 0, 287, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 285, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 848 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 288, 0, 0, 0, 0, 0, 0, 289, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -272, 0, 0, 0, 0, 0, 0, -272, 0, -272, 0, 0, 0, -272, 0, 0, -272, 0, 0, 0, -272, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -272, 0, -272, -272, -272, -272, 0, 0, 0, 0, 0, -272, -272, -272, -272, 0, -272, -272, -272, -272, 0, 0, 0, 0, -272, -272, -272, -272, -272, 0, 0, -272, -272, -272, -272, 0, -272, -272, -272, -272, -272, -272, -272, -272, -272, 0, 0, 0, -272, -272, 0, -272, 0, 0, 0, -272, -272, 0, -272, -272, -272, -272, // State 849 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 290, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 286, 0, 0, 0, 0, 0, 0, 287, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 850 - -940, 0, 0, 0, 0, 0, 0, -940, 0, -940, 0, 0, 0, -940, 0, 0, -940, 0, 0, 0, -940, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -940, 0, -940, -940, -940, -940, 0, 0, 0, 0, 0, -940, -940, -940, -940, 0, -940, -940, -940, -940, 0, 0, 0, 0, -940, -940, -940, -940, -940, 0, 0, -940, -940, -940, -940, 0, -940, -940, -940, -940, -940, -940, -940, -940, -940, 0, 0, 0, -940, -940, 0, -940, 0, 0, 0, -940, -940, 0, -940, -940, -940, -940, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 288, 0, 0, 0, 0, 0, 0, 289, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 851 - -266, 0, 0, 0, 0, 0, 0, -266, 0, -266, 0, 0, 0, -266, 0, 0, -266, 0, 0, 0, -266, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -266, 0, -266, -266, -266, -266, 0, 0, 0, 0, 0, -266, -266, -266, -266, 0, -266, -266, -266, -266, 0, 0, 0, 0, -266, -266, -266, -266, -266, 0, 0, -266, -266, -266, -266, 0, -266, -266, -266, -266, -266, -266, -266, -266, -266, 0, 0, 0, -266, -266, 0, -266, 0, 0, 0, -266, -266, 0, -266, -266, -266, -266, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 290, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 852 - -269, 0, 0, 0, 0, 0, 0, -269, 0, -269, 0, 0, 0, -269, 0, 0, -269, 0, 0, 0, -269, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -269, 0, -269, -269, -269, -269, 0, 0, 0, 0, 0, -269, -269, -269, -269, 0, -269, -269, -269, -269, 0, 0, 0, 0, -269, -269, -269, -269, -269, 0, 0, -269, -269, -269, -269, 0, -269, -269, -269, -269, -269, -269, -269, -269, -269, 0, 0, 0, -269, -269, 0, -269, 0, 0, 0, -269, -269, 0, -269, -269, -269, -269, + -943, 0, 0, 0, 0, 0, 0, -943, 0, -943, 0, 0, 0, -943, 0, 0, -943, 0, 0, 0, -943, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -943, 0, -943, -943, -943, -943, 0, 0, 0, 0, 0, -943, -943, -943, -943, 0, -943, -943, -943, -943, 0, 0, 0, 0, -943, -943, -943, -943, -943, 0, 0, -943, -943, -943, -943, 0, -943, -943, -943, -943, -943, -943, -943, -943, -943, 0, 0, 0, -943, -943, 0, -943, 0, 0, 0, -943, -943, 0, -943, -943, -943, -943, // State 853 - 0, 0, 0, 0, 0, 0, 0, -910, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -910, 0, 0, 0, 0, 0, 0, -910, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -266, 0, 0, 0, 0, 0, 0, -266, 0, -266, 0, 0, 0, -266, 0, 0, -266, 0, 0, 0, -266, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -266, 0, -266, -266, -266, -266, 0, 0, 0, 0, 0, -266, -266, -266, -266, 0, -266, -266, -266, -266, 0, 0, 0, 0, -266, -266, -266, -266, -266, 0, 0, -266, -266, -266, -266, 0, -266, -266, -266, -266, -266, -266, -266, -266, -266, 0, 0, 0, -266, -266, 0, -266, 0, 0, 0, -266, -266, 0, -266, -266, -266, -266, // State 854 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -907, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -907, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -269, 0, 0, 0, 0, 0, 0, -269, 0, -269, 0, 0, 0, -269, 0, 0, -269, 0, 0, 0, -269, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -269, 0, -269, -269, -269, -269, 0, 0, 0, 0, 0, -269, -269, -269, -269, 0, -269, -269, -269, -269, 0, 0, 0, 0, -269, -269, -269, -269, -269, 0, 0, -269, -269, -269, -269, 0, -269, -269, -269, -269, -269, -269, -269, -269, -269, 0, 0, 0, -269, -269, 0, -269, 0, 0, 0, -269, -269, 0, -269, -269, -269, -269, // State 855 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -908, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -908, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -913, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -913, 0, 0, 0, 0, 0, 0, -913, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 856 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 291, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -910, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -910, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 857 - -414, 0, 0, 0, 0, 0, 0, -414, 0, -414, 0, 0, 0, -414, 0, 0, -414, 0, 0, 0, -414, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -414, 0, -414, -414, -414, -414, 0, 0, 0, 0, 0, -414, -414, -414, -414, 0, -414, -414, -414, -414, 0, 0, 0, 0, -414, -414, -414, -414, -414, 0, 0, -414, -414, -414, -414, 0, -414, -414, -414, -414, -414, -414, -414, -414, -414, 0, 0, 0, -414, -414, 0, -414, 0, 0, 0, -414, -414, 0, -414, -414, -414, -414, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -911, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -911, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 858 - 0, 0, 0, 0, 0, 0, 0, 0, -648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 291, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 859 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -746, 0, 0, 0, 0, 0, 0, -746, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -414, 0, 0, 0, 0, 0, 0, -414, 0, -414, 0, 0, 0, -414, 0, 0, -414, 0, 0, 0, -414, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -414, 0, -414, -414, -414, -414, 0, 0, 0, 0, 0, -414, -414, -414, -414, 0, -414, -414, -414, -414, 0, 0, 0, 0, -414, -414, -414, -414, -414, 0, 0, -414, -414, -414, -414, 0, -414, -414, -414, -414, -414, -414, -414, -414, -414, 0, 0, 0, -414, -414, 0, -414, 0, 0, 0, -414, -414, 0, -414, -414, -414, -414, // State 860 - 0, 0, 0, 0, 0, 0, 0, 0, -647, 0, 0, 0, 0, 0, 0, 294, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -649, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 861 - 0, 0, 0, 0, 0, 0, 0, 0, -819, 0, 0, 0, 0, 0, 0, -819, 0, 0, 0, 0, 0, 0, 0, 0, 0, 295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -747, 0, 0, 0, 0, 0, 0, -747, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 862 - 0, 0, 0, 0, 0, 0, 0, 0, -457, 0, 0, 0, 0, 0, 0, -457, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -648, 0, 0, 0, 0, 0, 0, 294, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 863 - 0, 0, 0, 0, 0, 0, 0, 0, -336, 0, 0, 0, 0, 0, 0, -336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 297, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -820, 0, 0, 0, 0, 0, 0, -820, 0, 0, 0, 0, 0, 0, 0, 0, 0, 295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 864 - 0, 0, 0, 0, 0, 0, 0, 0, 932, 0, 0, 0, 0, 0, 0, 298, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -457, 0, 0, 0, 0, 0, 0, -457, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 865 - -77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -77, 0, 0, 0, -77, 0, 0, 0, 0, 0, 0, 0, -77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -336, 0, 0, 0, 0, 0, 0, -336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 297, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 866 - -434, 0, 0, 0, 0, 0, 0, -434, 0, -434, 0, 0, 0, -434, 0, 0, -434, 0, 0, 0, -434, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -434, 0, -434, -434, -434, -434, 0, 0, 0, 0, 0, -434, -434, -434, -434, 0, -434, -434, -434, -434, 299, 933, 0, 0, -434, -434, -434, -434, -434, 0, 0, -434, -434, -434, -434, 0, -434, -434, -434, -434, -434, -434, -434, -434, -434, 0, 0, 0, -434, -434, 0, -434, 0, 0, 0, -434, -434, 0, -434, -434, -434, -434, + 0, 0, 0, 0, 0, 0, 0, 0, 934, 0, 0, 0, 0, 0, 0, 298, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 867 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 300, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -77, 0, 0, 0, -77, 0, 0, 0, 0, 0, 0, 0, -77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 868 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -434, 0, 0, 0, 0, 0, 0, -434, 0, -434, 0, 0, 0, -434, 0, 0, -434, 0, 0, 0, -434, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -434, 0, -434, -434, -434, -434, 0, 0, 0, 0, 0, -434, -434, -434, -434, 0, -434, -434, -434, -434, 299, 935, 0, 0, -434, -434, -434, -434, -434, 0, 0, -434, -434, -434, -434, 0, -434, -434, -434, -434, -434, -434, -434, -434, -434, 0, 0, 0, -434, -434, 0, -434, 0, 0, 0, -434, -434, 0, -434, -434, -434, -434, // State 869 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 304, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 300, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 870 - -858, 0, 0, 0, 0, 0, 0, -858, 0, -858, 0, 0, 0, -858, 0, 0, -858, 0, 0, 0, -858, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -858, 0, -858, -858, -858, -858, 0, 0, 0, 0, 0, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, 0, 0, -858, -858, -858, -858, 0, -858, -858, -858, -858, -858, -858, -858, -858, -858, 0, 0, 0, -858, -858, 0, -858, 0, 0, 0, -858, -858, 0, -858, -858, -858, -858, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 871 - 937, 0, 0, 0, 0, 0, 0, -135, 0, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -135, -135, -135, -135, 0, 0, 0, 0, 0, -135, 0, -135, -135, 0, 0, -135, 0, -135, 0, 0, 0, 0, 0, -135, -135, 0, -135, 0, 0, -135, 0, -135, -135, 0, -135, -135, -135, 0, -135, 0, 0, -135, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, -135, 0, -135, -135, -135, -135, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 304, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 872 - -855, 0, 0, 0, 0, 0, 0, -855, 0, -855, 0, 0, 0, -855, 0, 0, -855, 0, 0, 0, -855, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -855, 0, -855, -855, -855, -855, 0, 0, 0, 0, 0, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, 0, 0, -855, -855, -855, -855, 0, -855, -855, -855, -855, -855, -855, -855, -855, -855, 0, 0, 0, -855, -855, 0, -855, 0, 0, 0, -855, -855, 0, -855, -855, -855, -855, + -857, 0, 0, 0, 0, 0, 0, -857, 0, -857, 0, 0, 0, -857, 0, 0, -857, 0, 0, 0, -857, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -857, 0, -857, -857, -857, -857, 0, 0, 0, 0, 0, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, -857, 0, 0, -857, -857, -857, -857, 0, -857, -857, -857, -857, -857, -857, -857, -857, -857, 0, 0, 0, -857, -857, 0, -857, 0, 0, 0, -857, -857, 0, -857, -857, -857, -857, // State 873 - -343, 0, 0, 0, 0, 0, 0, -343, 0, -343, 0, 0, 0, -343, 0, 0, -343, 0, 0, 0, -343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -343, 0, -343, -343, -343, -343, 0, 0, 0, 0, 0, -343, -343, -343, -343, 0, -343, -343, -343, -343, 0, -343, -343, -343, -343, -343, -343, -343, -343, 0, 0, -343, -343, -343, -343, 0, -343, -343, -343, -343, -343, -343, -343, -343, -343, 0, 0, 0, -343, -343, 0, -343, 0, 0, 0, -343, -343, 0, -343, -343, -343, -343, + 939, 0, 0, 0, 0, 0, 0, -135, 0, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -135, -135, -135, -135, 0, 0, 0, 0, 0, -135, 0, -135, -135, 0, 0, -135, 0, -135, 0, 0, 0, 0, 0, -135, -135, 0, -135, 0, 0, -135, 0, -135, -135, 0, -135, -135, -135, 0, -135, 0, 0, -135, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, -135, 0, -135, -135, -135, -135, // State 874 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 306, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -854, 0, 0, 0, 0, 0, 0, -854, 0, -854, 0, 0, 0, -854, 0, 0, -854, 0, 0, 0, -854, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -854, 0, -854, -854, -854, -854, 0, 0, 0, 0, 0, -854, -854, -854, -854, -854, -854, -854, -854, -854, -854, -854, -854, -854, -854, -854, -854, -854, -854, 0, 0, -854, -854, -854, -854, 0, -854, -854, -854, -854, -854, -854, -854, -854, -854, 0, 0, 0, -854, -854, 0, -854, 0, 0, 0, -854, -854, 0, -854, -854, -854, -854, // State 875 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 307, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -343, 0, 0, 0, 0, 0, 0, -343, 0, -343, 0, 0, 0, -343, 0, 0, -343, 0, 0, 0, -343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -343, 0, -343, -343, -343, -343, 0, 0, 0, 0, 0, -343, -343, -343, -343, 0, -343, -343, -343, -343, 0, -343, -343, -343, -343, -343, -343, -343, -343, 0, 0, -343, -343, -343, -343, 0, -343, -343, -343, -343, -343, -343, -343, -343, -343, 0, 0, 0, -343, -343, 0, -343, 0, 0, 0, -343, -343, 0, -343, -343, -343, -343, // State 876 - -347, 0, 0, 0, 0, 0, 0, -347, 0, -347, 0, 0, 0, -347, 0, 0, -347, 0, 0, 0, -347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -347, 0, -347, -347, -347, -347, 0, 0, 0, 0, 0, -347, -347, -347, -347, 0, -347, -347, -347, -347, 0, -347, -347, -347, -347, -347, -347, -347, -347, 0, 0, -347, -347, -347, -347, 0, -347, -347, -347, -347, -347, -347, -347, -347, -347, 0, 0, 0, -347, -347, 0, -347, 0, 0, 0, -347, -347, 0, -347, -347, -347, -347, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 306, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 877 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 307, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 878 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 266, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -347, 0, 0, 0, 0, 0, 0, -347, 0, -347, 0, 0, 0, -347, 0, 0, -347, 0, 0, 0, -347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -347, 0, -347, -347, -347, -347, 0, 0, 0, 0, 0, -347, -347, -347, -347, 0, -347, -347, -347, -347, 0, -347, -347, -347, -347, -347, -347, -347, -347, 0, 0, -347, -347, -347, -347, 0, -347, -347, -347, -347, -347, -347, -347, -347, -347, 0, 0, 0, -347, -347, 0, -347, 0, 0, 0, -347, -347, 0, -347, -347, -347, -347, // State 879 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 880 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 310, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 311, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 266, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 881 - 0, 0, 0, 0, 0, 0, 0, -829, 0, -829, 0, 0, 0, -829, 0, 0, -829, 0, 0, 0, -829, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -829, 0, -829, -829, -829, -829, 0, 0, 0, 0, 0, -829, -829, -829, -829, 0, -829, -829, -829, -829, 0, 0, 0, 0, -829, -829, -829, -829, -829, 0, 0, -829, -829, -829, -829, 0, -829, -829, -829, -829, -829, -829, -829, -829, -829, 0, 0, 0, -829, -829, 0, -829, 0, 0, 0, -829, -829, 0, -829, -829, -829, -829, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 882 - 942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 943, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 310, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 311, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 883 - -903, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -903, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -830, 0, -830, 0, 0, 0, -830, 0, 0, -830, 0, 0, 0, -830, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -830, 0, -830, -830, -830, -830, 0, 0, 0, 0, 0, -830, -830, -830, -830, 0, -830, -830, -830, -830, 0, 0, 0, 0, -830, -830, -830, -830, -830, 0, 0, -830, -830, -830, -830, 0, -830, -830, -830, -830, -830, -830, -830, -830, -830, 0, 0, 0, -830, -830, 0, -830, 0, 0, 0, -830, -830, 0, -830, -830, -830, -830, // State 884 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 313, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 944, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 945, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 885 - 0, 0, -241, -241, 0, -241, 0, -241, 0, -241, -241, 0, 0, -241, 0, -241, -241, 0, 0, -241, 0, -241, -241, 0, 0, -245, 0, 0, -241, -241, 0, -241, 0, -241, -241, -241, -241, 0, 0, -241, 0, 0, 0, 0, -241, 0, -241, 0, -241, -241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -241, 0, -241, -241, 0, 0, 0, -241, -241, 0, 0, 0, 0, 0, 0, 0, 0, 0, -241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -906, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -906, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 886 - 0, 0, 0, 0, 0, 0, 0, 0, -71, 0, 0, 0, 0, 0, 0, -71, 0, 0, 0, 0, 0, 0, 0, 0, 0, -71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 313, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 887 - 0, 0, -201, -201, 0, -201, 0, -201, 0, -201, -201, 0, 0, -201, 0, -201, -201, 0, 0, -201, 0, -201, -201, 0, 0, -228, 0, 0, -201, -201, 0, -201, 0, -201, -201, -201, -201, 0, 0, -201, 0, 0, 0, 0, -201, 0, -201, 0, -201, -201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -201, 0, -201, -201, 0, 0, 0, -201, -201, 0, 0, 0, 0, 0, 0, 0, 0, 0, -201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -241, -241, 0, -241, 0, -241, 0, -241, -241, 0, 0, -241, 0, -241, -241, 0, 0, -241, 0, -241, -241, 0, 0, -245, 0, 0, -241, -241, 0, -241, 0, -241, -241, -241, -241, 0, 0, -241, 0, 0, 0, 0, -241, 0, -241, 0, -241, -241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -241, 0, -241, -241, 0, 0, 0, -241, -241, 0, 0, 0, 0, 0, 0, 0, 0, 0, -241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 888 - 0, 0, -198, -198, 0, -198, 0, -198, 0, -198, -198, 0, 0, -198, 0, -198, -198, 0, 0, -198, 0, -198, -198, 0, 0, -225, 0, 0, -198, -198, 0, -198, 0, -198, -198, -198, -198, 0, 0, -198, 0, 0, 0, 0, -198, 0, -198, 0, -198, -198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -198, 0, -198, -198, 0, 0, 0, -198, -198, 0, 0, 0, 0, 0, 0, 0, 0, 0, -198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -71, 0, 0, 0, 0, 0, 0, -71, 0, 0, 0, 0, 0, 0, 0, 0, 0, -71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 889 - 0, 0, -192, -192, 0, -192, 0, -192, 0, -192, -192, 0, 0, -192, 0, -192, -192, 0, 0, -192, 0, -192, -192, 0, 0, -219, 0, 0, -192, -192, 0, -192, 0, -192, -192, -192, -192, 0, 0, -192, 0, 0, 0, 0, -192, 0, -192, 0, -192, -192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -192, 0, -192, -192, 0, 0, 0, -192, -192, 0, 0, 0, 0, 0, 0, 0, 0, 0, -192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -201, -201, 0, -201, 0, -201, 0, -201, -201, 0, 0, -201, 0, -201, -201, 0, 0, -201, 0, -201, -201, 0, 0, -228, 0, 0, -201, -201, 0, -201, 0, -201, -201, -201, -201, 0, 0, -201, 0, 0, 0, 0, -201, 0, -201, 0, -201, -201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -201, 0, -201, -201, 0, 0, 0, -201, -201, 0, 0, 0, 0, 0, 0, 0, 0, 0, -201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 890 - 0, 0, 0, 0, 0, 0, 0, 0, -549, 0, 0, 0, 0, 0, 0, -549, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -198, -198, 0, -198, 0, -198, 0, -198, -198, 0, 0, -198, 0, -198, -198, 0, 0, -198, 0, -198, -198, 0, 0, -225, 0, 0, -198, -198, 0, -198, 0, -198, -198, -198, -198, 0, 0, -198, 0, 0, 0, 0, -198, 0, -198, 0, -198, -198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -198, 0, -198, -198, 0, 0, 0, -198, -198, 0, 0, 0, 0, 0, 0, 0, 0, 0, -198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 891 - 0, 0, -189, -189, 0, -189, 0, -189, 0, -189, -189, 0, 0, -189, 0, -189, -189, 0, 0, -189, 0, -189, -189, 0, 0, -927, 0, 0, -189, -189, 0, -189, 0, -189, -189, -189, -189, 0, 0, -189, 0, 0, 0, 0, -189, 0, -189, 0, -189, -189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -189, 0, -189, -189, 0, 0, 0, -189, -189, 0, 0, 0, 0, 0, 0, 0, 0, 0, -189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -192, -192, 0, -192, 0, -192, 0, -192, -192, 0, 0, -192, 0, -192, -192, 0, 0, -192, 0, -192, -192, 0, 0, -219, 0, 0, -192, -192, 0, -192, 0, -192, -192, -192, -192, 0, 0, -192, 0, 0, 0, 0, -192, 0, -192, 0, -192, -192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -192, 0, -192, -192, 0, 0, 0, -192, -192, 0, 0, 0, 0, 0, 0, 0, 0, 0, -192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 892 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -936, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -550, 0, 0, 0, 0, 0, 0, -550, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 893 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -930, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -189, -189, 0, -189, 0, -189, 0, -189, -189, 0, 0, -189, 0, -189, -189, 0, 0, -189, 0, -189, -189, 0, 0, -930, 0, 0, -189, -189, 0, -189, 0, -189, -189, -189, -189, 0, 0, -189, 0, 0, 0, 0, -189, 0, -189, 0, -189, -189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -189, 0, -189, -189, 0, 0, 0, -189, -189, 0, 0, 0, 0, 0, 0, 0, 0, 0, -189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 894 - 0, 0, -202, -202, 0, -202, 0, -202, 0, -202, -202, 0, 0, -202, 0, -202, -202, 0, 0, -202, 0, -202, -202, 0, 0, -229, 0, 0, -202, -202, 0, -202, 0, -202, -202, -202, -202, 0, 0, -202, 0, 0, 0, 0, -202, 0, -202, 0, -202, -202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -202, 0, -202, -202, 0, 0, 0, -202, -202, 0, 0, 0, 0, 0, 0, 0, 0, 0, -202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 895 - 0, 0, -188, -188, 0, -188, 0, -188, 0, -188, -188, 0, 0, -188, 0, -188, -188, 0, 0, -188, 0, -188, -188, 0, 0, -217, 0, 0, -188, -188, 0, -188, 0, -188, -188, -188, -188, 0, 0, -188, 0, 0, 0, 0, -188, 0, -188, 0, -188, -188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -188, 0, -188, -188, 0, 0, 0, -188, -188, 0, 0, 0, 0, 0, 0, 0, 0, 0, -188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -933, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 896 - 0, 0, -205, -205, 0, -205, 0, -205, 0, -205, -205, 0, 0, -205, 0, -205, -205, 0, 0, -205, 0, -205, -205, 0, 0, -232, 0, 0, -205, -205, 0, -205, 0, -205, -205, -205, -205, 0, 0, -205, 0, 0, 0, 0, -205, 0, -205, 0, -205, -205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -205, 0, -205, -205, 0, 0, 0, -205, -205, 0, 0, 0, 0, 0, 0, 0, 0, 0, -205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -202, -202, 0, -202, 0, -202, 0, -202, -202, 0, 0, -202, 0, -202, -202, 0, 0, -202, 0, -202, -202, 0, 0, -229, 0, 0, -202, -202, 0, -202, 0, -202, -202, -202, -202, 0, 0, -202, 0, 0, 0, 0, -202, 0, -202, 0, -202, -202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -202, 0, -202, -202, 0, 0, 0, -202, -202, 0, 0, 0, 0, 0, 0, 0, 0, 0, -202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 897 - 0, 0, -207, -207, 0, -207, 0, -207, 0, -207, -207, 0, 0, -207, 0, -207, -207, 0, 0, -207, 0, -207, -207, 0, 0, -234, 0, 0, -207, -207, 0, -207, 0, -207, -207, -207, -207, 0, 0, -207, 0, 0, 0, 0, -207, 0, -207, 0, -207, -207, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -207, 0, -207, -207, 0, 0, 0, -207, -207, 0, 0, 0, 0, 0, 0, 0, 0, 0, -207, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -188, -188, 0, -188, 0, -188, 0, -188, -188, 0, 0, -188, 0, -188, -188, 0, 0, -188, 0, -188, -188, 0, 0, -217, 0, 0, -188, -188, 0, -188, 0, -188, -188, -188, -188, 0, 0, -188, 0, 0, 0, 0, -188, 0, -188, 0, -188, -188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -188, 0, -188, -188, 0, 0, 0, -188, -188, 0, 0, 0, 0, 0, 0, 0, 0, 0, -188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 898 - 0, 0, 0, 0, 0, 0, 0, 0, -318, 0, 0, 0, 0, 0, 0, -318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -318, 0, 0, 0, 0, 0, -318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -318, 0, 0, -318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -205, -205, 0, -205, 0, -205, 0, -205, -205, 0, 0, -205, 0, -205, -205, 0, 0, -205, 0, -205, -205, 0, 0, -232, 0, 0, -205, -205, 0, -205, 0, -205, -205, -205, -205, 0, 0, -205, 0, 0, 0, 0, -205, 0, -205, 0, -205, -205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -205, 0, -205, -205, 0, 0, 0, -205, -205, 0, 0, 0, 0, 0, 0, 0, 0, 0, -205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 899 - -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, 0, -193, 0, -193, -193, -193, -193, -193, 0, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, 0, 0, 0, -193, -193, -193, -193, -193, -193, 0, -193, 0, 0, 0, 0, 0, 0, 0, 0, -193, 0, 0, -193, -193, 0, -193, 0, -193, -193, 0, 0, 0, -193, -193, 0, 0, 0, 0, 0, 0, 0, 0, 0, -193, -193, -193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -207, -207, 0, -207, 0, -207, 0, -207, -207, 0, 0, -207, 0, -207, -207, 0, 0, -207, 0, -207, -207, 0, 0, -234, 0, 0, -207, -207, 0, -207, 0, -207, -207, -207, -207, 0, 0, -207, 0, 0, 0, 0, -207, 0, -207, 0, -207, -207, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -207, 0, -207, -207, 0, 0, 0, -207, -207, 0, 0, 0, 0, 0, 0, 0, 0, 0, -207, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 900 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 957, 0, 0, 0, 0, 0, 0, 0, 0, 0, -686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -318, 0, 0, 0, 0, 0, 0, -318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -318, 0, 0, 0, 0, 0, -318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -318, 0, 0, -318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 901 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 959, 0, 0, 0, 0, 0, 0, 0, 0, 0, -677, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, 0, -193, 0, -193, -193, -193, -193, -193, 0, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, 0, 0, 0, -193, -193, -193, -193, -193, -193, 0, -193, 0, 0, 0, 0, 0, 0, 0, 0, -193, 0, 0, -193, -193, 0, -193, 0, -193, -193, 0, 0, 0, -193, -193, 0, 0, 0, 0, 0, 0, 0, 0, 0, -193, -193, -193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 902 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -653, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 959, 0, 0, 0, 0, 0, 0, 0, 0, 0, -687, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 903 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 960, 0, 0, 0, 0, 0, 0, 0, 0, 0, -709, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 961, 0, 0, 0, 0, 0, 0, 0, 0, 0, -678, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 904 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -705, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -654, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 905 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 319, 0, 0, 0, 0, 0, 0, 0, 0, 0, -699, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 962, 0, 0, 0, 0, 0, 0, 0, 0, 0, -710, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 906 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -712, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -706, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 907 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -379, 0, 0, -379, 0, 0, -379, 0, 0, 0, 0, 0, 0, -379, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 319, 0, 0, 0, 0, 0, 0, 0, 0, 0, -700, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 908 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 321, 0, 0, 0, 0, 0, 0, 322, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -713, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 909 - -268, 0, 0, 0, 0, 0, 0, -268, 0, -268, 0, 0, 0, -268, 0, 0, -268, 0, 0, 0, -268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -268, 0, -268, -268, -268, -268, 0, 0, 0, 0, 0, -268, -268, -268, -268, 0, -268, -268, -268, -268, 0, 0, 0, 0, -268, -268, -268, -268, -268, 0, 0, -268, -268, -268, -268, 0, -268, -268, -268, -268, -268, -268, -268, -268, -268, 0, 0, 0, -268, -268, 0, -268, 0, 0, 0, -268, -268, 0, -268, -268, -268, -268, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -379, 0, 0, -379, 0, 0, -379, 0, 0, 0, 0, 0, 0, -379, 0, 0, 0, 0, // State 910 - -271, 0, 0, 0, 0, 0, 0, -271, 0, -271, 0, 0, 0, -271, 0, 0, -271, 0, 0, 0, -271, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -271, 0, -271, -271, -271, -271, 0, 0, 0, 0, 0, -271, -271, -271, -271, 0, -271, -271, -271, -271, 0, 0, 0, 0, -271, -271, -271, -271, -271, 0, 0, -271, -271, -271, -271, 0, -271, -271, -271, -271, -271, -271, -271, -271, -271, 0, 0, 0, -271, -271, 0, -271, 0, 0, 0, -271, -271, 0, -271, -271, -271, -271, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 321, 0, 0, 0, 0, 0, 0, 322, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 911 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 323, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -268, 0, 0, 0, 0, 0, 0, -268, 0, -268, 0, 0, 0, -268, 0, 0, -268, 0, 0, 0, -268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -268, 0, -268, -268, -268, -268, 0, 0, 0, 0, 0, -268, -268, -268, -268, 0, -268, -268, -268, -268, 0, 0, 0, 0, -268, -268, -268, -268, -268, 0, 0, -268, -268, -268, -268, 0, -268, -268, -268, -268, -268, -268, -268, -268, -268, 0, 0, 0, -268, -268, 0, -268, 0, 0, 0, -268, -268, 0, -268, -268, -268, -268, // State 912 - -416, 0, 0, 0, 0, 0, 0, -416, 0, -416, 0, 0, 0, -416, 0, 0, -416, 0, 0, 0, -416, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -416, 0, -416, -416, -416, -416, 0, 0, 0, 0, 0, -416, -416, -416, -416, 0, -416, -416, -416, -416, 0, 0, 0, 0, -416, -416, -416, -416, -416, 0, 0, -416, -416, -416, -416, 0, -416, -416, -416, -416, -416, -416, -416, -416, -416, 0, 0, 0, -416, -416, 0, -416, 0, 0, 0, -416, -416, 0, -416, -416, -416, -416, + -271, 0, 0, 0, 0, 0, 0, -271, 0, -271, 0, 0, 0, -271, 0, 0, -271, 0, 0, 0, -271, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -271, 0, -271, -271, -271, -271, 0, 0, 0, 0, 0, -271, -271, -271, -271, 0, -271, -271, -271, -271, 0, 0, 0, 0, -271, -271, -271, -271, -271, 0, 0, -271, -271, -271, -271, 0, -271, -271, -271, -271, -271, -271, -271, -271, -271, 0, 0, 0, -271, -271, 0, -271, 0, 0, 0, -271, -271, 0, -271, -271, -271, -271, // State 913 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 324, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 323, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 914 - -406, 0, 0, 0, 0, 0, 0, -406, 0, -406, 0, 0, 0, -406, 0, 0, -406, 0, 0, 0, -406, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -406, 0, -406, -406, -406, -406, 0, 0, 0, 0, 0, -406, -406, -406, -406, 0, -406, -406, -406, -406, 0, 0, 0, 0, -406, -406, -406, -406, -406, 0, 0, -406, -406, -406, -406, 0, -406, -406, -406, -406, -406, -406, -406, -406, -406, 0, 0, 0, -406, -406, 0, -406, 0, 0, 0, -406, -406, 0, -406, -406, -406, -406, + -416, 0, 0, 0, 0, 0, 0, -416, 0, -416, 0, 0, 0, -416, 0, 0, -416, 0, 0, 0, -416, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -416, 0, -416, -416, -416, -416, 0, 0, 0, 0, 0, -416, -416, -416, -416, 0, -416, -416, -416, -416, 0, 0, 0, 0, -416, -416, -416, -416, -416, 0, 0, -416, -416, -416, -416, 0, -416, -416, -416, -416, -416, -416, -416, -416, -416, 0, 0, 0, -416, -416, 0, -416, 0, 0, 0, -416, -416, 0, -416, -416, -416, -416, // State 915 - -265, 0, 0, 0, 0, 0, 0, -265, 0, -265, 0, 0, 0, -265, 0, 0, -265, 0, 0, 0, -265, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -265, 0, -265, -265, -265, -265, 0, 0, 0, 0, 0, -265, -265, -265, -265, 0, -265, -265, -265, -265, 0, 0, 0, 0, -265, -265, -265, -265, -265, 0, 0, -265, -265, -265, -265, 0, -265, -265, -265, -265, -265, -265, -265, -265, -265, 0, 0, 0, -265, -265, 0, -265, 0, 0, 0, -265, -265, 0, -265, -265, -265, -265, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 324, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 916 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -905, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -905, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -406, 0, 0, 0, 0, 0, 0, -406, 0, -406, 0, 0, 0, -406, 0, 0, -406, 0, 0, 0, -406, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -406, 0, -406, -406, -406, -406, 0, 0, 0, 0, 0, -406, -406, -406, -406, 0, -406, -406, -406, -406, 0, 0, 0, 0, -406, -406, -406, -406, -406, 0, 0, -406, -406, -406, -406, 0, -406, -406, -406, -406, -406, -406, -406, -406, -406, 0, 0, 0, -406, -406, 0, -406, 0, 0, 0, -406, -406, 0, -406, -406, -406, -406, // State 917 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -265, 0, 0, 0, 0, 0, 0, -265, 0, -265, 0, 0, 0, -265, 0, 0, -265, 0, 0, 0, -265, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -265, 0, -265, -265, -265, -265, 0, 0, 0, 0, 0, -265, -265, -265, -265, 0, -265, -265, -265, -265, 0, 0, 0, 0, -265, -265, -265, -265, -265, 0, 0, -265, -265, -265, -265, 0, -265, -265, -265, -265, -265, -265, -265, -265, -265, 0, 0, 0, -265, -265, 0, -265, 0, 0, 0, -265, -265, 0, -265, -265, -265, -265, // State 918 - 0, 0, 0, 0, 0, 0, 0, -909, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -909, 0, 0, 0, 0, 0, 0, -909, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -908, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -908, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 919 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 325, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -556, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -556, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 920 - -413, 0, 0, 0, 0, 0, 0, -413, 0, -413, 0, 0, 0, -413, 0, 0, -413, 0, 0, 0, -413, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -413, 0, -413, -413, -413, -413, 0, 0, 0, 0, 0, -413, -413, -413, -413, 0, -413, -413, -413, -413, 0, 0, 0, 0, -413, -413, -413, -413, -413, 0, 0, -413, -413, -413, -413, 0, -413, -413, -413, -413, -413, -413, -413, -413, -413, 0, 0, 0, -413, -413, 0, -413, 0, 0, 0, -413, -413, 0, -413, -413, -413, -413, + 0, 0, 0, 0, 0, 0, 0, -912, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -912, 0, 0, 0, 0, 0, 0, -912, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 921 - 0, 0, 0, 0, 0, 0, 0, 0, -913, 0, 0, 0, 0, 0, 0, -913, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -913, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 325, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 922 - 0, 0, 0, 0, 0, 0, 0, 0, -629, 0, 0, 0, 0, 0, 0, 973, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -413, 0, 0, 0, 0, 0, 0, -413, 0, -413, 0, 0, 0, -413, 0, 0, -413, 0, 0, 0, -413, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -413, 0, -413, -413, -413, -413, 0, 0, 0, 0, 0, -413, -413, -413, -413, 0, -413, -413, -413, -413, 0, 0, 0, 0, -413, -413, -413, -413, -413, 0, 0, -413, -413, -413, -413, 0, -413, -413, -413, -413, -413, -413, -413, -413, -413, 0, 0, 0, -413, -413, 0, -413, 0, 0, 0, -413, -413, 0, -413, -413, -413, -413, // State 923 - 0, 0, 0, 0, 0, 0, 0, 0, -543, 0, 0, 0, 0, 0, 0, -543, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -916, 0, 0, 0, 0, 0, 0, -916, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -916, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 924 - 0, 0, 0, 0, 0, 0, 0, 0, -563, 0, 0, 0, 0, 0, 0, -563, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -630, 0, 0, 0, 0, 0, 0, 975, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 925 - 0, 0, 0, 0, 0, 0, 0, 0, -646, 0, 0, 0, 0, 0, 0, 329, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -544, 0, 0, 0, 0, 0, 0, -544, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 926 - 0, 0, 0, 0, 0, 0, 0, 0, -641, 0, 0, 0, 0, 0, 0, 980, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -564, 0, 0, 0, 0, 0, 0, -564, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 927 - 0, 0, 0, 0, 0, 0, 0, 0, -18, 0, 0, 0, 0, 0, 0, -18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -647, 0, 0, 0, 0, 0, 0, 329, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 928 - -400, 0, 0, 0, 0, 0, 0, -400, 0, -400, 0, 0, 0, -400, 0, 0, -400, 0, 0, 0, -400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -400, 0, -400, -400, -400, -400, 0, 0, 0, 0, 0, -400, -400, -400, -400, 0, -400, -400, -400, -400, 0, 982, 0, 0, -400, -400, -400, -400, -400, 0, 0, -400, -400, -400, -400, 0, -400, -400, -400, -400, -400, -400, -400, -400, -400, 0, 0, 0, -400, -400, 0, -400, 0, 0, 0, -400, -400, 0, -400, -400, -400, -400, + 0, 0, 0, 0, 0, 0, 0, 0, -642, 0, 0, 0, 0, 0, 0, 982, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 929 - -534, 0, 0, 0, 0, 0, 0, 0, -534, 0, 0, 0, 0, 0, 0, -534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -18, 0, 0, 0, 0, 0, 0, -18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 930 - -537, 0, 0, 0, 0, 0, 0, 0, -537, 0, 0, 0, 0, 0, 0, -537, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -537, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -400, 0, 0, 0, 0, 0, 0, -400, 0, -400, 0, 0, 0, -400, 0, 0, -400, 0, 0, 0, -400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -400, 0, -400, -400, -400, -400, 0, 0, 0, 0, 0, -400, -400, -400, -400, 0, -400, -400, -400, -400, 0, 984, 0, 0, -400, -400, -400, -400, -400, 0, 0, -400, -400, -400, -400, 0, -400, -400, -400, -400, -400, -400, -400, -400, -400, 0, 0, 0, -400, -400, 0, -400, 0, 0, 0, -400, -400, 0, -400, -400, -400, -400, // State 931 - -441, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -441, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -535, 0, 0, 0, 0, 0, 0, 0, -535, 0, 0, 0, 0, 0, 0, -535, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -535, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 932 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 331, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -538, 0, 0, 0, 0, 0, 0, 0, -538, 0, 0, 0, 0, 0, 0, -538, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -538, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 933 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 332, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -441, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -441, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 934 - -532, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -532, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -532, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 331, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 935 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -491, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -491, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 332, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 936 - -856, 0, 0, 0, 0, 0, 0, -856, 0, -856, 0, 0, 0, -856, 0, 0, -856, 0, 0, 0, -856, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -856, 0, -856, -856, -856, -856, 0, 0, 0, 0, 0, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, -856, 0, 0, -856, -856, -856, -856, 0, -856, -856, -856, -856, -856, -856, -856, -856, -856, 0, 0, 0, -856, -856, 0, -856, 0, 0, 0, -856, -856, 0, -856, -856, -856, -856, + -533, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -533, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -533, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 937 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 938 - -340, 0, 0, 0, 0, 0, 0, -340, 0, -340, 0, 0, 0, -340, 0, 0, -340, 0, 0, 0, -340, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -340, 0, -340, -340, -340, -340, 0, 0, 0, 0, 0, -340, -340, -340, -340, 0, -340, -340, -340, -340, 0, -340, -340, -340, -340, -340, -340, -340, -340, 0, 0, -340, -340, -340, -340, 0, -340, -340, -340, -340, -340, -340, -340, -340, -340, 0, 0, 0, -340, -340, 0, -340, 0, 0, 0, -340, -340, 0, -340, -340, -340, -340, + -855, 0, 0, 0, 0, 0, 0, -855, 0, -855, 0, 0, 0, -855, 0, 0, -855, 0, 0, 0, -855, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -855, 0, -855, -855, -855, -855, 0, 0, 0, 0, 0, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, -855, 0, 0, -855, -855, -855, -855, 0, -855, -855, -855, -855, -855, -855, -855, -855, -855, 0, 0, 0, -855, -855, 0, -855, 0, 0, 0, -855, -855, 0, -855, -855, -855, -855, // State 939 - -893, 0, 0, 0, 0, 0, 0, -893, 0, -893, 0, 0, 0, -893, 0, 0, -893, 0, 0, 0, -893, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -893, 0, -893, -893, -893, -893, 0, 0, 0, 0, 0, -893, -893, -893, -893, 0, -893, -893, -893, -893, 0, 0, 0, 0, -893, -893, -893, -893, -893, 0, 0, -893, -893, -893, -893, 0, -893, -893, -893, -893, -893, -893, -893, -893, -893, 0, 0, 0, -893, -893, 0, -893, 0, 0, 0, -893, -893, 0, -893, -893, -893, -893, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 940 - 1016, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1017, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -340, 0, 0, 0, 0, 0, 0, -340, 0, -340, 0, 0, 0, -340, 0, 0, -340, 0, 0, 0, -340, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -340, 0, -340, -340, -340, -340, 0, 0, 0, 0, 0, -340, -340, -340, -340, 0, -340, -340, -340, -340, 0, -340, -340, -340, -340, -340, -340, -340, -340, 0, 0, -340, -340, -340, -340, 0, -340, -340, -340, -340, -340, -340, -340, -340, -340, 0, 0, 0, -340, -340, 0, -340, 0, 0, 0, -340, -340, 0, -340, -340, -340, -340, // State 941 - 0, 0, 0, 0, 0, 0, 0, -827, 0, -827, 0, 0, 0, -827, 0, 0, -827, 0, 0, 0, -827, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -827, 0, -827, -827, -827, -827, 0, 0, 0, 0, 0, -827, -827, -827, -827, 0, -827, -827, -827, -827, 0, 0, 0, 0, -827, -827, -827, -827, -827, 0, 0, -827, -827, -827, -827, 0, -827, -827, -827, -827, -827, -827, -827, -827, -827, 0, 0, 0, -827, -827, 0, -827, 0, 0, 0, -827, -827, 0, -827, -827, -827, -827, + -892, 0, 0, 0, 0, 0, 0, -892, 0, -892, 0, 0, 0, -892, 0, 0, -892, 0, 0, 0, -892, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -892, 0, -892, -892, -892, -892, 0, 0, 0, 0, 0, -892, -892, -892, -892, 0, -892, -892, -892, -892, 0, 0, 0, 0, -892, -892, -892, -892, -892, 0, 0, -892, -892, -892, -892, 0, -892, -892, -892, -892, -892, -892, -892, -892, -892, 0, 0, 0, -892, -892, 0, -892, 0, 0, 0, -892, -892, 0, -892, -892, -892, -892, // State 942 - 1018, 0, 0, 0, 0, 0, 0, -134, 0, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -134, -134, -134, -134, 0, 0, 0, 0, 0, -134, 0, -134, -134, 0, 0, -134, 0, -134, 0, 0, 0, 0, 0, -134, -134, 0, -134, 0, 0, -134, 0, -134, -134, 0, -134, -134, -134, 0, -134, 0, 0, -134, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, -134, 0, -134, -134, -134, -134, + 1017, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1018, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 943 - 0, 0, 0, 0, 0, 0, 0, -830, 0, -830, 0, 0, 0, -830, 0, 0, -830, 0, 0, 0, -830, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -830, 0, -830, -830, -830, -830, 0, 0, 0, 0, 0, -830, -830, -830, -830, 0, -830, -830, -830, -830, 0, 0, 0, 0, -830, -830, -830, -830, -830, 0, 0, -830, -830, -830, -830, 0, -830, -830, -830, -830, -830, -830, -830, -830, -830, 0, 0, 0, -830, -830, 0, -830, 0, 0, 0, -830, -830, 0, -830, -830, -830, -830, + 0, 0, 0, 0, 0, 0, 0, -828, 0, -828, 0, 0, 0, -828, 0, 0, -828, 0, 0, 0, -828, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -828, 0, -828, -828, -828, -828, 0, 0, 0, 0, 0, -828, -828, -828, -828, 0, -828, -828, -828, -828, 0, 0, 0, 0, -828, -828, -828, -828, -828, 0, 0, -828, -828, -828, -828, 0, -828, -828, -828, -828, -828, -828, -828, -828, -828, 0, 0, 0, -828, -828, 0, -828, 0, 0, 0, -828, -828, 0, -828, -828, -828, -828, // State 944 - 1020, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1021, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1019, 0, 0, 0, 0, 0, 0, -134, 0, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -134, -134, -134, -134, 0, 0, 0, 0, 0, -134, 0, -134, -134, 0, 0, -134, 0, -134, 0, 0, 0, 0, 0, -134, -134, 0, -134, 0, 0, -134, 0, -134, -134, 0, -134, -134, -134, 0, -134, 0, 0, -134, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, -134, 0, -134, -134, -134, -134, // State 945 - -859, 0, 0, 0, 0, 0, 0, -859, 0, -859, 0, 0, 0, -859, 0, 0, -859, 0, 0, 0, -859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -859, 0, -859, -859, -859, -859, 0, 0, 0, 0, 0, -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, 0, 0, -859, -859, -859, -859, 0, -859, -859, -859, -859, -859, -859, -859, -859, -859, 0, 0, 0, -859, -859, 0, -859, 0, 0, 0, -859, -859, 0, -859, -859, -859, -859, + 0, 0, 0, 0, 0, 0, 0, -831, 0, -831, 0, 0, 0, -831, 0, 0, -831, 0, 0, 0, -831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -831, 0, -831, -831, -831, -831, 0, 0, 0, 0, 0, -831, -831, -831, -831, 0, -831, -831, -831, -831, 0, 0, 0, 0, -831, -831, -831, -831, -831, 0, 0, -831, -831, -831, -831, 0, -831, -831, -831, -831, -831, -831, -831, -831, -831, 0, 0, 0, -831, -831, 0, -831, 0, 0, 0, -831, -831, 0, -831, -831, -831, -831, // State 946 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -864, 0, 0, 0, 0, 0, 0, 0, 0, 0, -869, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1021, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1022, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 947 - 0, 0, -194, -194, 0, -194, 0, -194, 0, -194, -194, 0, 0, -194, 0, -194, -194, 0, 0, -194, 0, -194, -194, 0, 0, -221, 0, 0, -194, -194, 0, -194, 0, -194, -194, -194, -194, 0, 0, -194, 0, 0, 0, 0, -194, 0, -194, 0, -194, -194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -194, 0, -194, -194, 0, 0, 0, -194, -194, 0, 0, 0, 0, 0, 0, 0, 0, 0, -194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -858, 0, 0, 0, 0, 0, 0, -858, 0, -858, 0, 0, 0, -858, 0, 0, -858, 0, 0, 0, -858, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -858, 0, -858, -858, -858, -858, 0, 0, 0, 0, 0, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, -858, 0, 0, -858, -858, -858, -858, 0, -858, -858, -858, -858, -858, -858, -858, -858, -858, 0, 0, 0, -858, -858, 0, -858, 0, 0, 0, -858, -858, 0, -858, -858, -858, -858, // State 948 - 0, 0, 0, 0, 0, 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -863, 0, 0, 0, 0, 0, 0, 0, 0, 0, -868, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -863, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 949 - 0, 0, -195, -195, 0, -195, 0, -195, 0, -195, -195, 0, 0, -195, 0, -195, -195, 0, 0, -195, 0, -195, -195, 0, 0, -222, 0, 0, -195, -195, 0, -195, 0, -195, -195, -195, -195, 0, 0, -195, 0, 0, 0, 0, -195, 0, -195, 0, -195, -195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -195, 0, -195, -195, 0, 0, 0, -195, -195, 0, 0, 0, 0, 0, 0, 0, 0, 0, -195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -194, -194, 0, -194, 0, -194, 0, -194, -194, 0, 0, -194, 0, -194, -194, 0, 0, -194, 0, -194, -194, 0, 0, -221, 0, 0, -194, -194, 0, -194, 0, -194, -194, -194, -194, 0, 0, -194, 0, 0, 0, 0, -194, 0, -194, 0, -194, -194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -194, 0, -194, -194, 0, 0, 0, -194, -194, 0, 0, 0, 0, 0, 0, 0, 0, 0, -194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 950 - 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1024, 0, 0, 0, 0, 0, 0, 348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 951 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -933, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -195, -195, 0, -195, 0, -195, 0, -195, -195, 0, 0, -195, 0, -195, -195, 0, 0, -195, 0, -195, -195, 0, 0, -222, 0, 0, -195, -195, 0, -195, 0, -195, -195, -195, -195, 0, 0, -195, 0, 0, 0, 0, -195, 0, -195, 0, -195, -195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -195, 0, -195, -195, 0, 0, 0, -195, -195, 0, 0, 0, 0, 0, 0, 0, 0, 0, -195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 952 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -932, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1026, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 953 - 0, 0, 0, 0, 0, 0, 0, 0, -319, 0, 0, 0, 0, 0, 0, -319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -319, 0, 0, 0, 0, 0, -319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -319, 0, 0, -319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -936, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 954 - 0, 0, 0, 0, 0, 0, 0, 0, -315, 0, 0, 0, 0, 0, 0, -315, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -315, 0, 0, 0, 0, 0, -315, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -315, 0, 0, -315, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -315, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -935, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 955 - 0, 0, 0, 0, 0, 0, 0, 0, -355, 0, 0, 0, 0, 0, 0, -355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -355, 0, 0, 0, 0, 0, -355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -355, 0, 0, -355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -319, 0, 0, 0, 0, 0, 0, -319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -319, 0, 0, 0, 0, 0, -319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -319, 0, 0, -319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 956 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -659, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -315, 0, 0, 0, 0, 0, 0, -315, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -315, 0, 0, 0, 0, 0, -315, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -315, 0, 0, -315, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -315, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 957 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1027, 0, 0, 0, 0, 0, 0, 0, 0, 0, -683, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -355, 0, 0, 0, 0, 0, 0, -355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -355, 0, 0, 0, 0, 0, -355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -355, 0, 0, -355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 958 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -660, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 959 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -706, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1028, 0, 0, 0, 0, 0, 0, 0, 0, 0, -684, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 960 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 0, 0, -700, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -651, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 961 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0, 0, 0, 0, -696, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -707, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 962 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, -681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 350, 0, 0, 0, 0, 0, 0, 0, 0, 0, -701, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 963 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 352, 0, 0, 0, 0, 0, 0, 0, 0, 0, -697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 964 - -408, 0, 0, 0, 0, 0, 0, -408, 0, -408, 0, 0, 0, -408, 0, 0, -408, 0, 0, 0, -408, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -408, 0, -408, -408, -408, -408, 0, 0, 0, 0, 0, -408, -408, -408, -408, 0, -408, -408, -408, -408, 0, 0, 0, 0, -408, -408, -408, -408, -408, 0, 0, -408, -408, -408, -408, 0, -408, -408, -408, -408, -408, -408, -408, -408, -408, 0, 0, 0, -408, -408, 0, -408, 0, 0, 0, -408, -408, 0, -408, -408, -408, -408, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1033, 0, 0, 0, 0, 0, 0, 0, 0, 0, -682, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 965 - -267, 0, 0, 0, 0, 0, 0, -267, 0, -267, 0, 0, 0, -267, 0, 0, -267, 0, 0, 0, -267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -267, 0, -267, -267, -267, -267, 0, 0, 0, 0, 0, -267, -267, -267, -267, 0, -267, -267, -267, -267, 0, 0, 0, 0, -267, -267, -267, -267, -267, 0, 0, -267, -267, -267, -267, 0, -267, -267, -267, -267, -267, -267, -267, -267, -267, 0, 0, 0, -267, -267, 0, -267, 0, 0, 0, -267, -267, 0, -267, -267, -267, -267, - // State 966 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 966 + -408, 0, 0, 0, 0, 0, 0, -408, 0, -408, 0, 0, 0, -408, 0, 0, -408, 0, 0, 0, -408, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -408, 0, -408, -408, -408, -408, 0, 0, 0, 0, 0, -408, -408, -408, -408, 0, -408, -408, -408, -408, 0, 0, 0, 0, -408, -408, -408, -408, -408, 0, 0, -408, -408, -408, -408, 0, -408, -408, -408, -408, -408, -408, -408, -408, -408, 0, 0, 0, -408, -408, 0, -408, 0, 0, 0, -408, -408, 0, -408, -408, -408, -408, // State 967 - -415, 0, 0, 0, 0, 0, 0, -415, 0, -415, 0, 0, 0, -415, 0, 0, -415, 0, 0, 0, -415, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -415, 0, -415, -415, -415, -415, 0, 0, 0, 0, 0, -415, -415, -415, -415, 0, -415, -415, -415, -415, 0, 0, 0, 0, -415, -415, -415, -415, -415, 0, 0, -415, -415, -415, -415, 0, -415, -415, -415, -415, -415, -415, -415, -415, -415, 0, 0, 0, -415, -415, 0, -415, 0, 0, 0, -415, -415, 0, -415, -415, -415, -415, + -267, 0, 0, 0, 0, 0, 0, -267, 0, -267, 0, 0, 0, -267, 0, 0, -267, 0, 0, 0, -267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -267, 0, -267, -267, -267, -267, 0, 0, 0, 0, 0, -267, -267, -267, -267, 0, -267, -267, -267, -267, 0, 0, 0, 0, -267, -267, -267, -267, -267, 0, 0, -267, -267, -267, -267, 0, -267, -267, -267, -267, -267, -267, -267, -267, -267, 0, 0, 0, -267, -267, 0, -267, 0, 0, 0, -267, -267, 0, -267, -267, -267, -267, // State 968 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 354, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 969 - -405, 0, 0, 0, 0, 0, 0, -405, 0, -405, 0, 0, 0, -405, 0, 0, -405, 0, 0, 0, -405, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -405, 0, -405, -405, -405, -405, 0, 0, 0, 0, 0, -405, -405, -405, -405, 0, -405, -405, -405, -405, 0, 0, 0, 0, -405, -405, -405, -405, -405, 0, 0, -405, -405, -405, -405, 0, -405, -405, -405, -405, -405, -405, -405, -405, -405, 0, 0, 0, -405, -405, 0, -405, 0, 0, 0, -405, -405, 0, -405, -405, -405, -405, + -415, 0, 0, 0, 0, 0, 0, -415, 0, -415, 0, 0, 0, -415, 0, 0, -415, 0, 0, 0, -415, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -415, 0, -415, -415, -415, -415, 0, 0, 0, 0, 0, -415, -415, -415, -415, 0, -415, -415, -415, -415, 0, 0, 0, 0, -415, -415, -415, -415, -415, 0, 0, -415, -415, -415, -415, 0, -415, -415, -415, -415, -415, -415, -415, -415, -415, 0, 0, 0, -415, -415, 0, -415, 0, 0, 0, -415, -415, 0, -415, -415, -415, -415, // State 970 - -398, 0, 0, 0, 0, 0, 0, -398, 0, -398, 0, 0, 0, -398, 0, 0, -398, 0, 0, 0, -398, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -398, 0, -398, -398, -398, -398, 0, 0, 0, 0, 0, -398, -398, -398, -398, 0, -398, -398, -398, -398, 0, 1037, 0, 0, -398, -398, -398, -398, -398, 0, 0, -398, -398, -398, -398, 0, -398, -398, -398, -398, -398, -398, -398, -398, -398, 0, 0, 0, -398, -398, 0, -398, 0, 0, 0, -398, -398, 0, -398, -398, -398, -398, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 971 - -410, 0, 0, 0, 0, 0, 0, -410, 0, -410, 0, 0, 0, -410, 0, 0, -410, 0, 0, 0, -410, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -410, 0, -410, -410, -410, -410, 0, 0, 0, 0, 0, -410, -410, -410, -410, 0, -410, -410, -410, -410, 0, 0, 0, 0, -410, -410, -410, -410, -410, 0, 0, -410, -410, -410, -410, 0, -410, -410, -410, -410, -410, -410, -410, -410, -410, 0, 0, 0, -410, -410, 0, -410, 0, 0, 0, -410, -410, 0, -410, -410, -410, -410, + -405, 0, 0, 0, 0, 0, 0, -405, 0, -405, 0, 0, 0, -405, 0, 0, -405, 0, 0, 0, -405, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -405, 0, -405, -405, -405, -405, 0, 0, 0, 0, 0, -405, -405, -405, -405, 0, -405, -405, -405, -405, 0, 0, 0, 0, -405, -405, -405, -405, -405, 0, 0, -405, -405, -405, -405, 0, -405, -405, -405, -405, -405, -405, -405, -405, -405, 0, 0, 0, -405, -405, 0, -405, 0, 0, 0, -405, -405, 0, -405, -405, -405, -405, // State 972 - 0, 0, 0, 0, 0, 0, 0, 0, -626, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -398, 0, 0, 0, 0, 0, 0, -398, 0, -398, 0, 0, 0, -398, 0, 0, -398, 0, 0, 0, -398, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -398, 0, -398, -398, -398, -398, 0, 0, 0, 0, 0, -398, -398, -398, -398, 0, -398, -398, -398, -398, 0, 1038, 0, 0, -398, -398, -398, -398, -398, 0, 0, -398, -398, -398, -398, 0, -398, -398, -398, -398, -398, -398, -398, -398, -398, 0, 0, 0, -398, -398, 0, -398, 0, 0, 0, -398, -398, 0, -398, -398, -398, -398, // State 973 - 0, 0, 0, 0, 0, 0, 0, 0, -620, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -410, 0, 0, 0, 0, 0, 0, -410, 0, -410, 0, 0, 0, -410, 0, 0, -410, 0, 0, 0, -410, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -410, 0, -410, -410, -410, -410, 0, 0, 0, 0, 0, -410, -410, -410, -410, 0, -410, -410, -410, -410, 0, 0, 0, 0, -410, -410, -410, -410, -410, 0, 0, -410, -410, -410, -410, 0, -410, -410, -410, -410, -410, -410, -410, -410, -410, 0, 0, 0, -410, -410, 0, -410, 0, 0, 0, -410, -410, 0, -410, -410, -410, -410, // State 974 - 0, 0, 0, 0, 0, 0, 0, 0, -625, 0, 0, 0, 0, 0, 0, 357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -627, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 975 - 0, 0, 0, 0, 0, 0, 0, 0, -643, 0, 0, 0, 0, 0, 0, 1042, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -621, 0, 0, 0, 0, 0, 0, 356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 976 - 0, 0, 0, 0, 0, 0, 0, 0, -19, 0, 0, 0, 0, 0, 0, -19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -626, 0, 0, 0, 0, 0, 0, 358, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 977 - 0, 0, 0, 0, 0, 0, 0, 0, -818, 0, 0, 0, 0, 0, 0, -818, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -644, 0, 0, 0, 0, 0, 0, 1043, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 978 - 0, 0, 0, 0, 0, 0, 0, 0, -640, 0, 0, 0, 0, 0, 0, 1044, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -19, 0, 0, 0, 0, 0, 0, -19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 979 - 0, 0, 0, 0, 0, 0, 0, 0, -633, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -819, 0, 0, 0, 0, 0, 0, -819, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 980 - 0, 0, 0, 0, 0, 0, 0, 0, -335, 0, 0, 0, 0, 0, 0, -335, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -641, 0, 0, 0, 0, 0, 0, 1045, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 981 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -634, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 982 - -440, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -440, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -335, 0, 0, 0, 0, 0, 0, -335, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 983 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 984 - -431, 0, 0, 0, 0, 0, 0, -431, 0, -431, 0, 0, 0, -431, 0, 0, -431, 0, 0, 0, -431, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -431, 0, -431, -431, -431, -431, 0, 0, 0, 0, 0, -431, -431, -431, -431, 0, -431, -431, -431, -431, 0, 0, 0, 0, -431, -431, -431, -431, -431, 0, 0, -431, -431, -431, -431, 0, -431, -431, -431, -431, -431, -431, -431, -431, -431, 0, 0, 0, -431, -431, 0, -431, 0, 0, 0, -431, -431, 0, -431, -431, -431, -431, + -440, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -440, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 985 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 361, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 986 - -498, 0, 0, 0, 0, 0, 0, -498, 0, -498, 0, 0, 0, -498, 0, 0, -498, 0, 0, 0, -498, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -498, 0, -498, -498, -498, -498, 0, 0, 0, 0, 0, -498, -498, -498, -498, 0, -498, -498, -498, -498, 0, 0, 0, 0, -498, -498, -498, -498, -498, 0, 0, -498, -498, -498, -498, 0, -498, -498, -498, -498, -498, -498, -498, -498, -498, 0, 0, 0, -498, -498, 0, -498, 0, 0, 0, -498, -498, 0, -498, -498, -498, -498, + -431, 0, 0, 0, 0, 0, 0, -431, 0, -431, 0, 0, 0, -431, 0, 0, -431, 0, 0, 0, -431, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -431, 0, -431, -431, -431, -431, 0, 0, 0, 0, 0, -431, -431, -431, -431, 0, -431, -431, -431, -431, 0, 0, 0, 0, -431, -431, -431, -431, -431, 0, 0, -431, -431, -431, -431, 0, -431, -431, -431, -431, -431, -431, -431, -431, -431, 0, 0, 0, -431, -431, 0, -431, 0, 0, 0, -431, -431, 0, -431, -431, -431, -431, // State 987 - 0, 0, 0, 0, 0, 0, 0, 0, -473, 0, 0, 0, 0, 0, 0, -473, 0, 0, 0, 0, 0, 0, 0, 0, 0, -473, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -473, 0, 0, 0, -473, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -473, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -473, 0, -473, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -493, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -493, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 988 - 0, 0, 0, 0, 0, 0, 0, 0, -749, 0, 0, 0, 0, 0, 0, -749, 0, 0, 0, 0, 0, 0, 0, 0, 0, -749, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -749, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -749, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -749, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -499, 0, 0, 0, 0, 0, 0, -499, 0, -499, 0, 0, 0, -499, 0, 0, -499, 0, 0, 0, -499, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -499, 0, -499, -499, -499, -499, 0, 0, 0, 0, 0, -499, -499, -499, -499, 0, -499, -499, -499, -499, 0, 0, 0, 0, -499, -499, -499, -499, -499, 0, 0, -499, -499, -499, -499, 0, -499, -499, -499, -499, -499, -499, -499, -499, -499, 0, 0, 0, -499, -499, 0, -499, 0, 0, 0, -499, -499, 0, -499, -499, -499, -499, // State 989 - 0, 0, 0, 0, 0, 0, 0, 0, -276, 0, 0, 0, 0, 0, 0, -276, 0, 0, 0, 0, 0, 0, 0, 0, 0, -276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -276, 0, 0, 0, -276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -276, 0, -276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -473, 0, 0, 0, 0, 0, 0, -473, 0, 0, 0, 0, 0, 0, 0, 0, 0, -473, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -473, 0, 0, 0, -473, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -473, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -473, 0, -473, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 990 - 0, 0, 0, 0, 0, 0, 0, 0, -281, 0, 0, 0, 0, 0, 0, -281, 0, 0, 0, 0, 0, 0, 0, 0, 0, -281, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -281, 0, 0, 0, -281, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -281, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -281, 0, -281, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -750, 0, 0, 0, 0, 0, 0, -750, 0, 0, 0, 0, 0, 0, 0, 0, 0, -750, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -750, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -750, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -750, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 991 - 0, 0, 0, 0, 0, 0, 0, 0, -556, 0, 0, 0, 0, 0, 0, -556, 0, 0, 0, 0, 0, 0, 0, 0, 0, -556, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -556, 0, 0, 0, -556, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -556, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 361, 0, -556, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -276, 0, 0, 0, 0, 0, 0, -276, 0, 0, 0, 0, 0, 0, 0, 0, 0, -276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -276, 0, 0, 0, -276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -276, 0, -276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 992 - 0, 0, 0, 0, 0, 0, 0, -495, -264, 0, 0, 0, 0, 0, 0, -264, 0, 0, 0, -495, 0, 0, 0, 0, 0, -264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -264, 0, 0, 0, -264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -264, 0, -264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -281, 0, 0, 0, 0, 0, 0, -281, 0, 0, 0, 0, 0, 0, 0, 0, 0, -281, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -281, 0, 0, 0, -281, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -281, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -281, 0, -281, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 993 - 0, 0, 0, 0, 0, 0, 0, 0, -275, 0, 0, 0, 0, 0, 0, -275, 0, 0, 0, 0, 0, 0, 0, 0, 0, -275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -275, 0, 0, 0, -275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -275, 0, -275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -557, 0, 0, 0, 0, 0, 0, -557, 0, 0, 0, 0, 0, 0, 0, 0, 0, -557, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -557, 0, 0, 0, -557, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -557, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 362, 0, -557, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 994 - 0, 0, 0, 0, 0, 0, 0, 0, -280, 0, 0, 0, 0, 0, 0, -280, 0, 0, 0, 0, 0, 0, 0, 0, 0, -280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -280, 0, 0, 0, -280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -280, 0, -280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -496, -264, 0, 0, 0, 0, 0, 0, -264, 0, 0, 0, -496, 0, 0, 0, 0, 0, -264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -264, 0, 0, 0, -264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -264, 0, -264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 995 - 0, 0, 0, 0, 0, 0, 0, 0, -521, 0, 0, 0, 0, -521, 0, -521, -521, 0, 0, 0, 0, 0, 0, 0, 0, -521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -521, 0, 0, 0, -521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -521, 0, -521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -275, 0, 0, 0, 0, 0, 0, -275, 0, 0, 0, 0, 0, 0, 0, 0, 0, -275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -275, 0, 0, 0, -275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -275, 0, -275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 996 - 0, 0, 0, 0, 0, 0, 0, 0, -522, 0, 0, 0, 0, -522, 0, -522, -522, 0, 0, 0, 0, 0, 0, 0, 0, -522, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -522, 0, 0, 0, -522, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -522, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -522, 0, -522, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -280, 0, 0, 0, 0, 0, 0, -280, 0, 0, 0, 0, 0, 0, 0, 0, 0, -280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -280, 0, 0, 0, -280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -280, 0, -280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 997 - 0, 0, 0, 0, 0, 0, 0, 0, -750, 0, 0, 0, 0, 0, 0, -750, 0, 0, 0, 0, 0, 0, 0, 0, 0, -750, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -750, 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -750, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -750, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -522, 0, 0, 0, 0, -522, 0, -522, -522, 0, 0, 0, 0, 0, 0, 0, 0, -522, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -522, 0, 0, 0, -522, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -522, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -522, 0, -522, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 998 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 367, 0, 0, 0, 0, 0, 0, 0, 0, 0, -763, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -763, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -523, 0, 0, 0, 0, -523, 0, -523, -523, 0, 0, 0, 0, 0, 0, 0, 0, -523, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -523, 0, 0, 0, -523, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -523, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -523, 0, -523, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 999 - 0, 0, 0, 0, 0, 0, 0, 0, -279, 0, 0, 0, 0, 0, 0, -279, 0, 0, 0, 0, 0, 0, 0, 0, 0, -279, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -279, 0, 0, 0, -279, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -279, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -279, 0, -279, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -751, 0, 0, 0, 0, 0, 0, -751, 0, 0, 0, 0, 0, 0, 0, 0, 0, -751, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -751, 0, 0, 0, 367, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -751, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -751, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1000 - 0, 0, 0, 0, 0, 0, 0, 0, -277, 0, 0, 0, 0, 0, 0, -277, 0, 0, 0, 0, 0, 0, 0, 0, 0, -277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -277, 0, 0, 0, -277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -277, 0, -277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 368, 0, 0, 0, 0, 0, 0, 0, 0, 0, -764, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -764, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1001 - 0, 0, 0, 0, 0, 0, 0, 0, -836, 0, 0, 0, 0, 0, 0, -836, 0, 0, 0, 0, 0, 0, 0, 0, 0, -836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -836, 0, 0, 0, -836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -836, 0, -836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -836, + 0, 0, 0, 0, 0, 0, 0, 0, -279, 0, 0, 0, 0, 0, 0, -279, 0, 0, 0, 0, 0, 0, 0, 0, 0, -279, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -279, 0, 0, 0, -279, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -279, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -279, 0, -279, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1002 - 0, 0, 0, 0, 0, 0, 0, 0, -557, 0, 0, 0, 0, 0, 0, -557, 0, 0, 0, 0, 0, 0, 0, 0, 0, -557, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -557, 0, 0, 0, -557, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -557, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 370, 0, -557, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -277, 0, 0, 0, 0, 0, 0, -277, 0, 0, 0, 0, 0, 0, 0, 0, 0, -277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -277, 0, 0, 0, -277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -277, 0, -277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1003 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 371, 0, 0, 0, 0, 0, 0, 0, 0, 0, -762, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -762, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -558, 0, 0, 0, 0, 0, 0, -558, 0, 0, 0, 0, 0, 0, 0, 0, 0, -558, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -558, 0, 0, 0, -558, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -558, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 371, 0, -558, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1004 - 0, 0, 0, 0, 0, 0, 0, 0, -278, 0, 0, 0, 0, 0, 0, -278, 0, 0, 0, 0, 0, 0, 0, 0, 0, -278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -278, 0, 0, 0, -278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -278, 0, -278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 372, 0, 0, 0, 0, 0, 0, 0, 0, 0, -763, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -763, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1005 - 0, 0, 0, 0, 0, 0, 0, 0, -471, 0, 0, 0, 0, 0, 0, -471, 0, 0, 0, 0, 0, 0, 0, 0, 0, -471, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -471, 0, 0, 0, -471, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -471, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -471, 0, -471, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -278, 0, 0, 0, 0, 0, 0, -278, 0, 0, 0, 0, 0, 0, 0, 0, 0, -278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -278, 0, 0, 0, -278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -278, 0, -278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1006 - 0, 0, 0, 0, 0, 0, 0, 0, -469, 0, 0, 0, 0, 0, 0, -469, 0, 0, 0, 0, 0, 0, 0, 0, 0, -469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -469, 0, 0, 0, -469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -469, 0, -469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -471, 0, 0, 0, 0, 0, 0, -471, 0, 0, 0, 0, 0, 0, 0, 0, 0, -471, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -471, 0, 0, 0, -471, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -471, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -471, 0, -471, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1007 - 0, 0, 0, 0, 0, 0, 0, 0, -470, 0, 0, 0, 0, 0, 0, -470, 0, 0, 0, 0, 0, 0, 0, 0, 0, -470, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -470, 0, 0, 0, -470, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -470, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -470, 0, -470, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -469, 0, 0, 0, 0, 0, 0, -469, 0, 0, 0, 0, 0, 0, 0, 0, 0, -469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -469, 0, 0, 0, -469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -469, 0, -469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1008 - -501, 0, 0, 0, 0, 0, 0, -501, 0, -501, 0, 0, 0, -501, 0, 0, -501, 0, 0, 0, -501, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -501, 0, -501, -501, -501, -501, 0, 0, 0, 0, 0, -501, -501, -501, -501, 0, -501, -501, -501, -501, 0, 0, 0, 0, -501, -501, -501, -501, -501, 0, 0, -501, -501, -501, -501, 0, -501, -501, -501, -501, -501, -501, -501, -501, -501, 0, 0, 0, -501, -501, 0, -501, 0, 0, 0, -501, -501, 0, -501, -501, -501, -501, + 0, 0, 0, 0, 0, 0, 0, 0, -470, 0, 0, 0, 0, 0, 0, -470, 0, 0, 0, 0, 0, 0, 0, 0, 0, -470, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -470, 0, 0, 0, -470, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -470, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -470, 0, -470, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1009 - -886, 0, 0, 0, 0, 0, 0, -886, 0, -886, 0, 0, 0, -886, 0, 0, -886, 0, 0, 0, -886, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -886, 0, -886, -886, -886, -886, 0, 0, 0, 0, 0, -886, -886, -886, -886, 0, -886, -886, -886, -886, 0, 0, 0, 1071, -886, -886, -886, -886, -886, 0, 0, -886, -886, -886, -886, 0, -886, -886, -886, -886, -886, -886, -886, -886, -886, 0, 0, 0, -886, -886, 0, -886, 0, 0, 0, -886, -886, 0, -886, -886, -886, -886, + -502, 0, 0, 0, 0, 0, 0, -502, 0, -502, 0, 0, 0, -502, 0, 0, -502, 0, 0, 0, -502, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -502, 0, -502, -502, -502, -502, 0, 0, 0, 0, 0, -502, -502, -502, -502, 0, -502, -502, -502, -502, 0, 0, 0, 0, -502, -502, -502, -502, -502, 0, 0, -502, -502, -502, -502, 0, -502, -502, -502, -502, -502, -502, -502, -502, -502, 0, 0, 0, -502, -502, 0, -502, 0, 0, 0, -502, -502, 0, -502, -502, -502, -502, // State 1010 - -887, 0, 0, 0, 0, 0, 0, -887, 0, -887, 0, 0, 0, -887, 0, 0, -887, 0, 0, 0, -887, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -887, 0, -887, -887, -887, -887, 0, 0, 0, 0, 0, -887, -887, -887, -887, 0, -887, -887, -887, -887, 0, 0, 0, 0, -887, -887, -887, -887, -887, 0, 0, -887, -887, -887, -887, 0, -887, -887, -887, -887, -887, -887, -887, -887, -887, 0, 0, 0, -887, -887, 0, -887, 0, 0, 0, -887, -887, 0, -887, -887, -887, -887, + -885, 0, 0, 0, 0, 0, 0, -885, 0, -885, 0, 0, 0, -885, 0, 0, -885, 0, 0, 0, -885, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -885, 0, -885, -885, -885, -885, 0, 0, 0, 0, 0, -885, -885, -885, -885, 0, -885, -885, -885, -885, 0, 0, 0, 1074, -885, -885, -885, -885, -885, 0, 0, -885, -885, -885, -885, 0, -885, -885, -885, -885, -885, -885, -885, -885, -885, 0, 0, 0, -885, -885, 0, -885, 0, 0, 0, -885, -885, 0, -885, -885, -885, -885, // State 1011 - -890, 0, 0, 0, 0, 0, 0, -890, 0, -890, 0, 0, 0, -890, 0, 0, -890, 0, 0, 0, -890, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -890, 0, -890, -890, -890, -890, 0, 0, 0, 0, 0, -890, -890, -890, -890, 0, -890, -890, -890, -890, 0, 0, 0, 1072, -890, -890, -890, -890, -890, 0, 0, -890, -890, -890, -890, 0, -890, -890, -890, -890, -890, -890, -890, -890, -890, 0, 0, 0, -890, -890, 0, -890, 0, 0, 0, -890, -890, 0, -890, -890, -890, -890, + -886, 0, 0, 0, 0, 0, 0, -886, 0, -886, 0, 0, 0, -886, 0, 0, -886, 0, 0, 0, -886, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -886, 0, -886, -886, -886, -886, 0, 0, 0, 0, 0, -886, -886, -886, -886, 0, -886, -886, -886, -886, 0, 0, 0, 0, -886, -886, -886, -886, -886, 0, 0, -886, -886, -886, -886, 0, -886, -886, -886, -886, -886, -886, -886, -886, -886, 0, 0, 0, -886, -886, 0, -886, 0, 0, 0, -886, -886, 0, -886, -886, -886, -886, // State 1012 - -891, 0, 0, 0, 0, 0, 0, -891, 0, -891, 0, 0, 0, -891, 0, 0, -891, 0, 0, 0, -891, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -891, 0, -891, -891, -891, -891, 0, 0, 0, 0, 0, -891, -891, -891, -891, 0, -891, -891, -891, -891, 0, 0, 0, 0, -891, -891, -891, -891, -891, 0, 0, -891, -891, -891, -891, 0, -891, -891, -891, -891, -891, -891, -891, -891, -891, 0, 0, 0, -891, -891, 0, -891, 0, 0, 0, -891, -891, 0, -891, -891, -891, -891, + -889, 0, 0, 0, 0, 0, 0, -889, 0, -889, 0, 0, 0, -889, 0, 0, -889, 0, 0, 0, -889, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -889, 0, -889, -889, -889, -889, 0, 0, 0, 0, 0, -889, -889, -889, -889, 0, -889, -889, -889, -889, 0, 0, 0, 1075, -889, -889, -889, -889, -889, 0, 0, -889, -889, -889, -889, 0, -889, -889, -889, -889, -889, -889, -889, -889, -889, 0, 0, 0, -889, -889, 0, -889, 0, 0, 0, -889, -889, 0, -889, -889, -889, -889, // State 1013 - -339, 0, 0, 0, 0, 0, 0, -339, 0, -339, 0, 0, 0, -339, 0, 0, -339, 0, 0, 0, -339, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -339, 0, -339, -339, -339, -339, 0, 0, 0, 0, 0, -339, -339, -339, -339, 0, -339, -339, -339, -339, 0, -339, -339, -339, -339, -339, -339, -339, -339, 0, 0, -339, -339, -339, -339, 0, -339, -339, -339, -339, -339, -339, -339, -339, -339, 0, 0, 0, -339, -339, 0, -339, 0, 0, 0, -339, -339, 0, -339, -339, -339, -339, + -890, 0, 0, 0, 0, 0, 0, -890, 0, -890, 0, 0, 0, -890, 0, 0, -890, 0, 0, 0, -890, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -890, 0, -890, -890, -890, -890, 0, 0, 0, 0, 0, -890, -890, -890, -890, 0, -890, -890, -890, -890, 0, 0, 0, 0, -890, -890, -890, -890, -890, 0, 0, -890, -890, -890, -890, 0, -890, -890, -890, -890, -890, -890, -890, -890, -890, 0, 0, 0, -890, -890, 0, -890, 0, 0, 0, -890, -890, 0, -890, -890, -890, -890, // State 1014 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -339, 0, 0, 0, 0, 0, 0, -339, 0, -339, 0, 0, 0, -339, 0, 0, -339, 0, 0, 0, -339, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -339, 0, -339, -339, -339, -339, 0, 0, 0, 0, 0, -339, -339, -339, -339, 0, -339, -339, -339, -339, 0, -339, -339, -339, -339, -339, -339, -339, -339, 0, 0, -339, -339, -339, -339, 0, -339, -339, -339, -339, -339, -339, -339, -339, -339, 0, 0, 0, -339, -339, 0, -339, 0, 0, 0, -339, -339, 0, -339, -339, -339, -339, // State 1015 - 0, 0, 0, 0, 0, 0, 0, -828, 0, -828, 0, 0, 0, -828, 0, 0, -828, 0, 0, 0, -828, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -828, 0, -828, -828, -828, -828, 0, 0, 0, 0, 0, -828, -828, -828, -828, 0, -828, -828, -828, -828, 0, 0, 0, 0, -828, -828, -828, -828, -828, 0, 0, -828, -828, -828, -828, 0, -828, -828, -828, -828, -828, -828, -828, -828, -828, 0, 0, 0, -828, -828, 0, -828, 0, 0, 0, -828, -828, 0, -828, -828, -828, -828, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1016 - 1075, 0, 0, 0, 0, 0, 0, -135, 0, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -135, -135, -135, -135, 0, 0, 0, 0, 0, -135, 0, -135, -135, 0, 0, -135, 0, -135, 0, 0, 0, 0, 0, -135, -135, 0, -135, 0, 0, -135, 0, -135, -135, 0, -135, -135, -135, 0, -135, 0, 0, -135, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, -135, 0, -135, -135, -135, -135, + 0, 0, 0, 0, 0, 0, 0, -829, 0, -829, 0, 0, 0, -829, 0, 0, -829, 0, 0, 0, -829, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -829, 0, -829, -829, -829, -829, 0, 0, 0, 0, 0, -829, -829, -829, -829, 0, -829, -829, -829, -829, 0, 0, 0, 0, -829, -829, -829, -829, -829, 0, 0, -829, -829, -829, -829, 0, -829, -829, -829, -829, -829, -829, -829, -829, -829, 0, 0, 0, -829, -829, 0, -829, 0, 0, 0, -829, -829, 0, -829, -829, -829, -829, // State 1017 - 0, 0, 0, 0, 0, 0, 0, -825, 0, -825, 0, 0, 0, -825, 0, 0, -825, 0, 0, 0, -825, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -825, 0, -825, -825, -825, -825, 0, 0, 0, 0, 0, -825, -825, -825, -825, 0, -825, -825, -825, -825, 0, 0, 0, 0, -825, -825, -825, -825, -825, 0, 0, -825, -825, -825, -825, 0, -825, -825, -825, -825, -825, -825, -825, -825, -825, 0, 0, 0, -825, -825, 0, -825, 0, 0, 0, -825, -825, 0, -825, -825, -825, -825, + 1078, 0, 0, 0, 0, 0, 0, -135, 0, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -135, -135, -135, -135, 0, 0, 0, 0, 0, -135, 0, -135, -135, 0, 0, -135, 0, -135, 0, 0, 0, 0, 0, -135, -135, 0, -135, 0, 0, -135, 0, -135, -135, 0, -135, -135, -135, 0, -135, 0, 0, -135, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, -135, 0, -135, -135, -135, -135, // State 1018 - 1076, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1077, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -826, 0, -826, 0, 0, 0, -826, 0, 0, -826, 0, 0, 0, -826, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -826, 0, -826, -826, -826, -826, 0, 0, 0, 0, 0, -826, -826, -826, -826, 0, -826, -826, -826, -826, 0, 0, 0, 0, -826, -826, -826, -826, -826, 0, 0, -826, -826, -826, -826, 0, -826, -826, -826, -826, -826, -826, -826, -826, -826, 0, 0, 0, -826, -826, 0, -826, 0, 0, 0, -826, -826, 0, -826, -826, -826, -826, // State 1019 - 0, 0, 0, 0, 0, 0, 0, -833, 0, -833, 0, 0, 0, -833, 0, 0, -833, 0, 0, 0, -833, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -833, 0, -833, -833, -833, -833, 0, 0, 0, 0, 0, -833, -833, -833, -833, 0, -833, -833, -833, -833, 0, 0, 0, 0, -833, -833, -833, -833, -833, 0, 0, -833, -833, -833, -833, 0, -833, -833, -833, -833, -833, -833, -833, -833, -833, 0, 0, 0, -833, -833, 0, -833, 0, 0, 0, -833, -833, 0, -833, -833, -833, -833, + 1079, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1080, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1020 - 1078, 0, 0, 0, 0, 0, 0, -134, 0, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -134, -134, -134, -134, 0, 0, 0, 0, 0, -134, 0, -134, -134, 0, 0, -134, 0, -134, 0, 0, 0, 0, 0, -134, -134, 0, -134, 0, 0, -134, 0, -134, -134, 0, -134, -134, -134, 0, -134, 0, 0, -134, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, -134, 0, -134, -134, -134, -134, + 0, 0, 0, 0, 0, 0, 0, -834, 0, -834, 0, 0, 0, -834, 0, 0, -834, 0, 0, 0, -834, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -834, 0, -834, -834, -834, -834, 0, 0, 0, 0, 0, -834, -834, -834, -834, 0, -834, -834, -834, -834, 0, 0, 0, 0, -834, -834, -834, -834, -834, 0, 0, -834, -834, -834, -834, 0, -834, -834, -834, -834, -834, -834, -834, -834, -834, 0, 0, 0, -834, -834, 0, -834, 0, 0, 0, -834, -834, 0, -834, -834, -834, -834, // State 1021 - -920, 0, 0, 0, 0, 0, 0, -920, 0, -920, 0, 0, 0, -920, 0, 0, -920, 0, 0, 0, -920, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -920, 0, -920, -920, -920, -920, 0, 0, 0, 0, 0, -920, -920, -920, -920, 0, -920, -920, -920, -920, 0, 0, 0, 0, -920, -920, -920, -920, -920, 0, 0, -920, -920, -920, -920, 0, -920, -920, -920, -920, -920, -920, -920, -920, -920, 0, 0, 0, -920, -920, 0, -920, 0, 0, 0, -920, -920, 0, -920, -920, -920, -920, + 1081, 0, 0, 0, 0, 0, 0, -134, 0, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -134, -134, -134, -134, 0, 0, 0, 0, 0, -134, 0, -134, -134, 0, 0, -134, 0, -134, 0, 0, 0, 0, 0, -134, -134, 0, -134, 0, 0, -134, 0, -134, -134, 0, -134, -134, -134, 0, -134, 0, 0, -134, -134, 0, 0, 0, -134, 0, 0, -134, 0, 0, 0, -134, -134, 0, -134, -134, -134, -134, // State 1022 - 0, 0, -197, -197, 0, -197, 0, -197, 0, -197, -197, 0, 0, -197, 0, -197, -197, 0, 0, -197, 0, -197, -197, 0, 0, -224, 0, 0, -197, -197, 0, -197, 0, -197, -197, -197, -197, 0, 0, -197, 0, 0, 0, 0, -197, 0, -197, 0, -197, -197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -197, 0, -197, -197, 0, 0, 0, -197, -197, 0, 0, 0, 0, 0, 0, 0, 0, 0, -197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -923, 0, 0, 0, 0, 0, 0, -923, 0, -923, 0, 0, 0, -923, 0, 0, -923, 0, 0, 0, -923, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -923, 0, -923, -923, -923, -923, 0, 0, 0, 0, 0, -923, -923, -923, -923, 0, -923, -923, -923, -923, 0, 0, 0, 0, -923, -923, -923, -923, -923, 0, 0, -923, -923, -923, -923, 0, -923, -923, -923, -923, -923, -923, -923, -923, -923, 0, 0, 0, -923, -923, 0, -923, 0, 0, 0, -923, -923, 0, -923, -923, -923, -923, // State 1023 - 0, 0, -191, -191, 0, -191, 0, -191, 0, -191, -191, 0, 0, -191, 0, -191, -191, 0, 0, -191, 0, -191, -191, 0, 0, -218, 0, 0, -191, -191, 0, -191, 0, -191, -191, -191, -191, 0, 0, -191, 0, 0, 0, 0, -191, 0, -191, 0, -191, -191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -191, 0, -191, -191, 0, 0, 0, -191, -191, 0, 0, 0, 0, 0, 0, 0, 0, 0, -191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -197, -197, 0, -197, 0, -197, 0, -197, -197, 0, 0, -197, 0, -197, -197, 0, 0, -197, 0, -197, -197, 0, 0, -224, 0, 0, -197, -197, 0, -197, 0, -197, -197, -197, -197, 0, 0, -197, 0, 0, 0, 0, -197, 0, -197, 0, -197, -197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -197, 0, -197, -197, 0, 0, 0, -197, -197, 0, 0, 0, 0, 0, 0, 0, 0, 0, -197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1024 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -935, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -191, -191, 0, -191, 0, -191, 0, -191, -191, 0, 0, -191, 0, -191, -191, 0, 0, -191, 0, -191, -191, 0, 0, -218, 0, 0, -191, -191, 0, -191, 0, -191, -191, -191, -191, 0, 0, -191, 0, 0, 0, 0, -191, 0, -191, 0, -191, -191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -191, 0, -191, -191, 0, 0, 0, -191, -191, 0, 0, 0, 0, 0, 0, 0, 0, 0, -191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1025 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -929, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1026 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -932, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1027 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 378, 0, 0, 0, 0, 0, 0, 0, 0, 0, -697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -657, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1028 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1083, 0, 0, 0, 0, 0, 0, 0, 0, 0, -682, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 378, 0, 0, 0, 0, 0, 0, 0, 0, 0, -698, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1029 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1084, 0, 0, 0, 0, 0, 0, 0, 0, 0, -687, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1086, 0, 0, 0, 0, 0, 0, 0, 0, 0, -683, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1030 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1086, 0, 0, 0, 0, 0, 0, 0, 0, 0, -678, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1087, 0, 0, 0, 0, 0, 0, 0, 0, 0, -688, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1031 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -654, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1089, 0, 0, 0, 0, 0, 0, 0, 0, 0, -679, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1032 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 379, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -655, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1033 - -407, 0, 0, 0, 0, 0, 0, -407, 0, -407, 0, 0, 0, -407, 0, 0, -407, 0, 0, 0, -407, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -407, 0, -407, -407, -407, -407, 0, 0, 0, 0, 0, -407, -407, -407, -407, 0, -407, -407, -407, -407, 0, 0, 0, 0, -407, -407, -407, -407, -407, 0, 0, -407, -407, -407, -407, 0, -407, -407, -407, -407, -407, -407, -407, -407, -407, 0, 0, 0, -407, -407, 0, -407, 0, 0, 0, -407, -407, 0, -407, -407, -407, -407, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 379, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1034 - -412, 0, 0, 0, 0, 0, 0, -412, 0, -412, 0, 0, 0, -412, 0, 0, -412, 0, 0, 0, -412, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -412, 0, -412, -412, -412, -412, 0, 0, 0, 0, 0, -412, -412, -412, -412, 0, -412, -412, -412, -412, 0, 0, 0, 0, -412, -412, -412, -412, -412, 0, 0, -412, -412, -412, -412, 0, -412, -412, -412, -412, -412, -412, -412, -412, -412, 0, 0, 0, -412, -412, 0, -412, 0, 0, 0, -412, -412, 0, -412, -412, -412, -412, + -407, 0, 0, 0, 0, 0, 0, -407, 0, -407, 0, 0, 0, -407, 0, 0, -407, 0, 0, 0, -407, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -407, 0, -407, -407, -407, -407, 0, 0, 0, 0, 0, -407, -407, -407, -407, 0, -407, -407, -407, -407, 0, 0, 0, 0, -407, -407, -407, -407, -407, 0, 0, -407, -407, -407, -407, 0, -407, -407, -407, -407, -407, -407, -407, -407, -407, 0, 0, 0, -407, -407, 0, -407, 0, 0, 0, -407, -407, 0, -407, -407, -407, -407, // State 1035 - -402, 0, 0, 0, 0, 0, 0, -402, 0, -402, 0, 0, 0, -402, 0, 0, -402, 0, 0, 0, -402, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -402, 0, -402, -402, -402, -402, 0, 0, 0, 0, 0, -402, -402, -402, -402, 0, -402, -402, -402, -402, 0, 0, 0, 0, -402, -402, -402, -402, -402, 0, 0, -402, -402, -402, -402, 0, -402, -402, -402, -402, -402, -402, -402, -402, -402, 0, 0, 0, -402, -402, 0, -402, 0, 0, 0, -402, -402, 0, -402, -402, -402, -402, + -412, 0, 0, 0, 0, 0, 0, -412, 0, -412, 0, 0, 0, -412, 0, 0, -412, 0, 0, 0, -412, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -412, 0, -412, -412, -412, -412, 0, 0, 0, 0, 0, -412, -412, -412, -412, 0, -412, -412, -412, -412, 0, 0, 0, 0, -412, -412, -412, -412, -412, 0, 0, -412, -412, -412, -412, 0, -412, -412, -412, -412, -412, -412, -412, -412, -412, 0, 0, 0, -412, -412, 0, -412, 0, 0, 0, -412, -412, 0, -412, -412, -412, -412, // State 1036 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 380, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -402, 0, 0, 0, 0, 0, 0, -402, 0, -402, 0, 0, 0, -402, 0, 0, -402, 0, 0, 0, -402, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -402, 0, -402, -402, -402, -402, 0, 0, 0, 0, 0, -402, -402, -402, -402, 0, -402, -402, -402, -402, 0, 0, 0, 0, -402, -402, -402, -402, -402, 0, 0, -402, -402, -402, -402, 0, -402, -402, -402, -402, -402, -402, -402, -402, -402, 0, 0, 0, -402, -402, 0, -402, 0, 0, 0, -402, -402, 0, -402, -402, -402, -402, // State 1037 - -409, 0, 0, 0, 0, 0, 0, -409, 0, -409, 0, 0, 0, -409, 0, 0, -409, 0, 0, 0, -409, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -409, 0, -409, -409, -409, -409, 0, 0, 0, 0, 0, -409, -409, -409, -409, 0, -409, -409, -409, -409, 0, 0, 0, 0, -409, -409, -409, -409, -409, 0, 0, -409, -409, -409, -409, 0, -409, -409, -409, -409, -409, -409, -409, -409, -409, 0, 0, 0, -409, -409, 0, -409, 0, 0, 0, -409, -409, 0, -409, -409, -409, -409, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 380, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1038 - 0, 0, 0, 0, 0, 0, 0, 0, -617, 0, 0, 0, 0, 0, 0, 381, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -409, 0, 0, 0, 0, 0, 0, -409, 0, -409, 0, 0, 0, -409, 0, 0, -409, 0, 0, 0, -409, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -409, 0, -409, -409, -409, -409, 0, 0, 0, 0, 0, -409, -409, -409, -409, 0, -409, -409, -409, -409, 0, 0, 0, 0, -409, -409, -409, -409, -409, 0, 0, -409, -409, -409, -409, 0, -409, -409, -409, -409, -409, -409, -409, -409, -409, 0, 0, 0, -409, -409, 0, -409, 0, 0, 0, -409, -409, 0, -409, -409, -409, -409, // State 1039 - 0, 0, 0, 0, 0, 0, 0, 0, -602, 0, 0, 0, 0, 0, 0, 1092, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -618, 0, 0, 0, 0, 0, 0, 381, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1040 - 0, 0, 0, 0, 0, 0, 0, 0, -630, 0, 0, 0, 0, 0, 0, 1094, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -603, 0, 0, 0, 0, 0, 0, 1095, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1041 - 0, 0, 0, 0, 0, 0, 0, 0, -635, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -631, 0, 0, 0, 0, 0, 0, 1097, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1042 - 0, 0, 0, 0, 0, 0, 0, 0, -642, 0, 0, 0, 0, 0, 0, 1096, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -636, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1043 - 0, 0, 0, 0, 0, 0, 0, 0, -632, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -643, 0, 0, 0, 0, 0, 0, 1099, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1044 - -536, 0, 0, 0, 0, 0, 0, 0, -536, 0, 0, 0, 0, 0, 0, -536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -633, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1045 - -433, 0, 0, 0, 0, 0, 0, -433, 0, -433, 0, 0, 0, -433, 0, 0, -433, 0, 0, 0, -433, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -433, 0, -433, -433, -433, -433, 0, 0, 0, 0, 0, -433, -433, -433, -433, 0, -433, -433, -433, -433, 0, 0, 0, 0, -433, -433, -433, -433, -433, 0, 0, -433, -433, -433, -433, 0, -433, -433, -433, -433, -433, -433, -433, -433, -433, 0, 0, 0, -433, -433, 0, -433, 0, 0, 0, -433, -433, 0, -433, -433, -433, -433, + -537, 0, 0, 0, 0, 0, 0, 0, -537, 0, 0, 0, 0, 0, 0, -537, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -537, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1046 - -107, 0, 0, 0, 0, 0, 0, -107, 0, -107, 0, 0, 0, -107, 0, 0, -107, 0, 0, 0, -107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -107, 0, -107, -107, -107, -107, 0, 0, 0, 0, 0, -107, -107, -107, -107, 0, -107, -107, -107, -107, -107, -107, 0, 0, -107, -107, -107, -107, -107, 0, 0, -107, -107, -107, -107, 0, -107, -107, -107, -107, -107, -107, -107, -107, -107, 0, 0, 0, -107, -107, 0, -107, 0, 0, 0, -107, -107, 0, -107, -107, -107, -107, + -433, 0, 0, 0, 0, 0, 0, -433, 0, -433, 0, 0, 0, -433, 0, 0, -433, 0, 0, 0, -433, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -433, 0, -433, -433, -433, -433, 0, 0, 0, 0, 0, -433, -433, -433, -433, 0, -433, -433, -433, -433, 0, 0, 0, 0, -433, -433, -433, -433, -433, 0, 0, -433, -433, -433, -433, 0, -433, -433, -433, -433, -433, -433, -433, -433, -433, 0, 0, 0, -433, -433, 0, -433, 0, 0, 0, -433, -433, 0, -433, -433, -433, -433, // State 1047 - -499, 0, 0, 0, 0, 0, 0, -499, 0, -499, 0, 0, 0, -499, 0, 0, -499, 0, 0, 0, -499, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -499, 0, -499, -499, -499, -499, 0, 0, 0, 0, 0, -499, -499, -499, -499, 0, -499, -499, -499, -499, 0, 0, 0, 0, -499, -499, -499, -499, -499, 0, 0, -499, -499, -499, -499, 0, -499, -499, -499, -499, -499, -499, -499, -499, -499, 0, 0, 0, -499, -499, 0, -499, 0, 0, 0, -499, -499, 0, -499, -499, -499, -499, + -107, 0, 0, 0, 0, 0, 0, -107, 0, -107, 0, 0, 0, -107, 0, 0, -107, 0, 0, 0, -107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -107, 0, -107, -107, -107, -107, 0, 0, 0, 0, 0, -107, -107, -107, -107, 0, -107, -107, -107, -107, -107, -107, 0, 0, -107, -107, -107, -107, -107, 0, 0, -107, -107, -107, -107, 0, -107, -107, -107, -107, -107, -107, -107, -107, -107, 0, 0, 0, -107, -107, 0, -107, 0, 0, 0, -107, -107, 0, -107, -107, -107, -107, // State 1048 - 0, 0, 0, 0, 0, 0, 0, 0, -273, 0, 0, 0, 0, 0, 0, -273, 0, 0, 0, 0, 0, 0, 0, 0, 0, -273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -273, 0, 0, 0, -273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -273, 0, -273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -500, 0, 0, 0, 0, 0, 0, -500, 0, -500, 0, 0, 0, -500, 0, 0, -500, 0, 0, 0, -500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -500, 0, -500, -500, -500, -500, 0, 0, 0, 0, 0, -500, -500, -500, -500, 0, -500, -500, -500, -500, 0, 0, 0, 0, -500, -500, -500, -500, -500, 0, 0, -500, -500, -500, -500, 0, -500, -500, -500, -500, -500, -500, -500, -500, -500, 0, 0, 0, -500, -500, 0, -500, 0, 0, 0, -500, -500, 0, -500, -500, -500, -500, // State 1049 - 0, 0, 0, 0, 0, 0, 0, 0, -274, 0, 0, 0, 0, 0, 0, -274, 0, 0, 0, 0, 0, 0, 0, 0, 0, -274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -274, 0, 0, 0, -274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -274, 0, -274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -273, 0, 0, 0, 0, 0, 0, -273, 0, 0, 0, 0, 0, 0, 0, 0, 0, -273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -273, 0, 0, 0, -273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -273, 0, -273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1050 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -274, 0, 0, 0, 0, 0, 0, -274, 0, 0, 0, 0, 0, 0, 0, 0, 0, -274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -274, 0, 0, 0, -274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -274, 0, -274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1051 - 0, 0, 0, 0, 0, 0, 0, 0, -837, 0, 0, 0, 0, 0, 0, -837, 0, 0, 0, 0, 0, 0, 0, 0, 0, -837, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -837, 0, 0, 0, -837, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -837, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -837, 0, -837, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -837, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1052 - 0, 0, 0, 0, 0, 0, 0, 0, 1116, 0, 0, 0, 0, 0, 0, 1117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -893, 0, 0, 0, 0, 0, 0, -893, 0, 0, 0, 0, 0, 0, 0, 0, 0, -893, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -893, 0, 0, 0, -893, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -893, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -893, 0, -893, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -893, // State 1053 - 0, 0, 0, 0, 0, 0, 0, 0, -779, 0, 0, 0, 0, 0, 0, -779, 0, 0, 0, 0, 0, 0, 0, 0, 0, -779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -779, 0, 0, 0, -779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -779, 0, -779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -894, 0, 0, 0, 0, 0, 0, -894, 0, 0, 0, 0, 0, 0, 0, 0, 0, -894, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -894, 0, 0, 0, -894, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -894, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -894, 0, -894, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -894, // State 1054 - 0, 0, 0, 0, 0, 0, 0, 0, -817, 0, 0, 0, 0, 0, 0, -817, 0, 0, 0, 0, 0, 0, 0, 0, 0, -817, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -817, 0, 0, 0, -817, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -817, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -817, 0, -817, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1119, 0, 0, 0, 0, 0, 0, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1055 - 0, 0, 0, 0, 0, 0, 0, 0, -523, 0, 0, 0, 0, -523, 0, -523, -523, 0, 0, 0, 0, 0, 0, 0, 0, -523, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -523, 0, 0, 0, -523, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -523, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -523, 0, -523, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -780, 0, 0, 0, 0, 0, 0, -780, 0, 0, 0, 0, 0, 0, 0, 0, 0, -780, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -780, 0, 0, 0, -780, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -780, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -780, 0, -780, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1056 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -818, 0, 0, 0, 0, 0, 0, -818, 0, 0, 0, 0, 0, 0, 0, 0, 0, -818, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -818, 0, 0, 0, -818, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -818, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -818, 0, -818, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1057 - 0, 0, 0, 0, 0, 0, 0, 0, -784, 0, 0, 0, 0, 0, 0, -784, 0, 0, 0, 0, 0, 0, 0, 0, 0, -784, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -784, 0, 0, 0, -784, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -784, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -784, 0, -784, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -524, 0, 0, 0, 0, -524, 0, -524, -524, 0, 0, 0, 0, 0, 0, 0, 0, -524, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -524, 0, 0, 0, -524, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -524, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -524, 0, -524, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1058 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -477, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1059 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -495, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -785, 0, 0, 0, 0, 0, 0, -785, 0, 0, 0, 0, 0, 0, 0, 0, 0, -785, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -785, 0, 0, 0, -785, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -785, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -785, 0, -785, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1060 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 386, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -479, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1061 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -540, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -540, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -496, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1062 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 363, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 386, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1063 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 364, 0, 0, 0, 0, 0, -475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -541, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -541, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1064 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 387, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 364, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1065 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -480, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 365, 0, 0, 0, 0, 0, -476, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1066 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -478, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 387, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1067 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -479, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -477, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1068 - 0, 0, 0, 0, 0, 0, 0, 0, -482, 0, 0, 0, 0, 0, 0, -482, 0, 0, 0, 0, 0, 0, 0, 0, 0, -482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -482, 0, 0, 0, -482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -482, 0, -482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1069 - -500, 0, 0, 0, 0, 0, 0, -500, 0, -500, 0, 0, 0, -500, 0, 0, -500, 0, 0, 0, -500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -500, 0, -500, -500, -500, -500, 0, 0, 0, 0, 0, -500, -500, -500, -500, 0, -500, -500, -500, -500, 0, 0, 0, 0, -500, -500, -500, -500, -500, 0, 0, -500, -500, -500, -500, 0, -500, -500, -500, -500, -500, -500, -500, -500, -500, 0, 0, 0, -500, -500, 0, -500, 0, 0, 0, -500, -500, 0, -500, -500, -500, -500, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -480, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1070 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 388, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -481, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1071 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 389, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -483, 0, 0, 0, 0, 0, 0, -483, 0, 0, 0, 0, 0, 0, 0, 0, 0, -483, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -483, 0, 0, 0, -483, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -483, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -483, 0, -483, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1072 - -344, 0, 0, 0, 0, 0, 0, -344, 0, -344, 0, 0, 0, -344, 0, 0, -344, 0, 0, 0, -344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -344, 0, -344, -344, -344, -344, 0, 0, 0, 0, 0, -344, -344, -344, -344, 0, -344, -344, -344, -344, 0, -344, -344, -344, -344, -344, -344, -344, -344, 0, 0, -344, -344, -344, -344, 0, -344, -344, -344, -344, -344, -344, -344, -344, -344, 0, 0, 0, -344, -344, 0, -344, 0, 0, 0, -344, -344, 0, -344, -344, -344, -344, + -501, 0, 0, 0, 0, 0, 0, -501, 0, -501, 0, 0, 0, -501, 0, 0, -501, 0, 0, 0, -501, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -501, 0, -501, -501, -501, -501, 0, 0, 0, 0, 0, -501, -501, -501, -501, 0, -501, -501, -501, -501, 0, 0, 0, 0, -501, -501, -501, -501, -501, 0, 0, -501, -501, -501, -501, 0, -501, -501, -501, -501, -501, -501, -501, -501, -501, 0, 0, 0, -501, -501, 0, -501, 0, 0, 0, -501, -501, 0, -501, -501, -501, -501, // State 1073 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 390, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 388, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1074 - 0, 0, 0, 0, 0, 0, 0, -826, 0, -826, 0, 0, 0, -826, 0, 0, -826, 0, 0, 0, -826, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -826, 0, -826, -826, -826, -826, 0, 0, 0, 0, 0, -826, -826, -826, -826, 0, -826, -826, -826, -826, 0, 0, 0, 0, -826, -826, -826, -826, -826, 0, 0, -826, -826, -826, -826, 0, -826, -826, -826, -826, -826, -826, -826, -826, -826, 0, 0, 0, -826, -826, 0, -826, 0, 0, 0, -826, -826, 0, -826, -826, -826, -826, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 389, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1075 - 0, 0, 0, 0, 0, 0, 0, -834, 0, -834, 0, 0, 0, -834, 0, 0, -834, 0, 0, 0, -834, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -834, 0, -834, -834, -834, -834, 0, 0, 0, 0, 0, -834, -834, -834, -834, 0, -834, -834, -834, -834, 0, 0, 0, 0, -834, -834, -834, -834, -834, 0, 0, -834, -834, -834, -834, 0, -834, -834, -834, -834, -834, -834, -834, -834, -834, 0, 0, 0, -834, -834, 0, -834, 0, 0, 0, -834, -834, 0, -834, -834, -834, -834, + -344, 0, 0, 0, 0, 0, 0, -344, 0, -344, 0, 0, 0, -344, 0, 0, -344, 0, 0, 0, -344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -344, 0, -344, -344, -344, -344, 0, 0, 0, 0, 0, -344, -344, -344, -344, 0, -344, -344, -344, -344, 0, -344, -344, -344, -344, -344, -344, -344, -344, 0, 0, -344, -344, -344, -344, 0, -344, -344, -344, -344, -344, -344, -344, -344, -344, 0, 0, 0, -344, -344, 0, -344, 0, 0, 0, -344, -344, 0, -344, -344, -344, -344, // State 1076 - 1125, 0, 0, 0, 0, 0, 0, -135, 0, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -135, -135, -135, -135, 0, 0, 0, 0, 0, -135, 0, -135, -135, 0, 0, -135, 0, -135, 0, 0, 0, 0, 0, -135, -135, 0, -135, 0, 0, -135, 0, -135, -135, 0, -135, -135, -135, 0, -135, 0, 0, -135, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, -135, 0, -135, -135, -135, -135, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 390, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1077 - 0, 0, 0, 0, 0, 0, 0, -831, 0, -831, 0, 0, 0, -831, 0, 0, -831, 0, 0, 0, -831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -831, 0, -831, -831, -831, -831, 0, 0, 0, 0, 0, -831, -831, -831, -831, 0, -831, -831, -831, -831, 0, 0, 0, 0, -831, -831, -831, -831, -831, 0, 0, -831, -831, -831, -831, 0, -831, -831, -831, -831, -831, -831, -831, -831, -831, 0, 0, 0, -831, -831, 0, -831, 0, 0, 0, -831, -831, 0, -831, -831, -831, -831, + 0, 0, 0, 0, 0, 0, 0, -827, 0, -827, 0, 0, 0, -827, 0, 0, -827, 0, 0, 0, -827, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -827, 0, -827, -827, -827, -827, 0, 0, 0, 0, 0, -827, -827, -827, -827, 0, -827, -827, -827, -827, 0, 0, 0, 0, -827, -827, -827, -827, -827, 0, 0, -827, -827, -827, -827, 0, -827, -827, -827, -827, -827, -827, -827, -827, -827, 0, 0, 0, -827, -827, 0, -827, 0, 0, 0, -827, -827, 0, -827, -827, -827, -827, // State 1078 - 0, 0, -193, -193, 0, -193, 0, -193, 0, -193, -193, 0, 0, -193, 0, -193, -193, 0, 0, -193, 0, -193, -193, 0, 0, -220, 0, 0, -193, -193, 0, -193, 0, -193, -193, -193, -193, 0, 0, -193, 0, 0, 0, 0, -193, 0, -193, 0, -193, -193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -193, 0, -193, -193, 0, 0, 0, -193, -193, 0, 0, 0, 0, 0, 0, 0, 0, 0, -193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -835, 0, -835, 0, 0, 0, -835, 0, 0, -835, 0, 0, 0, -835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -835, 0, -835, -835, -835, -835, 0, 0, 0, 0, 0, -835, -835, -835, -835, 0, -835, -835, -835, -835, 0, 0, 0, 0, -835, -835, -835, -835, -835, 0, 0, -835, -835, -835, -835, 0, -835, -835, -835, -835, -835, -835, -835, -835, -835, 0, 0, 0, -835, -835, 0, -835, 0, 0, 0, -835, -835, 0, -835, -835, -835, -835, // State 1079 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -931, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1128, 0, 0, 0, 0, 0, 0, -135, 0, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -135, -135, -135, -135, 0, 0, 0, 0, 0, -135, 0, -135, -135, 0, 0, -135, 0, -135, 0, 0, 0, 0, 0, -135, -135, 0, -135, 0, 0, -135, 0, -135, -135, 0, -135, -135, -135, 0, -135, 0, 0, -135, -135, 0, 0, 0, -135, 0, 0, -135, 0, 0, 0, -135, -135, 0, -135, -135, -135, -135, // State 1080 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1126, 0, 0, 0, 0, 0, 0, 0, 0, 0, -688, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -832, 0, -832, 0, 0, 0, -832, 0, 0, -832, 0, 0, 0, -832, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -832, 0, -832, -832, -832, -832, 0, 0, 0, 0, 0, -832, -832, -832, -832, 0, -832, -832, -832, -832, 0, 0, 0, 0, -832, -832, -832, -832, -832, 0, 0, -832, -832, -832, -832, 0, -832, -832, -832, -832, -832, -832, -832, -832, -832, 0, 0, 0, -832, -832, 0, -832, 0, 0, 0, -832, -832, 0, -832, -832, -832, -832, // State 1081 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1128, 0, 0, 0, 0, 0, 0, 0, 0, 0, -679, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -193, -193, 0, -193, 0, -193, 0, -193, -193, 0, 0, -193, 0, -193, -193, 0, 0, -193, 0, -193, -193, 0, 0, -220, 0, 0, -193, -193, 0, -193, 0, -193, -193, -193, -193, 0, 0, -193, 0, 0, 0, 0, -193, 0, -193, 0, -193, -193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -193, 0, -193, -193, 0, 0, 0, -193, -193, 0, 0, 0, 0, 0, 0, 0, 0, 0, -193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1082 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -655, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -934, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1083 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -660, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1129, 0, 0, 0, 0, 0, 0, 0, 0, 0, -689, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1084 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1129, 0, 0, 0, 0, 0, 0, 0, 0, 0, -684, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1131, 0, 0, 0, 0, 0, 0, 0, 0, 0, -680, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1085 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -651, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1086 - -404, 0, 0, 0, 0, 0, 0, -404, 0, -404, 0, 0, 0, -404, 0, 0, -404, 0, 0, 0, -404, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -404, 0, -404, -404, -404, -404, 0, 0, 0, 0, 0, -404, -404, -404, -404, 0, -404, -404, -404, -404, 0, 0, 0, 0, -404, -404, -404, -404, -404, 0, 0, -404, -404, -404, -404, 0, -404, -404, -404, -404, -404, -404, -404, -404, -404, 0, 0, 0, -404, -404, 0, -404, 0, 0, 0, -404, -404, 0, -404, -404, -404, -404, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -661, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1087 - -411, 0, 0, 0, 0, 0, 0, -411, 0, -411, 0, 0, 0, -411, 0, 0, -411, 0, 0, 0, -411, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -411, 0, -411, -411, -411, -411, 0, 0, 0, 0, 0, -411, -411, -411, -411, 0, -411, -411, -411, -411, 0, 0, 0, 0, -411, -411, -411, -411, -411, 0, 0, -411, -411, -411, -411, 0, -411, -411, -411, -411, -411, -411, -411, -411, -411, 0, 0, 0, -411, -411, 0, -411, 0, 0, 0, -411, -411, 0, -411, -411, -411, -411, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1132, 0, 0, 0, 0, 0, 0, 0, 0, 0, -685, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1088 - -401, 0, 0, 0, 0, 0, 0, -401, 0, -401, 0, 0, 0, -401, 0, 0, -401, 0, 0, 0, -401, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -401, 0, -401, -401, -401, -401, 0, 0, 0, 0, 0, -401, -401, -401, -401, 0, -401, -401, -401, -401, 0, 0, 0, 0, -401, -401, -401, -401, -401, 0, 0, -401, -401, -401, -401, 0, -401, -401, -401, -401, -401, -401, -401, -401, -401, 0, 0, 0, -401, -401, 0, -401, 0, 0, 0, -401, -401, 0, -401, -401, -401, -401, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1089 - 0, 0, 0, 0, 0, 0, 0, 0, -608, 0, 0, 0, 0, 0, 0, 1132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -404, 0, 0, 0, 0, 0, 0, -404, 0, -404, 0, 0, 0, -404, 0, 0, -404, 0, 0, 0, -404, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -404, 0, -404, -404, -404, -404, 0, 0, 0, 0, 0, -404, -404, -404, -404, 0, -404, -404, -404, -404, 0, 0, 0, 0, -404, -404, -404, -404, -404, 0, 0, -404, -404, -404, -404, 0, -404, -404, -404, -404, -404, -404, -404, -404, -404, 0, 0, 0, -404, -404, 0, -404, 0, 0, 0, -404, -404, 0, -404, -404, -404, -404, // State 1090 - 0, 0, 0, 0, 0, 0, 0, 0, -599, 0, 0, 0, 0, 0, 0, 1134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -411, 0, 0, 0, 0, 0, 0, -411, 0, -411, 0, 0, 0, -411, 0, 0, -411, 0, 0, 0, -411, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -411, 0, -411, -411, -411, -411, 0, 0, 0, 0, 0, -411, -411, -411, -411, 0, -411, -411, -411, -411, 0, 0, 0, 0, -411, -411, -411, -411, -411, 0, 0, -411, -411, -411, -411, 0, -411, -411, -411, -411, -411, -411, -411, -411, -411, 0, 0, 0, -411, -411, 0, -411, 0, 0, 0, -411, -411, 0, -411, -411, -411, -411, // State 1091 - 0, 0, 0, 0, 0, 0, 0, 0, -575, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -401, 0, 0, 0, 0, 0, 0, -401, 0, -401, 0, 0, 0, -401, 0, 0, -401, 0, 0, 0, -401, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -401, 0, -401, -401, -401, -401, 0, 0, 0, 0, 0, -401, -401, -401, -401, 0, -401, -401, -401, -401, 0, 0, 0, 0, -401, -401, -401, -401, -401, 0, 0, -401, -401, -401, -401, 0, -401, -401, -401, -401, -401, -401, -401, -401, -401, 0, 0, 0, -401, -401, 0, -401, 0, 0, 0, -401, -401, 0, -401, -401, -401, -401, // State 1092 - 0, 0, 0, 0, 0, 0, 0, 0, -631, 0, 0, 0, 0, 0, 0, 1135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -609, 0, 0, 0, 0, 0, 0, 1135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1093 - 0, 0, 0, 0, 0, 0, 0, 0, -627, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -600, 0, 0, 0, 0, 0, 0, 1137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1094 - 0, 0, 0, 0, 0, 0, 0, 0, -621, 0, 0, 0, 0, 0, 0, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -576, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1095 - 0, 0, 0, 0, 0, 0, 0, 0, -634, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -632, 0, 0, 0, 0, 0, 0, 1138, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1096 - -399, 0, 0, 0, 0, 0, 0, -399, 0, -399, 0, 0, 0, -399, 0, 0, -399, 0, 0, 0, -399, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -399, 0, -399, -399, -399, -399, 0, 0, 0, 0, 0, -399, -399, -399, -399, 0, -399, -399, -399, -399, 0, 0, 0, 0, -399, -399, -399, -399, -399, 0, 0, -399, -399, -399, -399, 0, -399, -399, -399, -399, -399, -399, -399, -399, -399, 0, 0, 0, -399, -399, 0, -399, 0, 0, 0, -399, -399, 0, -399, -399, -399, -399, + 0, 0, 0, 0, 0, 0, 0, 0, -628, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1097 - -108, 0, 0, 0, 0, 0, 0, -108, 0, -108, 0, 0, 0, -108, 0, 0, -108, 0, 0, 0, -108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -108, 0, -108, -108, -108, -108, 0, 0, 0, 0, 0, -108, -108, -108, -108, 0, -108, -108, -108, -108, -108, -108, 0, 0, -108, -108, -108, -108, -108, 0, 0, -108, -108, -108, -108, 0, -108, -108, -108, -108, -108, -108, -108, -108, -108, 0, 0, 0, -108, -108, 0, -108, 0, 0, 0, -108, -108, 0, -108, -108, -108, -108, + 0, 0, 0, 0, 0, 0, 0, 0, -622, 0, 0, 0, 0, 0, 0, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1098 - 0, 0, 0, 0, 0, 0, 0, 0, -894, 0, 0, 0, 0, 0, 0, -894, 0, 0, 0, 0, 0, 0, 0, 0, 0, -894, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -894, 0, 0, 0, -894, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -894, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -894, 0, -894, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -635, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1099 - 0, 0, 0, 0, 0, 0, 0, -495, -264, 0, 0, 0, 0, 0, 0, -264, 0, 0, 0, -495, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 395, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -399, 0, 0, 0, 0, 0, 0, -399, 0, -399, 0, 0, 0, -399, 0, 0, -399, 0, 0, 0, -399, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -399, 0, -399, -399, -399, -399, 0, 0, 0, 0, 0, -399, -399, -399, -399, 0, -399, -399, -399, -399, 0, 0, 0, 0, -399, -399, -399, -399, -399, 0, 0, -399, -399, -399, -399, 0, -399, -399, -399, -399, -399, -399, -399, -399, -399, 0, 0, 0, -399, -399, 0, -399, 0, 0, 0, -399, -399, 0, -399, -399, -399, -399, // State 1100 - 0, 0, 0, 0, 0, 0, 0, 0, -538, 0, 0, 0, 0, 0, 0, -538, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -108, 0, 0, 0, 0, 0, 0, -108, 0, -108, 0, 0, 0, -108, 0, 0, -108, 0, 0, 0, -108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -108, 0, -108, -108, -108, -108, 0, 0, 0, 0, 0, -108, -108, -108, -108, 0, -108, -108, -108, -108, -108, -108, 0, 0, -108, -108, -108, -108, -108, 0, 0, -108, -108, -108, -108, 0, -108, -108, -108, -108, -108, -108, -108, -108, -108, 0, 0, 0, -108, -108, 0, -108, 0, 0, 0, -108, -108, 0, -108, -108, -108, -108, // State 1101 - 0, 0, 0, 0, 0, 0, 0, 0, 1139, 0, 0, 0, 0, 0, 0, 396, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -897, 0, 0, 0, 0, 0, 0, -897, 0, 0, 0, 0, 0, 0, 0, 0, 0, -897, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -897, 0, 0, 0, -897, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -897, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -897, 0, -897, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1102 - 0, 0, 0, 0, 0, 0, 0, 0, 1140, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -496, -264, 0, 0, 0, 0, 0, 0, -264, 0, 0, 0, -496, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 395, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1103 - 0, 0, 0, 0, 0, 0, 0, 0, -546, 0, 0, 0, 0, 0, 0, -546, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -539, 0, 0, 0, 0, 0, 0, -539, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1104 - 0, 0, 0, 0, 0, 0, 0, 0, -759, 0, 0, 0, 0, 0, 0, -759, 0, 0, 0, 0, 0, 0, 0, 0, 0, -759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -759, 0, 0, 0, -759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -759, 0, -759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1142, 0, 0, 0, 0, 0, 0, 396, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1105 - 0, 0, 0, 0, 0, 0, 0, -496, -496, 0, 0, 0, 0, 0, 0, -496, 0, 0, 0, -496, 0, 0, 0, 0, 0, -496, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -496, 0, 0, 0, -496, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -496, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -496, 0, -496, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1143, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1106 - 0, 0, 0, 0, 0, 0, 0, -497, -497, 0, 0, 0, 0, 0, 0, -497, 0, 0, 0, -497, 0, 0, 0, 0, 0, -497, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -497, 0, 0, 0, -497, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -497, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -497, 0, -497, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -547, 0, 0, 0, 0, 0, 0, -547, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1107 - 0, 0, 0, 0, 0, 0, 0, 0, -153, 0, 0, 0, 0, 0, 0, -153, 0, 0, 0, 0, 0, 0, 0, 0, 0, -153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -153, 0, 0, 0, -153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -153, 0, -153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -760, 0, 0, 0, 0, 0, 0, -760, 0, 0, 0, 0, 0, 0, 0, 0, 0, -760, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -760, 0, 0, 0, -760, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -760, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -760, 0, -760, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1108 - 0, 0, 0, 0, 0, 0, 0, 0, -172, 0, 0, 0, 0, 0, 0, -172, 0, 0, 0, 0, 0, 0, 0, 0, 0, -172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -497, -497, 0, 0, 0, 0, 0, 0, -497, 0, 0, 0, -497, 0, 0, 0, 0, 0, -497, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -497, 0, 0, 0, -497, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -497, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -497, 0, -497, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1109 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -896, 0, 0, 0, 0, 0, 0, 0, 0, 0, -896, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -896, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -498, -498, 0, 0, 0, 0, 0, 0, -498, 0, 0, 0, -498, 0, 0, 0, 0, 0, -498, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -498, 0, 0, 0, -498, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -498, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -498, 0, -498, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1110 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -490, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -490, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -153, 0, 0, 0, 0, 0, 0, -153, 0, 0, 0, 0, 0, 0, 0, 0, 0, -153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -153, 0, 0, 0, -153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -153, 0, -153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1111 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -429, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -172, 0, 0, 0, 0, 0, 0, -172, 0, 0, 0, 0, 0, 0, 0, 0, 0, -172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1112 - 0, 0, 0, 0, 0, 0, 0, 0, -895, 0, 0, 0, 0, 0, 0, -895, 0, 0, 0, 0, 0, 0, 0, 0, 0, -895, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -895, 0, 0, 0, -895, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -895, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -895, 0, -895, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -899, 0, 0, 0, 0, 0, 0, 0, 0, 0, -899, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -899, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1113 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -897, 0, 0, 0, 0, 0, 0, 0, 0, 0, -897, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -897, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -491, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -491, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1114 - 0, 0, 0, 0, 0, 0, 0, 0, 1142, 0, 0, 0, 0, 0, 0, 1143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -429, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1115 - 0, 0, 0, 0, 0, 0, 0, 0, -778, 0, 0, 0, 0, 0, 0, -778, 0, 0, 0, 0, 0, 0, 0, 0, 0, -778, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -778, 0, 0, 0, -778, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -778, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -778, 0, -778, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -898, 0, 0, 0, 0, 0, 0, -898, 0, 0, 0, 0, 0, 0, 0, 0, 0, -898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -898, 0, 0, 0, -898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -898, 0, -898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1116 - 0, 0, 0, 0, 0, 0, 0, -129, 1144, -129, 0, 0, 0, 0, 0, 0, -129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -129, -129, -129, -129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -129, -129, 0, -129, 0, -129, -129, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -900, 0, 0, 0, 0, 0, 0, 0, 0, 0, -900, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -900, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1117 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1145, 0, 0, 0, 0, 0, 0, 1146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1118 - 0, 0, 0, 0, 0, 0, 0, 0, -786, 0, 0, 0, 0, 0, 0, -786, 0, 0, 0, 0, 0, 0, 0, 0, 0, -786, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -786, 0, 0, 0, -786, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -786, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -786, 0, -786, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -779, 0, 0, 0, 0, 0, 0, -779, 0, 0, 0, 0, 0, 0, 0, 0, 0, -779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -779, 0, 0, 0, -779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -779, 0, -779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1119 - 0, 0, 0, 0, 0, 0, 0, -129, 0, -129, 0, 0, 0, 0, 0, 0, -129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -129, -129, -129, -129, -129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -129, -129, 0, -129, 0, -129, -129, + 0, 0, 0, 0, 0, 0, 0, -129, 1147, -129, 0, 0, 0, 0, 0, 0, -129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -129, -129, -129, -129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -129, -129, 0, -129, 0, -129, -129, // State 1120 - 0, 0, 0, 0, 0, 0, 0, 0, -783, 0, 0, 0, 0, 0, 0, -783, 0, 0, 0, 0, 0, 0, 0, 0, 0, -783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -783, 0, 0, 0, -783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -783, 0, -783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1149, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1121 - 0, 0, 0, 0, 0, 0, 0, 0, -484, 0, 0, 0, 0, 0, 0, -484, 0, 0, 0, 0, 0, 0, 0, 0, 0, -484, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -484, 0, 0, 0, -484, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -484, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -484, 0, -484, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -787, 0, 0, 0, 0, 0, 0, -787, 0, 0, 0, 0, 0, 0, 0, 0, 0, -787, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -787, 0, 0, 0, -787, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -787, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -787, 0, -787, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1122 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -129, 0, -129, 0, 0, 0, 0, 0, 0, -129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -129, -129, -129, -129, -129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -129, -129, 0, -129, 0, -129, -129, // State 1123 - -341, 0, 0, 0, 0, 0, 0, -341, 0, -341, 0, 0, 0, -341, 0, 0, -341, 0, 0, 0, -341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -341, 0, -341, -341, -341, -341, 0, 0, 0, 0, 0, -341, -341, -341, -341, 0, -341, -341, -341, -341, 0, -341, -341, -341, -341, -341, -341, -341, -341, 0, 0, -341, -341, -341, -341, 0, -341, -341, -341, -341, -341, -341, -341, -341, -341, 0, 0, 0, -341, -341, 0, -341, 0, 0, 0, -341, -341, 0, -341, -341, -341, -341, + 0, 0, 0, 0, 0, 0, 0, 0, -784, 0, 0, 0, 0, 0, 0, -784, 0, 0, 0, 0, 0, 0, 0, 0, 0, -784, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -784, 0, 0, 0, -784, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -784, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -784, 0, -784, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1124 - 0, 0, 0, 0, 0, 0, 0, -832, 0, -832, 0, 0, 0, -832, 0, 0, -832, 0, 0, 0, -832, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -832, 0, -832, -832, -832, -832, 0, 0, 0, 0, 0, -832, -832, -832, -832, 0, -832, -832, -832, -832, 0, 0, 0, 0, -832, -832, -832, -832, -832, 0, 0, -832, -832, -832, -832, 0, -832, -832, -832, -832, -832, -832, -832, -832, -832, 0, 0, 0, -832, -832, 0, -832, 0, 0, 0, -832, -832, 0, -832, -832, -832, -832, + 0, 0, 0, 0, 0, 0, 0, 0, -485, 0, 0, 0, 0, 0, 0, -485, 0, 0, 0, 0, 0, 0, 0, 0, 0, -485, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -485, 0, 0, 0, -485, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -485, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -485, 0, -485, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1125 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -661, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1126 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1155, 0, 0, 0, 0, 0, 0, 0, 0, 0, -685, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -341, 0, 0, 0, 0, 0, 0, -341, 0, -341, 0, 0, 0, -341, 0, 0, -341, 0, 0, 0, -341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -341, 0, -341, -341, -341, -341, 0, 0, 0, 0, 0, -341, -341, -341, -341, 0, -341, -341, -341, -341, 0, -341, -341, -341, -341, -341, -341, -341, -341, 0, 0, -341, -341, -341, -341, 0, -341, -341, -341, -341, -341, -341, -341, -341, -341, 0, 0, 0, -341, -341, 0, -341, 0, 0, 0, -341, -341, 0, -341, -341, -341, -341, // State 1127 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -833, 0, -833, 0, 0, 0, -833, 0, 0, -833, 0, 0, 0, -833, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -833, 0, -833, -833, -833, -833, 0, 0, 0, 0, 0, -833, -833, -833, -833, 0, -833, -833, -833, -833, 0, 0, 0, 0, -833, -833, -833, -833, -833, 0, 0, -833, -833, -833, -833, 0, -833, -833, -833, -833, -833, -833, -833, -833, -833, 0, 0, 0, -833, -833, 0, -833, 0, 0, 0, -833, -833, 0, -833, -833, -833, -833, // State 1128 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -657, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -662, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1129 - -403, 0, 0, 0, 0, 0, 0, -403, 0, -403, 0, 0, 0, -403, 0, 0, -403, 0, 0, 0, -403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -403, 0, -403, -403, -403, -403, 0, 0, 0, 0, 0, -403, -403, -403, -403, 0, -403, -403, -403, -403, 0, 0, 0, 0, -403, -403, -403, -403, -403, 0, 0, -403, -403, -403, -403, 0, -403, -403, -403, -403, -403, -403, -403, -403, -403, 0, 0, 0, -403, -403, 0, -403, 0, 0, 0, -403, -403, 0, -403, -403, -403, -403, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1158, 0, 0, 0, 0, 0, 0, 0, 0, 0, -686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1130 - -397, 0, 0, 0, 0, 0, 0, -397, 0, -397, 0, 0, 0, -397, 0, 0, -397, 0, 0, 0, -397, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -397, 0, -397, -397, -397, -397, 0, 0, 0, 0, 0, -397, -397, -397, -397, 0, -397, -397, -397, -397, 0, 0, 0, 0, -397, -397, -397, -397, -397, 0, 0, -397, -397, -397, -397, 0, -397, -397, -397, -397, -397, -397, -397, -397, -397, 0, 0, 0, -397, -397, 0, -397, 0, 0, 0, -397, -397, 0, -397, -397, -397, -397, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -653, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1131 - 0, 0, 0, 0, 0, 0, 0, 0, -581, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -658, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1132 - 0, 0, 0, 0, 0, 0, 0, 0, -605, 0, 0, 0, 0, 0, 0, 1156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -403, 0, 0, 0, 0, 0, 0, -403, 0, -403, 0, 0, 0, -403, 0, 0, -403, 0, 0, 0, -403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -403, 0, -403, -403, -403, -403, 0, 0, 0, 0, 0, -403, -403, -403, -403, 0, -403, -403, -403, -403, 0, 0, 0, 0, -403, -403, -403, -403, -403, 0, 0, -403, -403, -403, -403, 0, -403, -403, -403, -403, -403, -403, -403, -403, -403, 0, 0, 0, -403, -403, 0, -403, 0, 0, 0, -403, -403, 0, -403, -403, -403, -403, // State 1133 - 0, 0, 0, 0, 0, 0, 0, 0, -572, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -397, 0, 0, 0, 0, 0, 0, -397, 0, -397, 0, 0, 0, -397, 0, 0, -397, 0, 0, 0, -397, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -397, 0, -397, -397, -397, -397, 0, 0, 0, 0, 0, -397, -397, -397, -397, 0, -397, -397, -397, -397, 0, 0, 0, 0, -397, -397, -397, -397, -397, 0, 0, -397, -397, -397, -397, 0, -397, -397, -397, -397, -397, -397, -397, -397, -397, 0, 0, 0, -397, -397, 0, -397, 0, 0, 0, -397, -397, 0, -397, -397, -397, -397, // State 1134 - 0, 0, 0, 0, 0, 0, 0, 0, -628, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -582, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1135 - 0, 0, 0, 0, 0, 0, 0, 0, -622, 0, 0, 0, 0, 0, 0, 399, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -606, 0, 0, 0, 0, 0, 0, 1159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1136 - 0, 0, 0, 0, 0, 0, 0, 0, -618, 0, 0, 0, 0, 0, 0, 401, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -573, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1137 - 0, 0, 0, 0, 0, 0, 0, 0, -603, 0, 0, 0, 0, 0, 0, 1161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1138 - 0, 0, 0, 0, 0, 0, 0, 0, -758, 0, 0, 0, 0, 0, 0, -758, 0, 0, 0, 0, 0, 0, 0, 0, 0, -758, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -758, 0, 0, 0, -758, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -758, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -758, 0, -758, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -623, 0, 0, 0, 0, 0, 0, 399, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1139 - 0, 0, 0, 0, 0, 0, 0, 0, -756, 0, 0, 0, 0, 0, 0, -756, 0, 0, 0, 0, 0, 0, 0, 0, 0, -756, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -756, 0, 0, 0, -756, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -756, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -756, 0, -756, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -619, 0, 0, 0, 0, 0, 0, 401, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1140 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -489, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -489, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -604, 0, 0, 0, 0, 0, 0, 1164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1141 - 0, 0, 0, 0, 0, 0, 0, 0, -782, 0, 0, 0, 0, 0, 0, -782, 0, 0, 0, 0, 0, 0, 0, 0, 0, -782, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -782, 0, 0, 0, -782, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -782, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -782, 0, -782, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -759, 0, 0, 0, 0, 0, 0, -759, 0, 0, 0, 0, 0, 0, 0, 0, 0, -759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -759, 0, 0, 0, -759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -759, 0, -759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1142 - 0, 0, 0, 0, 0, 0, 0, -130, 1169, -130, 0, 0, 0, 0, 0, 0, -130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -130, -130, -130, -130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -130, -130, 0, -130, 0, -130, -130, + 0, 0, 0, 0, 0, 0, 0, 0, -757, 0, 0, 0, 0, 0, 0, -757, 0, 0, 0, 0, 0, 0, 0, 0, 0, -757, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -757, 0, 0, 0, -757, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -757, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -757, 0, -757, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1143 - 0, 0, 0, 0, 0, 0, 0, 0, -780, 0, 0, 0, 0, 0, 0, -780, 0, 0, 0, 0, 0, 0, 0, 0, 0, -780, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -780, 0, 0, 0, -780, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -780, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -780, 0, -780, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -490, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -490, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1144 - 0, 0, 0, 0, 0, 0, 0, -130, 0, -130, 0, 0, 0, 0, 0, 0, -130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -130, -130, -130, -130, -130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -130, -130, 0, -130, 0, -130, -130, + 0, 0, 0, 0, 0, 0, 0, 0, -783, 0, 0, 0, 0, 0, 0, -783, 0, 0, 0, 0, 0, 0, 0, 0, 0, -783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -783, 0, 0, 0, -783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -783, 0, -783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1145 - 0, 0, 0, 0, 0, 0, 0, 0, -785, 0, 0, 0, 0, 0, 0, -785, 0, 0, 0, 0, 0, 0, 0, 0, 0, -785, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -785, 0, 0, 0, -785, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -785, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -785, 0, -785, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -130, 1172, -130, 0, 0, 0, 0, 0, 0, -130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -130, -130, -130, -130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -130, -130, 0, -130, 0, -130, -130, // State 1146 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -494, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -494, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -781, 0, 0, 0, 0, 0, 0, -781, 0, 0, 0, 0, 0, 0, 0, 0, 0, -781, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -781, 0, 0, 0, -781, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -781, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -781, 0, -781, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1147 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -541, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -541, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -130, 0, -130, 0, 0, 0, 0, 0, 0, -130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -130, -130, -130, -130, -130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -130, -130, 0, -130, 0, -130, -130, // State 1148 - 0, 0, 0, 0, 0, 0, 0, 0, -483, 0, 0, 0, 0, 0, 0, -483, 0, 0, 0, 0, 0, 0, 0, 0, 0, -483, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -483, 0, 0, 0, -483, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -483, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -483, 0, -483, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -786, 0, 0, 0, 0, 0, 0, -786, 0, 0, 0, 0, 0, 0, 0, 0, 0, -786, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -786, 0, 0, 0, -786, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -786, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -786, 0, -786, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1149 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -495, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -495, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1150 - 0, 0, 0, 0, 0, 0, 0, 0, -486, 0, 0, 0, 0, 0, 0, -486, 0, 0, 0, 0, 0, 0, 0, 0, 0, -486, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -486, 0, 0, 0, -486, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -486, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -486, 0, -486, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -542, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -542, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1151 - -885, 0, 0, 0, 0, 0, 0, -885, 0, -885, 0, 0, 0, -885, 0, 0, -885, 0, 0, 0, -885, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -885, 0, -885, -885, -885, -885, 0, 0, 0, 0, 0, -885, -885, -885, -885, 0, -885, -885, -885, -885, 0, 0, 0, 0, -885, -885, -885, -885, -885, 0, 0, -885, -885, -885, -885, 0, -885, -885, -885, -885, -885, -885, -885, -885, -885, 0, 0, 0, -885, -885, 0, -885, 0, 0, 0, -885, -885, 0, -885, -885, -885, -885, + 0, 0, 0, 0, 0, 0, 0, 0, -484, 0, 0, 0, 0, 0, 0, -484, 0, 0, 0, 0, 0, 0, 0, 0, 0, -484, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -484, 0, 0, 0, -484, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -484, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -484, 0, -484, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1152 - -889, 0, 0, 0, 0, 0, 0, -889, 0, -889, 0, 0, 0, -889, 0, 0, -889, 0, 0, 0, -889, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -889, 0, -889, -889, -889, -889, 0, 0, 0, 0, 0, -889, -889, -889, -889, 0, -889, -889, -889, -889, 0, 0, 0, 0, -889, -889, -889, -889, -889, 0, 0, -889, -889, -889, -889, 0, -889, -889, -889, -889, -889, -889, -889, -889, -889, 0, 0, 0, -889, -889, 0, -889, 0, 0, 0, -889, -889, 0, -889, -889, -889, -889, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1153 - -345, 0, 0, 0, 0, 0, 0, -345, 0, -345, 0, 0, 0, -345, 0, 0, -345, 0, 0, 0, -345, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -345, 0, -345, -345, -345, -345, 0, 0, 0, 0, 0, -345, -345, -345, -345, 0, -345, -345, -345, -345, 0, -345, -345, -345, -345, -345, -345, -345, -345, 0, 0, -345, -345, -345, -345, 0, -345, -345, -345, -345, -345, -345, -345, -345, -345, 0, 0, 0, -345, -345, 0, -345, 0, 0, 0, -345, -345, 0, -345, -345, -345, -345, + 0, 0, 0, 0, 0, 0, 0, 0, -487, 0, 0, 0, 0, 0, 0, -487, 0, 0, 0, 0, 0, 0, 0, 0, 0, -487, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -487, 0, 0, 0, -487, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -487, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -487, 0, -487, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1154 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -658, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -884, 0, 0, 0, 0, 0, 0, -884, 0, -884, 0, 0, 0, -884, 0, 0, -884, 0, 0, 0, -884, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -884, 0, -884, -884, -884, -884, 0, 0, 0, 0, 0, -884, -884, -884, -884, 0, -884, -884, -884, -884, 0, 0, 0, 0, -884, -884, -884, -884, -884, 0, 0, -884, -884, -884, -884, 0, -884, -884, -884, -884, -884, -884, -884, -884, -884, 0, 0, 0, -884, -884, 0, -884, 0, 0, 0, -884, -884, 0, -884, -884, -884, -884, // State 1155 - 0, 0, 0, 0, 0, 0, 0, 0, -578, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -888, 0, 0, 0, 0, 0, 0, -888, 0, -888, 0, 0, 0, -888, 0, 0, -888, 0, 0, 0, -888, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -888, 0, -888, -888, -888, -888, 0, 0, 0, 0, 0, -888, -888, -888, -888, 0, -888, -888, -888, -888, 0, 0, 0, 0, -888, -888, -888, -888, -888, 0, 0, -888, -888, -888, -888, 0, -888, -888, -888, -888, -888, -888, -888, -888, -888, 0, 0, 0, -888, -888, 0, -888, 0, 0, 0, -888, -888, 0, -888, -888, -888, -888, // State 1156 - 0, 0, 0, 0, 0, 0, 0, 0, -619, 0, 0, 0, 0, 0, 0, 402, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -345, 0, 0, 0, 0, 0, 0, -345, 0, -345, 0, 0, 0, -345, 0, 0, -345, 0, 0, 0, -345, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -345, 0, -345, -345, -345, -345, 0, 0, 0, 0, 0, -345, -345, -345, -345, 0, -345, -345, -345, -345, 0, -345, -345, -345, -345, -345, -345, -345, -345, 0, 0, -345, -345, -345, -345, 0, -345, -345, -345, -345, -345, -345, -345, -345, -345, 0, 0, 0, -345, -345, 0, -345, 0, 0, 0, -345, -345, 0, -345, -345, -345, -345, // State 1157 - 0, 0, 0, 0, 0, 0, 0, 0, -604, 0, 0, 0, 0, 0, 0, 1174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -659, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1158 - 0, 0, 0, 0, 0, 0, 0, 0, -609, 0, 0, 0, 0, 0, 0, 1175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -579, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1159 - 0, 0, 0, 0, 0, 0, 0, 0, -600, 0, 0, 0, 0, 0, 0, 1177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -620, 0, 0, 0, 0, 0, 0, 402, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1160 - 0, 0, 0, 0, 0, 0, 0, 0, -576, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -605, 0, 0, 0, 0, 0, 0, 1177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1161 - 0, 0, 0, 0, 0, 0, 0, 0, -493, 0, 0, 0, 0, 0, 0, -493, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -610, 0, 0, 0, 0, 0, 0, 1178, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1162 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 395, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -601, 0, 0, 0, 0, 0, 0, 1180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1163 - 0, 0, 0, 0, 0, 0, 0, 0, -539, 0, 0, 0, 0, 0, 0, -539, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -577, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1164 - 0, 0, 0, 0, 0, 0, 0, 0, -757, 0, 0, 0, 0, 0, 0, -757, 0, 0, 0, 0, 0, 0, 0, 0, 0, -757, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -757, 0, 0, 0, -757, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -757, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -757, 0, -757, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -494, 0, 0, 0, 0, 0, 0, -494, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1165 - 0, 0, 0, 0, 0, 0, 0, 0, 1178, 0, 0, 0, 0, 0, 0, 403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 395, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1166 - 0, 0, 0, 0, 0, 0, 0, 0, -547, 0, 0, 0, 0, 0, 0, -547, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -540, 0, 0, 0, 0, 0, 0, -540, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1167 - 0, 0, 0, 0, 0, 0, 0, 0, -755, 0, 0, 0, 0, 0, 0, -755, 0, 0, 0, 0, 0, 0, 0, 0, 0, -755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -755, 0, 0, 0, -755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -755, 0, -755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -758, 0, 0, 0, 0, 0, 0, -758, 0, 0, 0, 0, 0, 0, 0, 0, 0, -758, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -758, 0, 0, 0, -758, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -758, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -758, 0, -758, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1168 - 0, 0, 0, 0, 0, 0, 0, 0, -781, 0, 0, 0, 0, 0, 0, -781, 0, 0, 0, 0, 0, 0, 0, 0, 0, -781, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -781, 0, 0, 0, -781, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -781, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -781, 0, -781, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1181, 0, 0, 0, 0, 0, 0, 403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1169 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -548, 0, 0, 0, 0, 0, 0, -548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1170 - 0, 0, 0, 0, 0, 0, 0, 0, -485, 0, 0, 0, 0, 0, 0, -485, 0, 0, 0, 0, 0, 0, 0, 0, 0, -485, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -485, 0, 0, 0, -485, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -485, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -485, 0, -485, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -756, 0, 0, 0, 0, 0, 0, -756, 0, 0, 0, 0, 0, 0, 0, 0, 0, -756, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -756, 0, 0, 0, -756, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -756, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -756, 0, -756, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1171 - 0, 0, 0, 0, 0, 0, 0, 0, -610, 0, 0, 0, 0, 0, 0, 1181, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -782, 0, 0, 0, 0, 0, 0, -782, 0, 0, 0, 0, 0, 0, 0, 0, 0, -782, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -782, 0, 0, 0, -782, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -782, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -782, 0, -782, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1172 - 0, 0, 0, 0, 0, 0, 0, 0, -601, 0, 0, 0, 0, 0, 0, 1183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1173 - 0, 0, 0, 0, 0, 0, 0, 0, -577, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -486, 0, 0, 0, 0, 0, 0, -486, 0, 0, 0, 0, 0, 0, 0, 0, 0, -486, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -486, 0, 0, 0, -486, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -486, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -486, 0, -486, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1174 - 0, 0, 0, 0, 0, 0, 0, 0, -582, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -611, 0, 0, 0, 0, 0, 0, 1184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1175 - 0, 0, 0, 0, 0, 0, 0, 0, -606, 0, 0, 0, 0, 0, 0, 1184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -602, 0, 0, 0, 0, 0, 0, 1186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1176 - 0, 0, 0, 0, 0, 0, 0, 0, -573, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -578, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1177 - 0, 0, 0, 0, 0, 0, 0, 0, -754, 0, 0, 0, 0, 0, 0, -754, 0, 0, 0, 0, 0, 0, 0, 0, 0, -754, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -754, 0, 0, 0, -754, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -754, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -754, 0, -754, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -583, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1178 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -607, 0, 0, 0, 0, 0, 0, 1187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1179 - 0, 0, 0, 0, 0, 0, 0, 0, -488, 0, 0, 0, 0, 0, 0, -488, 0, 0, 0, 0, 0, 0, 0, 0, 0, -488, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -488, 0, 0, 0, -488, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -488, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -488, 0, -488, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -574, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1180 - 0, 0, 0, 0, 0, 0, 0, 0, -583, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -755, 0, 0, 0, 0, 0, 0, -755, 0, 0, 0, 0, 0, 0, 0, 0, 0, -755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -755, 0, 0, 0, -755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -755, 0, -755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1181 - 0, 0, 0, 0, 0, 0, 0, 0, -607, 0, 0, 0, 0, 0, 0, 1187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1182 - 0, 0, 0, 0, 0, 0, 0, 0, -574, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -489, 0, 0, 0, 0, 0, 0, -489, 0, 0, 0, 0, 0, 0, 0, 0, 0, -489, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -489, 0, 0, 0, -489, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -489, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -489, 0, -489, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1183 - 0, 0, 0, 0, 0, 0, 0, 0, -579, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -584, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1184 - 0, 0, 0, 0, 0, 0, 0, 0, -753, 0, 0, 0, 0, 0, 0, -753, 0, 0, 0, 0, 0, 0, 0, 0, 0, -753, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -753, 0, 0, 0, -753, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -753, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -753, 0, -753, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -608, 0, 0, 0, 0, 0, 0, 1190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1185 - 0, 0, 0, 0, 0, 0, 0, 0, -487, 0, 0, 0, 0, 0, 0, -487, 0, 0, 0, 0, 0, 0, 0, 0, 0, -487, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -487, 0, 0, 0, -487, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -487, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -487, 0, -487, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -575, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // State 1186 0, 0, 0, 0, 0, 0, 0, 0, -580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 1187 + 0, 0, 0, 0, 0, 0, 0, 0, -754, 0, 0, 0, 0, 0, 0, -754, 0, 0, 0, 0, 0, 0, 0, 0, 0, -754, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -754, 0, 0, 0, -754, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -754, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -754, 0, -754, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 1188 + 0, 0, 0, 0, 0, 0, 0, 0, -488, 0, 0, 0, 0, 0, 0, -488, 0, 0, 0, 0, 0, 0, 0, 0, 0, -488, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -488, 0, 0, 0, -488, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -488, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -488, 0, -488, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 1189 + 0, 0, 0, 0, 0, 0, 0, 0, -581, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; fn __action(state: i16, integer: usize) -> i16 { __ACTION[(state as usize) * 101 + integer] @@ -2535,27 +2541,27 @@ mod __parse__Top { // State 1 0, // State 2 - -768, + -769, // State 3 0, // State 4 0, // State 5 - -790, + -791, // State 6 -248, // State 7 -304, // State 8 - -883, + -882, // State 9 -155, // State 10 - -183, + -836, // State 11 -169, // State 12 - 0, + -837, // State 13 0, // State 14 @@ -2573,9 +2579,9 @@ mod __parse__Top { // State 20 0, // State 21 - -882, - // State 22 0, + // State 22 + -881, // State 23 0, // State 24 @@ -2587,15 +2593,15 @@ mod __parse__Top { // State 27 0, // State 28 - -303, - // State 29 0, + // State 29 + -303, // State 30 0, // State 31 - -426, - // State 32 0, + // State 32 + -426, // State 33 0, // State 34 @@ -2613,9 +2619,9 @@ mod __parse__Top { // State 40 0, // State 41 - -247, - // State 42 0, + // State 42 + -247, // State 43 0, // State 44 @@ -2673,11 +2679,11 @@ mod __parse__Top { // State 70 0, // State 71 - -154, + 0, // State 72 - -168, + -154, // State 73 - 0, + -168, // State 74 0, // State 75 @@ -2689,9 +2695,9 @@ mod __parse__Top { // State 78 0, // State 79 - -789, - // State 80 0, + // State 80 + -790, // State 81 0, // State 82 @@ -2973,9 +2979,9 @@ mod __parse__Top { // State 220 -432, // State 221 - -888, + -887, // State 222 - -892, + -891, // State 223 0, // State 224 @@ -3337,25 +3343,25 @@ mod __parse__Top { // State 402 0, // State 403 - -949, + -952, // State 404 - -943, + -946, // State 405 - -559, + -560, // State 406 -239, // State 407 - -765, + -766, // State 408 - -515, + -516, // State 409 - -839, + -840, // State 410 - -861, + -860, // State 411 -185, // State 412 - -866, + -865, // State 413 -159, // State 414 @@ -3363,19 +3369,19 @@ mod __parse__Top { // State 415 -427, // State 416 - -865, + -864, // State 417 -388, // State 418 - -878, + -877, // State 419 - -838, + -183, // State 420 - -840, + -839, // State 421 - -877, + -876, // State 422 - -550, + -551, // State 423 -349, // State 424 @@ -3393,17 +3399,17 @@ mod __parse__Top { // State 430 0, // State 431 - -520, + -521, // State 432 - -519, + -520, // State 433 - -518, + -519, // State 434 -430, // State 435 - -835, + -838, // State 436 - -558, + -559, // State 437 -158, // State 438 @@ -3433,7 +3439,7 @@ mod __parse__Top { // State 450 0, // State 451 - -884, + -883, // State 452 -90, // State 453 @@ -3443,7 +3449,7 @@ mod __parse__Top { // State 455 0, // State 456 - -841, + -895, // State 457 0, // State 458 @@ -3455,9 +3461,9 @@ mod __parse__Top { // State 461 0, // State 462 - -387, + -896, // State 463 - 0, + -387, // State 464 0, // State 465 @@ -3471,11 +3477,11 @@ mod __parse__Top { // State 469 0, // State 470 - -199, + 0, // State 471 - -816, + -199, // State 472 - 0, + -817, // State 473 0, // State 474 @@ -3487,9 +3493,9 @@ mod __parse__Top { // State 477 0, // State 478 - -187, - // State 479 0, + // State 479 + -187, // State 480 0, // State 481 @@ -3501,9 +3507,9 @@ mod __parse__Top { // State 484 0, // State 485 - -514, - // State 486 0, + // State 486 + -515, // State 487 0, // State 488 @@ -3517,23 +3523,23 @@ mod __parse__Top { // State 492 0, // State 493 - -204, - // State 494 0, + // State 494 + -204, // State 495 0, // State 496 - -366, - // State 497 0, + // State 497 + -366, // State 498 0, // State 499 - -314, + 0, // State 500 - -769, + -314, // State 501 - 0, + -770, // State 502 0, // State 503 @@ -3541,23 +3547,23 @@ mod __parse__Top { // State 504 0, // State 505 - -310, + 0, // State 506 - -313, + -310, // State 507 - 0, + -313, // State 508 - -308, - // State 509 0, + // State 509 + -308, // State 510 0, // State 511 0, // State 512 - -307, - // State 513 0, + // State 513 + -307, // State 514 0, // State 515 @@ -3567,19 +3573,19 @@ mod __parse__Top { // State 517 0, // State 518 - -311, - // State 519 0, + // State 519 + -311, // State 520 - -309, + 0, // State 521 - -312, + -309, // State 522 - 0, + -312, // State 523 - -774, - // State 524 0, + // State 524 + -775, // State 525 0, // State 526 @@ -3599,11 +3605,11 @@ mod __parse__Top { // State 533 0, // State 534 - -163, + 0, // State 535 - -242, + -163, // State 536 - 0, + -242, // State 537 0, // State 538 @@ -3613,27 +3619,27 @@ mod __parse__Top { // State 540 0, // State 541 - -764, + 0, // State 542 - -141, + -765, // State 543 - 0, + -141, // State 544 0, // State 545 - -348, + 0, // State 546 - -91, + -348, // State 547 - -551, + -91, // State 548 - 0, + -552, // State 549 - -860, + 0, // State 550 - -942, + -859, // State 551 - 0, + -945, // State 552 0, // State 553 @@ -3641,19 +3647,19 @@ mod __parse__Top { // State 554 0, // State 555 - -196, + 0, // State 556 - -190, + -196, // State 557 - -200, + -190, // State 558 - 0, + -200, // State 559 0, // State 560 - -186, - // State 561 0, + // State 561 + -186, // State 562 0, // State 563 @@ -3663,23 +3669,23 @@ mod __parse__Top { // State 565 0, // State 566 - -464, - // State 567 0, + // State 567 + -464, // State 568 - -203, - // State 569 0, + // State 569 + -203, // State 570 - -206, - // State 571 0, + // State 571 + -206, // State 572 0, // State 573 - -367, - // State 574 0, + // State 574 + -367, // State 575 0, // State 576 @@ -3721,9 +3727,9 @@ mod __parse__Top { // State 594 0, // State 595 - -772, - // State 596 0, + // State 596 + -773, // State 597 0, // State 598 @@ -3843,75 +3849,75 @@ mod __parse__Top { // State 655 0, // State 656 - -165, + 0, // State 657 - -162, - // State 658 0, + // State 658 + -165, // State 659 - 0, + -162, // State 660 0, // State 661 0, // State 662 - -241, + 0, // State 663 0, // State 664 - -142, + -241, // State 665 0, // State 666 - -201, + -142, // State 667 0, // State 668 - 0, + -201, // State 669 - -198, + 0, // State 670 0, // State 671 - -192, + -198, // State 672 0, // State 673 - 0, + -192, // State 674 - -189, + 0, // State 675 - -202, - // State 676 0, + // State 676 + -189, // State 677 - 0, + -202, // State 678 - -188, + 0, // State 679 0, // State 680 - 0, + -188, // State 681 - -462, + 0, // State 682 0, // State 683 - 0, + -462, // State 684 0, // State 685 0, // State 686 - -463, + 0, // State 687 - -205, + 0, // State 688 - -207, + -463, // State 689 - 0, + -205, // State 690 - 0, + -207, // State 691 0, // State 692 @@ -3923,11 +3929,11 @@ mod __parse__Top { // State 695 0, // State 696 - -773, + 0, // State 697 0, // State 698 - 0, + -774, // State 699 0, // State 700 @@ -3939,11 +3945,11 @@ mod __parse__Top { // State 703 0, // State 704 - -770, + 0, // State 705 0, // State 706 - 0, + -771, // State 707 0, // State 708 @@ -3997,11 +4003,11 @@ mod __parse__Top { // State 732 0, // State 733 - -164, + 0, // State 734 0, // State 735 - 0, + -164, // State 736 0, // State 737 @@ -4013,29 +4019,29 @@ mod __parse__Top { // State 740 0, // State 741 - -864, + 0, // State 742 0, // State 743 - 0, + -863, // State 744 - -194, + 0, // State 745 0, // State 746 - -195, + -194, // State 747 0, // State 748 - 0, + -195, // State 749 0, // State 750 - -461, + 0, // State 751 0, // State 752 - 0, + -461, // State 753 0, // State 754 @@ -4055,11 +4061,11 @@ mod __parse__Top { // State 761 0, // State 762 - -771, + 0, // State 763 0, // State 764 - 0, + -772, // State 765 0, // State 766 @@ -4069,11 +4075,11 @@ mod __parse__Top { // State 768 0, // State 769 - -270, + 0, // State 770 0, // State 771 - 0, + -270, // State 772 0, // State 773 @@ -4129,23 +4135,23 @@ mod __parse__Top { // State 798 0, // State 799 - -857, + 0, // State 800 0, // State 801 - -342, + -856, // State 802 - -346, - // State 803 0, + // State 803 + -342, // State 804 - 0, + -346, // State 805 - -921, + 0, // State 806 0, // State 807 - 0, + -924, // State 808 0, // State 809 @@ -4161,11 +4167,11 @@ mod __parse__Top { // State 814 0, // State 815 - -941, + 0, // State 816 0, // State 817 - 0, + -944, // State 818 0, // State 819 @@ -4195,13 +4201,13 @@ mod __parse__Top { // State 831 0, // State 832 - -197, + 0, // State 833 - -191, - // State 834 0, + // State 834 + -197, // State 835 - 0, + -191, // State 836 0, // State 837 @@ -4223,33 +4229,33 @@ mod __parse__Top { // State 845 0, // State 846 - -272, + 0, // State 847 0, // State 848 - 0, + -272, // State 849 0, // State 850 - -940, + 0, // State 851 - -266, + 0, // State 852 - -269, + -943, // State 853 - 0, + -266, // State 854 - 0, + -269, // State 855 0, // State 856 0, // State 857 - -414, + 0, // State 858 0, // State 859 - 0, + -414, // State 860 0, // State 861 @@ -4263,31 +4269,31 @@ mod __parse__Top { // State 865 0, // State 866 - -434, + 0, // State 867 0, // State 868 - 0, + -434, // State 869 0, // State 870 - -858, + 0, // State 871 0, // State 872 - -855, + -857, // State 873 - -343, - // State 874 0, + // State 874 + -854, // State 875 - 0, + -343, // State 876 - -347, + 0, // State 877 0, // State 878 - 0, + -347, // State 879 0, // State 880 @@ -4329,11 +4335,11 @@ mod __parse__Top { // State 898 0, // State 899 - -193, + 0, // State 900 0, // State 901 - 0, + -193, // State 902 0, // State 903 @@ -4349,33 +4355,33 @@ mod __parse__Top { // State 908 0, // State 909 - -268, + 0, // State 910 - -271, - // State 911 0, + // State 911 + -268, // State 912 - -416, + -271, // State 913 0, // State 914 - -406, + -416, // State 915 - -265, - // State 916 0, + // State 916 + -406, // State 917 - 0, + -265, // State 918 0, // State 919 0, // State 920 - -413, + 0, // State 921 0, // State 922 - 0, + -413, // State 923 0, // State 924 @@ -4387,11 +4393,11 @@ mod __parse__Top { // State 927 0, // State 928 - -400, + 0, // State 929 0, // State 930 - 0, + -400, // State 931 0, // State 932 @@ -4403,17 +4409,17 @@ mod __parse__Top { // State 935 0, // State 936 - -856, + 0, // State 937 0, // State 938 - -340, + -855, // State 939 - -893, - // State 940 0, + // State 940 + -340, // State 941 - 0, + -892, // State 942 0, // State 943 @@ -4421,11 +4427,11 @@ mod __parse__Top { // State 944 0, // State 945 - -859, + 0, // State 946 0, // State 947 - 0, + -858, // State 948 0, // State 949 @@ -4459,25 +4465,25 @@ mod __parse__Top { // State 963 0, // State 964 - -408, + 0, // State 965 - -267, - // State 966 0, + // State 966 + -408, // State 967 - -415, + -267, // State 968 0, // State 969 - -405, + -415, // State 970 - -398, + 0, // State 971 - -410, + -405, // State 972 - 0, + -398, // State 973 - 0, + -410, // State 974 0, // State 975 @@ -4499,15 +4505,15 @@ mod __parse__Top { // State 983 0, // State 984 - -431, + 0, // State 985 0, // State 986 - -498, + -431, // State 987 0, // State 988 - 0, + -499, // State 989 0, // State 990 @@ -4547,19 +4553,19 @@ mod __parse__Top { // State 1007 0, // State 1008 - -501, + 0, // State 1009 - -886, + -502, // State 1010 - -887, + -885, // State 1011 - -890, + -886, // State 1012 - -891, + -889, // State 1013 - -339, + -890, // State 1014 - 0, + -339, // State 1015 0, // State 1016 @@ -4573,9 +4579,9 @@ mod __parse__Top { // State 1020 0, // State 1021 - -920, - // State 1022 0, + // State 1022 + -923, // State 1023 0, // State 1024 @@ -4597,17 +4603,17 @@ mod __parse__Top { // State 1032 0, // State 1033 - -407, + 0, // State 1034 - -412, + -407, // State 1035 - -402, + -412, // State 1036 - 0, + -402, // State 1037 - -409, - // State 1038 0, + // State 1038 + -409, // State 1039 0, // State 1040 @@ -4621,13 +4627,13 @@ mod __parse__Top { // State 1044 0, // State 1045 - -433, + 0, // State 1046 - -107, + -433, // State 1047 - -499, + -107, // State 1048 - 0, + -500, // State 1049 0, // State 1050 @@ -4669,19 +4675,19 @@ mod __parse__Top { // State 1068 0, // State 1069 - -500, + 0, // State 1070 0, // State 1071 0, // State 1072 - -344, + -501, // State 1073 0, // State 1074 0, // State 1075 - 0, + -344, // State 1076 0, // State 1077 @@ -4703,17 +4709,17 @@ mod __parse__Top { // State 1085 0, // State 1086 - -404, + 0, // State 1087 - -411, + 0, // State 1088 - -401, - // State 1089 0, + // State 1089 + -404, // State 1090 - 0, + -411, // State 1091 - 0, + -401, // State 1092 0, // State 1093 @@ -4723,15 +4729,15 @@ mod __parse__Top { // State 1095 0, // State 1096 - -399, + 0, // State 1097 - -108, + 0, // State 1098 0, // State 1099 - 0, + -399, // State 1100 - 0, + -108, // State 1101 0, // State 1102 @@ -4777,27 +4783,27 @@ mod __parse__Top { // State 1122 0, // State 1123 - -341, + 0, // State 1124 0, // State 1125 0, // State 1126 - 0, + -341, // State 1127 0, // State 1128 0, // State 1129 - -403, + 0, // State 1130 - -397, + 0, // State 1131 0, // State 1132 - 0, + -403, // State 1133 - 0, + -397, // State 1134 0, // State 1135 @@ -4833,17 +4839,17 @@ mod __parse__Top { // State 1150 0, // State 1151 - -885, + 0, // State 1152 - -889, + 0, // State 1153 - -345, - // State 1154 0, + // State 1154 + -884, // State 1155 - 0, + -888, // State 1156 - 0, + -345, // State 1157 0, // State 1158 @@ -4904,609 +4910,615 @@ mod __parse__Top { 0, // State 1186 0, + // State 1187 + 0, + // State 1188 + 0, + // State 1189 + 0, ]; fn __goto(state: i16, nt: usize) -> i16 { match nt { 10 => match state { - 255 => 925, - 291 => 973, - 292 => 974, - 325 => 1038, - 357 => 1094, - 381 => 1135, - 382 => 1136, - 390 => 1156, - _ => 860, + 255 => 927, + 291 => 975, + 292 => 976, + 325 => 1039, + 358 => 1097, + 381 => 1138, + 382 => 1139, + 390 => 1159, + _ => 862, }, 13 => match state { - 90 => 683, - 137 => 748, - 138 => 749, - 197 => 834, - 239 => 905, - 279 => 960, - 280 => 961, - 316 => 1027, - _ => 563, + 91 => 685, + 137 => 750, + 138 => 751, + 197 => 836, + 239 => 907, + 279 => 962, + 280 => 963, + 316 => 1028, + _ => 564, }, 22 => match state { - 136 => 745, - 187 => 818, - 272 => 948, - _ => 554, + 136 => 747, + 187 => 820, + 272 => 950, + _ => 555, }, 25 => match state { - 188 => 821, - 273 => 950, - _ => 722, + 188 => 823, + 273 => 952, + _ => 724, }, - 29 => 712, - 35 => 579, + 29 => 714, + 35 => 580, 38 => 451, - 49 => 866, + 49 => 868, 53 => match state { - 70 | 105 => 112, + 71 | 106 => 113, _ => 3, }, - 56 => 73, + 56 => 74, 58 => match state { - 70 | 105 => 113, + 71 | 106 => 114, _ => 4, }, 63 => match state { - 341 => 372, - _ => 371, + 342 => 373, + _ => 372, }, 66 => match state { - 21 => 50, + 22 => 51, 224 => 268, 269 => 311, _ => 168, }, 71 => match state { - 116 => 177, - _ => 28, + 117 => 177, + _ => 29, }, 78 => match state { - 114 => 173, - 335 | 373 => 364, - _ => 23, + 115 => 173, + 335 | 374 => 365, + _ => 24, }, 79 => match state { - 342 | 386 => 1058, - _ => 987, + 343 | 386 => 1060, + _ => 989, }, 80 => match state { - 35 => 550, - 70 | 105 => 624, - 185 => 816, + 36 => 551, + 71 | 106 => 625, + 185 => 818, _ => 404, }, - 81 => 625, + 81 => 626, 82 => match state { 3 => 436, - 112 => 718, + 113 => 720, _ => 405, }, - 83 => 626, + 83 => 627, 84 => match state { - 106 => 708, - 115 => 720, - 146 => 763, - 151 => 768, - 204 => 845, + 107 => 710, + 116 => 722, + 146 => 765, + 151 => 770, + 204 => 847, _ => 441, }, 86 => match state { - 33 => 79, - 70 | 105 => 114, + 34 => 80, + 71 | 106 => 115, 180 => 228, _ => 5, }, - 87 => 627, - 88 => 988, - 89 => 498, + 87 => 628, + 88 => 990, + 89 => 499, 90 => match state { - 99 => 699, - 148 => 765, - _ => 581, + 100 => 701, + 148 => 767, + _ => 582, }, - 92 => 99, + 92 => 100, 94 => 406, - 95 => 628, + 95 => 629, 96 => match state { - 16 => 41, - 70 | 105 => 115, + 17 => 42, + 71 | 106 => 116, 124 => 191, _ => 6, }, - 97 => 629, + 97 => 630, 98 => match state { - 70 | 105 => 630, + 71 | 106 => 631, _ => 407, }, - 99 => 631, - 100 => 100, - 101 => 989, - 102 => 499, - 103 => 990, + 99 => 632, + 100 => 101, + 101 => 991, + 102 => 500, + 103 => 992, 104 => match state { - 360 => 1098, - 369 => 1112, - _ => 991, + 361 => 1101, + 370 => 1115, + _ => 993, }, 107 => match state { - 40 => 561, - 45 => 567, - 46 => 569, - 74 => 659, - 186 => 817, - 190 => 826, - 192 => 827, - 193 => 829, - _ => 551, + 41 => 562, + 46 => 568, + 47 => 570, + 75 => 661, + 186 => 819, + 190 => 828, + 192 => 829, + 193 => 831, + _ => 552, }, 109 => match state { - 28 | 177 => 78, - _ => 29, + 29 | 177 => 79, + _ => 30, }, 110 => 408, - 111 => 632, + 111 => 633, 112 => match state { - 224 => 881, - 269 => 943, - _ => 500, + 224 => 883, + 269 => 945, + _ => 501, }, 113 => match state { - 276 | 315 => 953, - _ => 898, + 276 | 315 => 955, + _ => 900, }, 115 => match state { 275 => 315, _ => 276, }, 116 => match state { - 51 => 577, - _ => 501, + 52 => 578, + _ => 502, }, - 118 => 51, - 119 => 502, + 118 => 52, + 119 => 503, 120 => match state { - 93 => 689, - _ => 486, + 94 => 691, + _ => 487, }, 121 => match state { 126 => 192, - 93 => 690, - _ => 45, + 94 => 692, + _ => 46, }, 122 => match state { - 126 => 730, - _ => 487, + 126 => 732, + _ => 488, }, 124 => match state { - 63 => 615, - 108 => 710, - 164 => 790, - _ => 607, + 64 => 616, + 109 => 712, + 164 => 792, + _ => 608, }, - 125 => 862, + 125 => 864, 127 => match state { - 221 => 873, - _ => 801, + 221 => 875, + _ => 803, }, 128 => 221, 129 => match state { - 222 => 876, - _ => 802, + 222 => 878, + _ => 804, }, 130 => 222, 131 => match state { - 21 | 50 | 110 | 152 | 162 | 168 | 171 | 184 | 205 | 209..=211 | 215 | 224 | 241..=242 | 244 | 246..=247 | 251 | 257 | 266..=269 | 283..=284 | 286 | 288..=290 | 299 | 305..=309 | 311..=312 | 321..=324 | 330..=331 | 344 | 351..=353 | 358..=359 | 367 | 376 | 378..=379 | 384 | 387..=389 => 52, - 70 | 105 => 116, - 14 => 471, - 29 => 542, - 38 => 558, - 47 => 571, - 58..=59 | 82 | 104 | 134 | 156 | 158 => 599, - 78 => 664, - 182 => 812, - 189 => 824, + 22 | 51 | 111 | 152 | 162 | 168 | 171 | 184 | 205 | 209..=211 | 215 | 224 | 241..=242 | 244 | 246..=247 | 251 | 257 | 266..=269 | 283..=284 | 286 | 288..=290 | 299 | 305..=309 | 311..=312 | 321..=324 | 330..=331 | 345 | 352..=354 | 359..=360 | 368 | 376 | 378..=379 | 384 | 387..=389 => 53, + 71 | 106 => 117, + 15 => 472, + 30 => 543, + 39 => 559, + 48 => 572, + 59..=60 | 83 | 105 | 134 | 156 | 158 => 600, + 79 => 666, + 182 => 814, + 189 => 826, _ => 7, }, - 132 => 633, + 132 => 634, 133 => match state { - 82 => 668, - 104 => 706, - 134 => 742, - _ => 604, + 83 => 670, + 105 => 708, + 134 => 744, + _ => 605, }, - 134 => 600, - 135 => 954, + 134 => 601, + 135 => 956, 136 => match state { - 156 | 158 => 781, - _ => 601, + 156 | 158 => 783, + _ => 602, }, - 137 => 503, + 137 => 504, 138 => match state { 144 => 202, _ => 142, }, 140 => 409, - 141 => 759, + 141 => 761, 142 => match state { - 142 => 755, - 144 => 760, - 202 => 841, - _ => 693, + 142 => 757, + 144 => 762, + 202 => 843, + _ => 695, }, 144 => match state { - 48 | 201 => 572, - _ => 494, + 49 | 201 => 573, + _ => 495, }, 146 => match state { 143 => 201, - _ => 48, + _ => 49, }, - 147 => 495, + 147 => 496, 148 => match state { - 12 => 462, - 27 => 541, - 34 => 549, - 120 => 721, - 176 => 808, - 181 => 811, + 13 => 463, + 28 => 542, + 35 => 550, + 120 => 723, + 176 => 810, + 181 => 813, _ => 410, }, - 149 => 634, - 150 => 504, - 151 => 505, - 152 => 506, + 149 => 635, + 150 => 505, + 151 => 506, + 152 => 507, 153 => match state { - 73 => 655, - _ => 532, + 74 => 657, + _ => 533, }, - 155 => 605, + 155 => 606, 156 => match state { 1 => 8, - 39 => 559, - 49 | 100..=101 => 574, - 67 => 621, - 157 => 782, - 208 => 849, - _ => 53, + 40 => 560, + 50 | 101..=102 => 575, + 68 => 622, + 157 => 784, + 208 => 851, + _ => 54, }, - 157 => 507, - 158 => 1050, + 157 => 508, + 158 => 1051, 159 => match state { - 56 => 106, 57 => 107, - 97 => 146, - 98 => 147, - 103 => 150, + 58 => 108, + 98 => 146, + 99 => 147, + 104 => 150, 145 => 203, - 13 | 15 | 19 | 26 | 54 | 62 | 64 | 69 | 83..=84 | 86 | 94 | 122..=123 | 126 | 128 | 130 | 135 | 165..=166 | 175 | 196 | 230..=231 | 235 | 260 | 271 | 298 | 313 | 346 | 368 => 463, - 17 | 87 | 91 | 140..=141 | 198..=200 | 236..=238 | 278 | 281 | 317..=319 | 348..=350 | 377 => 479, - 24 | 73 => 533, - 25 => 535, - 42..=43 | 137 | 239 | 279 => 564, - 61 | 65 => 612, - 68 => 622, - 70 | 105 => 635, - 153 | 249 => 770, - 155 | 253 | 256 | 293 | 295 | 326..=328 | 354..=356 | 380 | 383 | 391..=393 | 398..=401 => 774, - 159 | 218 => 783, - 160 => 787, - 161 => 788, - 163 => 789, - 174 => 806, - 212 => 854, - 213 => 855, - 216 | 291 | 357 | 381 => 861, - 217 => 863, - 219 => 865, - 258 => 929, - 259 | 297 => 930, - 261 => 934, - 302 | 338 | 341 | 360 | 366 | 369..=372 | 385 | 394 => 992, - 310 => 1014, - 329 => 1044, - 339 => 1054, - 342 | 386 => 1059, - 345 => 1073, - 361 | 396 => 1099, - 362 => 1105, - 363 => 1106, - 365 => 1108, - 375 => 1122, - 395 | 402 => 1162, - 397 => 1169, + 14 | 16 | 20 | 27 | 55 | 63 | 65 | 70 | 84..=85 | 87 | 95 | 122..=123 | 126 | 128 | 130 | 135 | 165..=166 | 175 | 196 | 230..=231 | 235 | 260 | 271 | 298 | 313 | 347 | 369 => 464, + 18 | 88 | 92 | 140..=141 | 198..=200 | 236..=238 | 278 | 281 | 317..=319 | 349..=351 | 377 => 480, + 25 | 74 => 534, + 26 => 536, + 43..=44 | 137 | 239 | 279 => 565, + 62 | 66 => 613, + 69 => 623, + 71 | 106 => 636, + 153 | 249 => 772, + 155 | 253 | 256 | 293 | 295 | 326..=328 | 355..=357 | 380 | 383 | 391..=393 | 398..=401 => 776, + 159 | 218 => 785, + 160 => 789, + 161 => 790, + 163 => 791, + 174 => 808, + 212 => 856, + 213 => 857, + 216 | 291 | 358 | 381 => 863, + 217 => 865, + 219 => 867, + 258 => 931, + 259 | 297 => 932, + 261 => 936, + 302 | 339 | 342 | 361 | 367 | 370..=373 | 385 | 394 => 994, + 310 => 1015, + 329 => 1045, + 340 => 1056, + 343 | 386 => 1061, + 346 => 1076, + 362 | 396 => 1102, + 363 => 1108, + 364 => 1109, + 366 => 1111, + 375 => 1125, + 395 | 402 => 1165, + 397 => 1172, _ => 411, }, - 160 => 508, - 163 => 784, + 160 => 509, + 163 => 786, 164 => match state { - 108 => 711, - _ => 608, + 109 => 713, + _ => 609, }, - 166 => 108, - 167 => 609, - 168 => 509, - 169 => 701, - 170 => 510, - 171 => 511, + 166 => 109, + 167 => 610, + 168 => 510, + 169 => 703, + 170 => 511, + 171 => 512, 172 => match state { - 253 => 922, - 256 => 926, - 293 => 975, - 295 => 978, - 326 => 1039, - 327 => 1040, - 328 => 1042, - 354 => 1089, - 355 => 1090, - 356 => 1092, - 380 => 1132, - 383 => 1137, - 391 => 1157, - 392 => 1158, - 393 => 1159, - 398 => 1171, - 399 => 1172, - 400 => 1175, - 401 => 1181, - _ => 775, + 253 => 924, + 256 => 928, + 293 => 977, + 295 => 980, + 326 => 1040, + 327 => 1041, + 328 => 1043, + 355 => 1092, + 356 => 1093, + 357 => 1095, + 380 => 1135, + 383 => 1140, + 391 => 1160, + 392 => 1161, + 393 => 1162, + 398 => 1174, + 399 => 1175, + 400 => 1178, + 401 => 1184, + _ => 777, }, 173 => match state { - 87 => 679, - 91 => 684, - 140 => 751, - 141 => 753, - 198 => 835, - 199 => 836, - 200 => 838, - 236 => 900, - 237 => 901, - 238 => 903, - 278 => 957, - 281 => 962, - 317 => 1028, - 318 => 1029, - 319 => 1030, - 348 => 1080, - 349 => 1081, + 88 => 681, + 92 => 686, + 140 => 753, + 141 => 755, + 198 => 837, + 199 => 838, + 200 => 840, + 236 => 902, + 237 => 903, + 238 => 905, + 278 => 959, + 281 => 964, + 317 => 1029, + 318 => 1030, + 319 => 1031, + 349 => 1083, 350 => 1084, - 377 => 1126, - _ => 480, + 351 => 1087, + 377 => 1129, + _ => 481, }, 174 => match state { - 70 | 105 => 636, + 71 | 106 => 637, _ => 412, }, 175 => match state { - 123 => 727, - _ => 472, + 123 => 729, + _ => 473, }, - 177 => 993, - 178 => 1060, - 179 => 994, + 177 => 995, + 178 => 1062, + 179 => 996, 180 => match state { - 262..=263 | 300 | 303 => 935, - _ => 985, + 262..=263 | 300 | 303 => 937, + _ => 987, }, 181 => match state { 263 => 304, 300 => 332, - 303 => 343, + 303 => 344, _ => 301, }, 182 => match state { - 395 | 402 => 1163, - _ => 1100, + 395 | 402 => 1166, + _ => 1103, }, 183 => match state { - 386 => 1147, - _ => 1061, + 386 => 1150, + _ => 1063, }, 184 => match state { - 342 | 386 => 1062, + 343 | 386 => 1064, _ => 333, }, 185 => match state { - 342 | 386 => 1063, + 343 | 386 => 1065, _ => 334, }, - 186 => 512, + 186 => 513, 187 => match state { 119 => 181, - _ => 34, + _ => 35, }, 188 => match state { - 13 | 122 => 464, - 84 | 231 => 672, - _ => 473, + 14 | 122 => 465, + 85 | 231 => 674, + _ => 474, }, - 189 => 465, + 189 => 466, 190 => match state { - 13 => 36, - 19 => 46, - 24 | 73 => 74, + 14 => 37, + 20 => 47, + 25 | 74 => 75, 122 => 186, 126 => 193, - 54 => 597, - 62 => 614, - 69 => 623, - 260 => 933, - 298 => 983, - 368 => 1111, - _ => 474, + 55 => 598, + 63 => 615, + 70 => 624, + 260 => 935, + 298 => 985, + 369 => 1114, + _ => 475, }, 191 => match state { - 84 => 136, + 85 => 136, 122 => 187, 231 => 272, - _ => 37, + _ => 38, }, - 192 => 513, + 192 => 514, 193 => match state { 4 => 437, - 18 => 485, - 113 => 719, - 125 => 729, + 19 => 486, + 114 => 721, + 125 => 731, _ => 413, }, - 194 => 637, + 194 => 638, 195 => match state { - 70 | 105 => 638, - 302 | 338 | 340..=342 | 360..=361 | 364 | 366 | 369..=372 | 385..=386 | 394 | 396 => 995, + 71 | 106 => 639, + 302 | 339 | 341..=343 | 361..=362 | 365 | 367 | 370..=373 | 385..=386 | 394 | 396 => 997, _ => 414, }, 196 => match state { - 340 => 1055, - 364 => 1107, - _ => 996, + 341 => 1057, + 365 => 1110, + _ => 998, }, 197 => match state { - 342 | 386 => 373, + 343 | 386 => 374, _ => 335, }, - 198 => 488, + 198 => 489, 199 => match state { - 58 => 602, - _ => 606, + 59 => 603, + _ => 607, }, 200 => match state { - 65 => 619, - _ => 613, + 66 => 620, + _ => 614, }, - 201 => 616, + 201 => 617, 202 => match state { - 218 => 864, - _ => 785, + 218 => 866, + _ => 787, }, 203 => match state { - 396 => 1165, - _ => 1101, + 396 => 1168, + _ => 1104, }, - 204 => 1064, - 205 => 776, - 206 => 481, - 207 => 1102, + 204 => 1066, + 205 => 778, + 206 => 482, + 207 => 1105, 208 => match state { - 122 => 723, - _ => 466, + 122 => 725, + _ => 467, }, 209 => 415, 210 => match state { - 19 | 126 => 489, - _ => 475, + 20 | 126 => 490, + _ => 476, }, - 211 => 771, - 212 => 997, + 211 => 773, + 212 => 999, 213 => match state { 195 => 234, 233 => 275, - 32 => 548, - 70 | 105 => 639, - 179 => 810, - 277 => 955, + 33 => 549, + 71 | 106 => 640, + 179 => 812, + 277 => 957, _ => 416, }, - 214 => 640, + 214 => 641, 215 => match state { - 155 => 777, - 253 => 923, - 293 | 328 | 354 | 356 | 380 | 392 | 398 | 400..=401 => 976, - _ => 927, + 155 => 779, + 253 => 925, + 293 | 328 | 355 | 357 | 380 | 392 | 398 | 400..=401 => 978, + _ => 929, }, 216 => match state { - 17 => 482, - 87 => 680, - 91 | 141 | 198..=199 | 237 | 281 | 317 | 319 | 349 => 685, - _ => 752, + 18 => 483, + 88 => 682, + 92 | 141 | 198..=199 | 237 | 281 | 317 | 319 | 350 => 687, + _ => 754, }, - 219 => 778, - 220 => 483, + 219 => 780, + 220 => 484, 224 => match state { - 147 => 764, - 150 => 767, - 154 => 773, - 203 => 844, - 206 => 847, - 207 => 848, - 240 => 908, - _ => 709, + 147 => 766, + 150 => 769, + 154 => 775, + 203 => 846, + 206 => 849, + 207 => 850, + 240 => 910, + _ => 711, }, - 225 => 514, + 225 => 515, 226 => match state { - 338 => 1052, - 341 => 1056, - 361 => 1103, - 366 => 1109, - 370 => 1113, - 371 => 1114, + 339 => 1054, + 342 => 1058, + 362 => 1106, + 367 => 1112, + 371 => 1116, 372 => 1117, - 385 => 1146, - 394 => 1161, - 396 => 1166, - _ => 998, + 373 => 1120, + 385 => 1149, + 394 => 1164, + 396 => 1169, + _ => 1000, }, 228 => match state { - 334 => 1049, - _ => 1048, + 334 => 1050, + _ => 1049, }, 229 => 336, 230 => 417, - 231 => 641, - 232 => 21, - 233 => 515, - 234 => 999, + 231 => 642, + 232 => 22, + 233 => 516, + 234 => 1001, 235 => match state { - 126 => 731, - _ => 490, + 126 => 733, + _ => 491, }, 236 => match state { - 22 => 71, - 70 | 105 => 117, + 23 => 72, + 71 | 106 => 118, 172 => 226, _ => 9, }, - 237 => 642, + 237 => 643, 238 => match state { - 117 => 180, - _ => 33, + 118 => 180, + _ => 34, }, 239 => match state { - 81 => 667, - _ => 552, + 82 => 669, + _ => 553, }, - 240 => 81, + 240 => 82, 241 => match state { - 129 => 737, - 131 => 739, - 194 => 831, - _ => 663, + 129 => 739, + 131 => 741, + 194 => 833, + _ => 665, }, 243 => match state { - 21 => 516, - 50 => 576, - 168 => 798, - 224 => 882, - 268 => 940, - 269 => 944, - 311 => 1018, - _ => 715, + 22 => 517, + 51 => 577, + 168 => 800, + 224 => 884, + 268 => 942, + 269 => 946, + 311 => 1019, + _ => 717, }, 244 => match state { - 13 | 84 | 122 | 231 => 467, - 15 | 19 | 26 | 64 | 83 | 86 | 94 | 123 | 126 | 128 | 130 | 135 | 165..=166 | 175 | 196 | 230 | 235 | 271 | 313 | 346 => 476, - 58..=59 | 82 | 104 | 134 | 156 | 158 => 603, + 14 | 85 | 122 | 231 => 468, + 16 | 20 | 27 | 65 | 84 | 87 | 95 | 123 | 126 | 128 | 130 | 135 | 165..=166 | 175 | 196 | 230 | 235 | 271 | 313 | 347 => 477, + 59..=60 | 83 | 105 | 134 | 156 | 158 => 604, _ => 418, }, - 245 => 1000, + 245 => 1002, 246 => match state { 291 => 325, - 357 => 382, + 358 => 382, 381 => 390, _ => 255, }, @@ -5514,226 +5526,229 @@ mod __parse__Top { 137 => 197, 239 => 280, 279 => 316, - 43 => 565, - _ => 90, + 44 => 566, + _ => 91, }, 250 => 269, 251 => match state { - 302 | 338 | 341 | 360..=361 | 366 | 369..=372 | 385 | 394 | 396 => 1001, - 337 => 1051, + 71 | 106 => 644, + 343 | 386 => 1067, _ => 419, }, - 252 => 337, - 253 => match state { - 10 | 118 | 374 => 456, + 252 => match state { + 302 | 339 | 342 | 361..=362 | 367 | 370..=373 | 385 | 394 | 396 => 337, + 337 => 1052, + 338 => 1053, _ => 420, }, - 254 => match state { - 70 | 105 => 118, - 342 | 386 => 374, + 253 => match state { + 10 => 456, + 12 => 462, _ => 10, }, + 254 => match state { + 128 => 738, + 130 => 740, + _ => 537, + }, 255 => match state { - 128 => 736, - 130 => 738, - _ => 536, + 175 => 809, + _ => 538, }, 256 => match state { - 175 => 807, - _ => 537, - }, - 257 => match state { 162 => 220, - 152 => 769, - 171 => 805, - 184 => 815, - 205 => 846, - 209 => 850, - 210 => 851, - 211 => 852, - 215 => 857, - 241 => 909, - 242 => 910, - 244 => 912, - 246 => 914, - 247 => 915, - 251 => 920, - 257 => 928, - 266 => 938, - 267 => 939, - 283 => 964, - 284 => 965, - 286 => 967, - 288 => 969, - 289 => 970, - 290 => 971, - 299 => 984, - 305 => 1009, - 306 => 1010, - 307 => 1011, - 308 => 1012, - 309 => 1013, - 312 => 1021, - 321 => 1033, - 322 => 1034, - 323 => 1035, - 324 => 1037, - 330 => 1045, - 331 => 1046, - 344 => 1072, - 351 => 1086, - 352 => 1087, - 353 => 1088, - 358 => 1096, - 359 => 1097, - 367 => 1110, - 376 => 1123, - 378 => 1129, - 379 => 1130, - 384 => 1140, - 387 => 1151, - 388 => 1152, - 389 => 1153, + 152 => 771, + 171 => 807, + 184 => 817, + 205 => 848, + 209 => 852, + 210 => 853, + 211 => 854, + 215 => 859, + 241 => 911, + 242 => 912, + 244 => 914, + 246 => 916, + 247 => 917, + 251 => 922, + 257 => 930, + 266 => 940, + 267 => 941, + 283 => 966, + 284 => 967, + 286 => 969, + 288 => 971, + 289 => 972, + 290 => 973, + 299 => 986, + 305 => 1010, + 306 => 1011, + 307 => 1012, + 308 => 1013, + 309 => 1014, + 312 => 1022, + 321 => 1034, + 322 => 1035, + 323 => 1036, + 324 => 1038, + 330 => 1046, + 331 => 1047, + 345 => 1075, + 352 => 1089, + 353 => 1090, + 354 => 1091, + 359 => 1099, + 360 => 1100, + 368 => 1113, + 376 => 1126, + 378 => 1132, + 379 => 1133, + 384 => 1143, + 387 => 1154, + 388 => 1155, + 389 => 1156, _ => 169, }, - 258 => match state { - 23 => 72, - 70 | 105 => 119, + 257 => match state { + 24 => 73, + 71 | 106 => 119, 173 => 227, _ => 11, }, - 259 => 643, - 260 => match state { - 77 => 131, - 102 => 148, + 258 => 645, + 259 => match state { + 78 => 131, + 103 => 148, 129 => 194, - 1 | 31 | 39 | 49 | 67 | 100..=101 | 157 | 208 | 294 => 421, - 13 => 468, - 15 | 24 | 54 | 62 | 64 | 69 | 73 | 83 | 86 | 94 | 123 | 135 | 165..=166 | 196 | 230 | 235 | 260 | 271 | 298 | 313 | 346 | 368 => 477, - 19 | 126 => 491, - 26 | 128 | 130 | 175 => 538, - 44 => 566, - 55 => 598, - 66 => 620, - 70 | 105 | 183 | 229 | 232 | 274 | 314 | 347 => 644, - 75 => 660, - 76 => 661, - 80 => 665, - 84 => 673, - 85 => 676, - 88 => 681, - 89 => 682, - 92 => 686, - 93 => 691, - 95 => 692, - 122 => 724, - 127 => 735, - 132 => 740, - 133 => 741, - 139 => 750, - 149 => 766, - 167 => 797, - 170 => 804, - 214 => 856, - 223 | 264 => 880, - 225 => 883, - 231 => 890, - 243 => 911, - 245 => 913, - 248 => 916, - 250 => 919, - 252 => 921, - 254 => 924, - 265 => 937, - 270 => 946, - 282 => 963, - 285 => 966, - 287 => 968, - 296 => 980, - 320 => 1032, - _ => 517, + 1 | 32 | 40 | 50 | 68 | 101..=102 | 157 | 208 | 294 => 421, + 14 => 469, + 16 | 25 | 55 | 63 | 65 | 70 | 74 | 84 | 87 | 95 | 123 | 135 | 165..=166 | 196 | 230 | 235 | 260 | 271 | 298 | 313 | 347 | 369 => 478, + 20 | 126 => 492, + 27 | 128 | 130 | 175 => 539, + 45 => 567, + 56 => 599, + 67 => 621, + 71 | 106 | 183 | 229 | 232 | 274 | 314 | 348 => 646, + 76 => 662, + 77 => 663, + 81 => 667, + 85 => 675, + 86 => 678, + 89 => 683, + 90 => 684, + 93 => 688, + 94 => 693, + 96 => 694, + 122 => 726, + 127 => 737, + 132 => 742, + 133 => 743, + 139 => 752, + 149 => 768, + 167 => 799, + 170 => 806, + 214 => 858, + 223 | 264 => 882, + 225 => 885, + 231 => 892, + 243 => 913, + 245 => 915, + 248 => 918, + 250 => 921, + 252 => 923, + 254 => 926, + 265 => 939, + 270 => 948, + 282 => 965, + 285 => 968, + 287 => 970, + 296 => 982, + 320 => 1033, + _ => 518, }, - 262 => 645, - 265 => match state { - 100 => 700, + 261 => 647, + 264 => match state { 101 => 702, - _ => 96, + 102 => 704, + _ => 97, }, - 266 => match state { - 31 => 547, - 294 => 977, + 265 => match state { + 32 => 548, + 294 => 979, _ => 422, }, - 268 => match state { - 15 => 40, + 267 => match state { + 16 => 41, 123 => 190, - 19 | 126 => 492, - 64 => 617, - 83 | 196 | 230 | 313 => 670, - 86 | 94 => 677, - 135 | 235 | 271 | 346 => 743, - 165 => 791, - 166 => 794, - _ => 539, + 20 | 126 => 493, + 65 => 618, + 84 | 196 | 230 | 313 => 672, + 87 | 95 => 679, + 135 | 235 | 271 | 347 => 745, + 165 => 793, + 166 => 796, + _ => 540, }, - 269 => 403, - 270 => 518, - 271 => 1002, + 268 => 403, + 269 => 519, + 270 => 338, + 271 => 12, 272 => 1003, - 273 => 540, - 274 => 618, - 275 => 111, - 276 => 519, - 277 => match state { - 249 => 917, - _ => 772, - }, + 273 => 1004, + 274 => 541, + 275 => 619, + 276 => 112, + 277 => 520, 278 => match state { - 107 => 154, + 249 => 919, + _ => 774, + }, + 279 => match state { + 108 => 154, 146 => 204, 147 => 206, 150 => 207, 203 => 240, - 111 => 717, + 112 => 719, _ => 151, }, - 280 => 779, - 281 => match state { - 70 | 105 => 120, - _ => 12, + 281 => 781, + 282 => match state { + 71 | 106 => 120, + _ => 13, }, - 282 => 484, - 283 => 1004, - 284 => 520, - 285 => match state { - 70 | 105 => 121, - 229 | 274 | 347 => 886, - _ => 813, + 283 => 485, + 284 => 1005, + 285 => 521, + 286 => match state { + 71 | 106 => 121, + 229 | 274 | 348 => 888, + _ => 815, }, - 286 => 646, - 287 => match state { + 287 => 648, + 288 => match state { 122 => 188, 231 => 273, - 70 | 105 => 647, - _ => 814, + 71 | 106 => 649, + _ => 816, }, - 288 => match state { - 105 => 707, - _ => 648, + 289 => match state { + 106 => 709, + _ => 650, }, - 290 => 521, - 291 => match state { - 30 => 545, - 70 | 105 => 649, - 178 => 809, + 291 => 522, + 292 => match state { + 31 => 546, + 71 | 106 => 651, + 178 => 811, _ => 423, }, - 292 => 650, - 293 => match state { - 13 => 469, - 49 | 100..=101 => 575, - 122 => 725, - _ => 522, + 293 => 652, + 294 => match state { + 14 => 470, + 50 | 101..=102 => 576, + 122 => 727, + _ => 523, }, _ => 0, } @@ -8975,7 +8990,7 @@ mod __parse__Top { 474 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 178, + nonterminal_produced: 177, } } 475 => { @@ -9015,95 +9030,95 @@ mod __parse__Top { } } 481 => { + __state_machine::SimulatedReduce::Reduce { + states_to_pop: 1, + nonterminal_produced: 178, + } + } + 482 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 179, } } - 482 => { + 483 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 179, } } - 483 => { + 484 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 179, } } - 484 => { + 485 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 179, } } - 485 => { + 486 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 179, } } - 486 => { + 487 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 179, } } - 487 => { + 488 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 179, } } - 488 => { + 489 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 180, } } - 489 => { + 490 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 180, } } - 490 => { + 491 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 181, } } - 491 => { + 492 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 181, } } - 492 => { + 493 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 182, } } - 493 => { + 494 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 183, } } - 494 => { + 495 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 184, } } - 495 => { - __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 185, - } - } 496 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, @@ -9112,13 +9127,13 @@ mod __parse__Top { } 497 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 7, - nonterminal_produced: 186, + states_to_pop: 3, + nonterminal_produced: 185, } } 498 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 8, + states_to_pop: 7, nonterminal_produced: 186, } } @@ -9130,14 +9145,14 @@ mod __parse__Top { } 500 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 7, + states_to_pop: 8, nonterminal_produced: 186, } } 501 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, - nonterminal_produced: 187, + states_to_pop: 7, + nonterminal_produced: 186, } } 502 => { @@ -9166,20 +9181,20 @@ mod __parse__Top { } 506 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 188, + states_to_pop: 1, + nonterminal_produced: 187, } } 507 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, - nonterminal_produced: 189, + states_to_pop: 3, + nonterminal_produced: 188, } } 508 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 190, + nonterminal_produced: 189, } } 509 => { @@ -9191,7 +9206,7 @@ mod __parse__Top { 510 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 191, + nonterminal_produced: 190, } } 511 => { @@ -9202,38 +9217,38 @@ mod __parse__Top { } 512 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 2, - nonterminal_produced: 192, + states_to_pop: 1, + nonterminal_produced: 191, } } 513 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, - nonterminal_produced: 193, + nonterminal_produced: 192, } } 514 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, + states_to_pop: 2, nonterminal_produced: 193, } } 515 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 2, - nonterminal_produced: 194, + states_to_pop: 1, + nonterminal_produced: 193, } } 516 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, + states_to_pop: 2, nonterminal_produced: 194, } } 517 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 195, + nonterminal_produced: 194, } } 518 => { @@ -9251,1713 +9266,1713 @@ mod __parse__Top { 520 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 196, + nonterminal_produced: 195, } } 521 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 197, + nonterminal_produced: 196, } } 522 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 2, + states_to_pop: 1, nonterminal_produced: 197, } } 523 => { + __state_machine::SimulatedReduce::Reduce { + states_to_pop: 2, + nonterminal_produced: 197, + } + } + 524 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 198, } } - 524 => { + 525 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 198, } } - 525 => { + 526 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 199, } } - 526 => { + 527 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 199, } } - 527 => { + 528 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 200, } } - 528 => { + 529 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 200, } } - 529 => { + 530 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 201, } } - 530 => { + 531 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 201, } } - 531 => { + 532 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 201, } } - 532 => { + 533 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 201, } } - 533 => { + 534 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 202, } } - 534 => { + 535 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 202, } } - 535 => { + 536 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 202, } } - 536 => { + 537 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 202, } } - 537 => { + 538 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 203, } } - 538 => { + 539 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 203, } } - 539 => { + 540 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 204, } } - 540 => { + 541 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 204, } } - 541 => { + 542 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 205, } } - 542 => { + 543 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 205, } } - 543 => { + 544 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 206, } } - 544 => { + 545 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 206, } } - 545 => { + 546 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 207, } } - 546 => { + 547 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 207, } } - 547 => { + 548 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 208, } } - 548 => { + 549 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 208, } } - 549 => { + 550 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 209, } } - 550 => { + 551 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 209, } } - 551 => { + 552 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 210, } } - 552 => { + 553 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 210, } } - 553 => { + 554 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 211, } } - 554 => { + 555 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 211, } } - 555 => { + 556 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 212, } } - 556 => { + 557 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 212, } } - 557 => { + 558 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 213, } } - 558 => { + 559 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 213, } } - 559 => { + 560 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 214, } } - 560 => { + 561 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 214, } } - 561 => { + 562 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 215, } } - 562 => { + 563 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 215, } } - 563 => { + 564 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 216, } } - 564 => { + 565 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 216, } } - 565 => { + 566 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 217, } } - 566 => { + 567 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 217, } } - 567 => { + 568 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 217, } } - 568 => { + 569 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 218, } } - 569 => { + 570 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 218, } } - 570 => { + 571 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 218, } } - 571 => { + 572 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 219, } } - 572 => { + 573 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 9, nonterminal_produced: 219, } } - 573 => { + 574 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 10, nonterminal_produced: 219, } } - 574 => { + 575 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 219, } } - 575 => { + 576 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 219, } } - 576 => { + 577 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 9, nonterminal_produced: 219, } } - 577 => { + 578 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 219, } } - 578 => { + 579 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 10, nonterminal_produced: 219, } } - 579 => { + 580 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 11, nonterminal_produced: 219, } } - 580 => { + 581 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 219, } } - 581 => { + 582 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 9, nonterminal_produced: 219, } } - 582 => { + 583 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 10, nonterminal_produced: 219, } } - 583 => { + 584 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 219, } } - 584 => { + 585 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 219, } } - 585 => { + 586 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 219, } } - 586 => { + 587 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 219, } } - 587 => { + 588 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 219, } } - 588 => { + 589 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 219, } } - 589 => { + 590 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 219, } } - 590 => { + 591 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 219, } } - 591 => { + 592 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 9, nonterminal_produced: 219, } } - 592 => { + 593 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 219, } } - 593 => { + 594 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 219, } } - 594 => { + 595 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 219, } } - 595 => { + 596 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 219, } } - 596 => { + 597 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 219, } } - 597 => { + 598 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 219, } } - 598 => { + 599 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 219, } } - 599 => { + 600 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 219, } } - 600 => { + 601 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 9, nonterminal_produced: 219, } } - 601 => { + 602 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 219, } } - 602 => { + 603 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 219, } } - 603 => { + 604 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 219, } } - 604 => { + 605 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 219, } } - 605 => { + 606 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 9, nonterminal_produced: 219, } } - 606 => { + 607 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 10, nonterminal_produced: 219, } } - 607 => { + 608 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 219, } } - 608 => { + 609 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 219, } } - 609 => { + 610 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 9, nonterminal_produced: 219, } } - 610 => { + 611 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 219, } } - 611 => { + 612 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 219, } } - 612 => { + 613 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 219, } } - 613 => { + 614 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 219, } } - 614 => { + 615 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 219, } } - 615 => { + 616 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 219, } } - 616 => { + 617 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 219, } } - 617 => { + 618 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 219, } } - 618 => { + 619 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 219, } } - 619 => { + 620 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 219, } } - 620 => { + 621 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 219, } } - 621 => { + 622 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 219, } } - 622 => { + 623 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 219, } } - 623 => { + 624 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 219, } } - 624 => { + 625 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 219, } } - 625 => { + 626 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 219, } } - 626 => { + 627 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 219, } } - 627 => { + 628 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 219, } } - 628 => { + 629 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 219, } } - 629 => { + 630 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 219, } } - 630 => { + 631 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 219, } } - 631 => { + 632 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 219, } } - 632 => { + 633 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 219, } } - 633 => { + 634 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 219, } } - 634 => { + 635 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 219, } } - 635 => { + 636 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 219, } } - 636 => { + 637 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 219, } } - 637 => { + 638 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 219, } } - 638 => { + 639 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 219, } } - 639 => { + 640 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 219, } } - 640 => { + 641 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 219, } } - 641 => { + 642 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 219, } } - 642 => { + 643 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 219, } } - 643 => { + 644 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 219, } } - 644 => { + 645 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 219, } } - 645 => { + 646 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 219, } } - 646 => { + 647 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 219, } } - 647 => { + 648 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 219, } } - 648 => { + 649 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 219, } } - 649 => { + 650 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 220, } } - 650 => { + 651 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 9, nonterminal_produced: 220, } } - 651 => { + 652 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 10, nonterminal_produced: 220, } } - 652 => { + 653 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 220, } } - 653 => { + 654 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 220, } } - 654 => { + 655 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 9, nonterminal_produced: 220, } } - 655 => { + 656 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 220, } } - 656 => { + 657 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 10, nonterminal_produced: 220, } } - 657 => { + 658 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 11, nonterminal_produced: 220, } } - 658 => { + 659 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 220, } } - 659 => { + 660 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 9, nonterminal_produced: 220, } } - 660 => { + 661 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 10, nonterminal_produced: 220, } } - 661 => { + 662 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 220, } } - 662 => { + 663 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 220, } } - 663 => { + 664 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 220, } } - 664 => { + 665 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 220, } } - 665 => { + 666 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 220, } } - 666 => { + 667 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 220, } } - 667 => { + 668 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 220, } } - 668 => { + 669 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 220, } } - 669 => { + 670 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 9, nonterminal_produced: 220, } } - 670 => { + 671 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 220, } } - 671 => { + 672 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 220, } } - 672 => { + 673 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 220, } } - 673 => { + 674 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 220, } } - 674 => { + 675 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 220, } } - 675 => { + 676 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 220, } } - 676 => { + 677 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 220, } } - 677 => { + 678 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 220, } } - 678 => { + 679 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 9, nonterminal_produced: 220, } } - 679 => { + 680 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 220, } } - 680 => { + 681 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 220, } } - 681 => { + 682 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 220, } } - 682 => { + 683 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 220, } } - 683 => { + 684 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 9, nonterminal_produced: 220, } } - 684 => { + 685 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 10, nonterminal_produced: 220, } } - 685 => { + 686 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 220, } } - 686 => { + 687 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 220, } } - 687 => { + 688 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 9, nonterminal_produced: 220, } } - 688 => { + 689 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 220, } } - 689 => { + 690 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 220, } } - 690 => { + 691 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 220, } } - 691 => { + 692 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 220, } } - 692 => { + 693 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 220, } } - 693 => { + 694 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 220, } } - 694 => { + 695 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 220, } } - 695 => { + 696 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 220, } } - 696 => { + 697 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 8, nonterminal_produced: 220, } } - 697 => { + 698 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 220, } } - 698 => { + 699 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 220, } } - 699 => { + 700 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 220, } } - 700 => { + 701 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 220, } } - 701 => { + 702 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 220, } } - 702 => { + 703 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 220, } } - 703 => { + 704 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 220, } } - 704 => { + 705 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 220, } } - 705 => { + 706 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, nonterminal_produced: 220, } } - 706 => { + 707 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 220, } } - 707 => { + 708 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 220, } } - 708 => { + 709 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 220, } } - 709 => { + 710 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 220, } } - 710 => { + 711 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 220, } } - 711 => { + 712 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 220, } } - 712 => { + 713 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 220, } } - 713 => { + 714 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 220, } } - 714 => { + 715 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 220, } } - 715 => { + 716 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 220, } } - 716 => { + 717 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 220, } } - 717 => { + 718 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 220, } } - 718 => { + 719 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 220, } } - 719 => { + 720 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 220, } } - 720 => { + 721 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 220, } } - 721 => { + 722 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 220, } } - 722 => { + 723 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 220, } } - 723 => { + 724 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 220, } } - 724 => { + 725 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 220, } } - 725 => { + 726 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 220, } } - 726 => { + 727 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 220, } } - 727 => { + 728 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 221, } } - 728 => { + 729 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 221, } } - 729 => { + 730 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 222, } } - 730 => { + 731 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 222, } } - 731 => { + 732 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 222, } } - 732 => { + 733 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 222, } } - 733 => { + 734 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 222, } } - 734 => { + 735 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 222, } } - 735 => { + 736 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 222, } } - 736 => { + 737 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 222, } } - 737 => { + 738 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 223, } } - 738 => { + 739 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 223, } } - 739 => { + 740 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 223, } } - 740 => { + 741 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 223, } } - 741 => { + 742 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 223, } } - 742 => { + 743 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 223, } } - 743 => { + 744 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 223, } } - 744 => { + 745 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 223, } } - 745 => { + 746 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 224, } } - 746 => { + 747 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 224, } } - 747 => { + 748 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 225, } } - 748 => { + 749 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 226, } } - 749 => { + 750 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 226, } } - 750 => { + 751 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 227, } } - 751 => { + 752 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 227, } } - 752 => { + 753 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 228, } } - 753 => { + 754 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 228, } } - 754 => { + 755 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 228, } } - 755 => { + 756 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 228, } } - 756 => { + 757 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 228, } } - 757 => { + 758 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 228, } } - 758 => { + 759 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 228, } } - 759 => { + 760 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 229, } } - 760 => { + 761 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 229, } } - 761 => { + 762 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 229, } } - 762 => { + 763 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 229, } } - 763 => { + 764 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 230, } } - 764 => { + 765 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 230, } } - 765 => { + 766 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 231, } } - 766 => { + 767 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 231, } } - 767 => { + 768 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 232, } } - 768 => { + 769 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 232, } } - 769 => { + 770 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 232, } } - 770 => { + 771 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 232, } } - 771 => { + 772 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 232, } } - 772 => { + 773 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 232, } } - 773 => { + 774 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 232, } } - 774 => { + 775 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 233, } } - 775 => { + 776 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 233, } } - 776 => { + 777 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 233, } } - 777 => { + 778 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 234, } } - 778 => { + 779 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 234, } } - 779 => { + 780 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 234, } } - 780 => { + 781 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 234, } } - 781 => { + 782 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 234, } } - 782 => { + 783 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 234, } } - 783 => { + 784 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 234, } } - 784 => { + 785 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 234, } } - 785 => { + 786 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 234, } } - 786 => { + 787 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 235, } } - 787 => { + 788 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 235, } } - 788 => { + 789 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 236, } } - 789 => { + 790 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 236, } } - 790 => { + 791 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 237, } } - 791 => { + 792 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 237, } } - 792 => { + 793 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 238, } } - 793 => { + 794 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 238, } } - 794 => { + 795 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 239, } } - 795 => { + 796 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 6, nonterminal_produced: 239, } } - 796 => { + 797 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 239, } } - 797 => { + 798 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 239, } } - 798 => { + 799 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 240, } } - 799 => { + 800 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 240, } } - 800 => { + 801 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 241, } } - 801 => { + 802 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 241, } } - 802 => { + 803 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 242, } } - 803 => { + 804 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 242, } } - 804 => { - __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, - nonterminal_produced: 243, - } - } 805 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, @@ -11019,141 +11034,141 @@ mod __parse__Top { } } 815 => { + __state_machine::SimulatedReduce::Reduce { + states_to_pop: 1, + nonterminal_produced: 243, + } + } + 816 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 244, } } - 816 => { + 817 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 245, } } - 817 => { + 818 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 246, } } - 818 => { + 819 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 246, } } - 819 => { + 820 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 247, } } - 820 => { + 821 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 247, } } - 821 => { + 822 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 248, } } - 822 => { + 823 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 249, } } - 823 => { + 824 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, nonterminal_produced: 249, } } - 824 => { + 825 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 250, } } - 825 => { + 826 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 250, } } - 826 => { + 827 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 250, } } - 827 => { + 828 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 250, } } - 828 => { + 829 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, nonterminal_produced: 250, } } - 829 => { + 830 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, nonterminal_produced: 250, } } - 830 => { + 831 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 250, } } - 831 => { + 832 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 5, nonterminal_produced: 250, } } - 832 => { + 833 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, nonterminal_produced: 250, } } - 833 => { + 834 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, nonterminal_produced: 250, } } - 834 => { - __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, - nonterminal_produced: 251, - } - } 835 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 252, + nonterminal_produced: 251, } } 836 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 2, - nonterminal_produced: 252, + states_to_pop: 1, + nonterminal_produced: 251, } } 837 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 253, + nonterminal_produced: 252, } } 838 => { @@ -11165,61 +11180,61 @@ mod __parse__Top { 839 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 254, + nonterminal_produced: 253, } } 840 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 2, + states_to_pop: 1, nonterminal_produced: 254, } } 841 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, - nonterminal_produced: 255, + states_to_pop: 4, + nonterminal_produced: 254, } } 842 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 4, - nonterminal_produced: 255, + states_to_pop: 3, + nonterminal_produced: 254, } } 843 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, - nonterminal_produced: 255, + nonterminal_produced: 254, } } 844 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 255, + states_to_pop: 2, + nonterminal_produced: 254, } } 845 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 2, - nonterminal_produced: 255, + states_to_pop: 3, + nonterminal_produced: 254, } } 846 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 255, + states_to_pop: 2, + nonterminal_produced: 254, } } 847 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, - nonterminal_produced: 255, + nonterminal_produced: 254, } } 848 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 2, - nonterminal_produced: 255, + states_to_pop: 1, + nonterminal_produced: 254, } } 849 => { @@ -11230,92 +11245,92 @@ mod __parse__Top { } 850 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, - nonterminal_produced: 256, + states_to_pop: 2, + nonterminal_produced: 255, } } 851 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, - nonterminal_produced: 256, + nonterminal_produced: 255, } } 852 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 2, - nonterminal_produced: 256, + states_to_pop: 1, + nonterminal_produced: 255, } } 853 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, + states_to_pop: 3, nonterminal_produced: 256, } } 854 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 257, + states_to_pop: 4, + nonterminal_produced: 256, } } 855 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 4, - nonterminal_produced: 257, + states_to_pop: 2, + nonterminal_produced: 256, } } 856 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 2, - nonterminal_produced: 257, + states_to_pop: 3, + nonterminal_produced: 256, } } 857 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 257, + states_to_pop: 4, + nonterminal_produced: 256, } } 858 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 4, + states_to_pop: 3, nonterminal_produced: 257, } } 859 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 258, + states_to_pop: 1, + nonterminal_produced: 257, } } 860 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, + states_to_pop: 3, nonterminal_produced: 258, } } 861 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 259, + states_to_pop: 1, + nonterminal_produced: 258, } } 862 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, + states_to_pop: 5, nonterminal_produced: 259, } } 863 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 5, - nonterminal_produced: 260, + states_to_pop: 1, + nonterminal_produced: 259, } } 864 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 260, + nonterminal_produced: 259, } } 865 => { @@ -11326,26 +11341,26 @@ mod __parse__Top { } 866 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, - nonterminal_produced: 261, + states_to_pop: 0, + nonterminal_produced: 260, } } 867 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 0, + states_to_pop: 5, nonterminal_produced: 261, } } 868 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 5, - nonterminal_produced: 262, + states_to_pop: 1, + nonterminal_produced: 261, } } 869 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 262, + nonterminal_produced: 261, } } 870 => { @@ -11362,20 +11377,20 @@ mod __parse__Top { } 872 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, - nonterminal_produced: 264, + states_to_pop: 0, + nonterminal_produced: 263, } } 873 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 0, + states_to_pop: 1, nonterminal_produced: 264, } } 874 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 265, + nonterminal_produced: 264, } } 875 => { @@ -11387,7 +11402,7 @@ mod __parse__Top { 876 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 266, + nonterminal_produced: 265, } } 877 => { @@ -11405,103 +11420,103 @@ mod __parse__Top { 879 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 268, + nonterminal_produced: 267, } } 880 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, + states_to_pop: 2, nonterminal_produced: 268, } } 881 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 2, - nonterminal_produced: 269, + nonterminal_produced: 268, } } 882 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 2, - nonterminal_produced: 269, + states_to_pop: 3, + nonterminal_produced: 268, } } 883 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, + states_to_pop: 10, nonterminal_produced: 269, } } 884 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 10, - nonterminal_produced: 270, + states_to_pop: 7, + nonterminal_produced: 269, } } 885 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, - nonterminal_produced: 270, + nonterminal_produced: 269, } } 886 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 7, - nonterminal_produced: 270, + states_to_pop: 4, + nonterminal_produced: 269, } } 887 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 4, - nonterminal_produced: 270, + states_to_pop: 10, + nonterminal_produced: 269, } } 888 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 10, - nonterminal_produced: 270, + states_to_pop: 7, + nonterminal_produced: 269, } } 889 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 7, - nonterminal_produced: 270, + nonterminal_produced: 269, } } 890 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 7, - nonterminal_produced: 270, + states_to_pop: 4, + nonterminal_produced: 269, } } 891 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 4, - nonterminal_produced: 270, + states_to_pop: 6, + nonterminal_produced: 269, } } 892 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 6, + states_to_pop: 2, nonterminal_produced: 270, } } 893 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 271, + states_to_pop: 2, + nonterminal_produced: 270, } } 894 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, + states_to_pop: 2, nonterminal_produced: 271, } } 895 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 272, + states_to_pop: 2, + nonterminal_produced: 271, } } 896 => { @@ -11513,7 +11528,7 @@ mod __parse__Top { 897 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, - nonterminal_produced: 273, + nonterminal_produced: 272, } } 898 => { @@ -11525,7 +11540,7 @@ mod __parse__Top { 899 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, - nonterminal_produced: 274, + nonterminal_produced: 273, } } 900 => { @@ -11536,74 +11551,74 @@ mod __parse__Top { } 901 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, - nonterminal_produced: 275, + states_to_pop: 3, + nonterminal_produced: 274, } } 902 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 5, - nonterminal_produced: 276, + states_to_pop: 3, + nonterminal_produced: 275, } } 903 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 4, - nonterminal_produced: 276, + states_to_pop: 3, + nonterminal_produced: 275, } } 904 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 277, + states_to_pop: 1, + nonterminal_produced: 276, } } 905 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, + states_to_pop: 5, nonterminal_produced: 277, } } 906 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 2, + states_to_pop: 4, nonterminal_produced: 277, } } 907 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 2, - nonterminal_produced: 277, + states_to_pop: 3, + nonterminal_produced: 278, } } 908 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 4, + states_to_pop: 1, nonterminal_produced: 278, } } 909 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, + states_to_pop: 2, nonterminal_produced: 278, } } 910 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, - nonterminal_produced: 279, + states_to_pop: 2, + nonterminal_produced: 278, } } 911 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 0, + states_to_pop: 4, nonterminal_produced: 279, } } 912 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 3, - nonterminal_produced: 280, + nonterminal_produced: 279, } } 913 => { @@ -11614,13 +11629,13 @@ mod __parse__Top { } 914 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, - nonterminal_produced: 281, + states_to_pop: 0, + nonterminal_produced: 280, } } 915 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, + states_to_pop: 3, nonterminal_produced: 281, } } @@ -11639,37 +11654,37 @@ mod __parse__Top { 918 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 283, + nonterminal_produced: 282, } } 919 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 7, - nonterminal_produced: 284, + states_to_pop: 1, + nonterminal_produced: 282, } } 920 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 4, - nonterminal_produced: 284, + states_to_pop: 1, + nonterminal_produced: 283, } } 921 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 285, + nonterminal_produced: 284, } } 922 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, + states_to_pop: 7, nonterminal_produced: 285, } } 923 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, - nonterminal_produced: 286, + states_to_pop: 4, + nonterminal_produced: 285, } } 924 => { @@ -11680,153 +11695,171 @@ mod __parse__Top { } 925 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 287, + states_to_pop: 1, + nonterminal_produced: 286, } } 926 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 4, - nonterminal_produced: 288, + states_to_pop: 1, + nonterminal_produced: 287, } } 927 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 288, + states_to_pop: 1, + nonterminal_produced: 287, } } 928 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 6, + states_to_pop: 3, nonterminal_produced: 288, } } 929 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 4, - nonterminal_produced: 288, + nonterminal_produced: 289, } } 930 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 7, - nonterminal_produced: 288, + states_to_pop: 3, + nonterminal_produced: 289, } } 931 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 5, - nonterminal_produced: 288, + states_to_pop: 6, + nonterminal_produced: 289, } } 932 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 5, - nonterminal_produced: 288, + states_to_pop: 4, + nonterminal_produced: 289, } } 933 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 288, + states_to_pop: 7, + nonterminal_produced: 289, } } 934 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 6, - nonterminal_produced: 288, + states_to_pop: 5, + nonterminal_produced: 289, } } 935 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 4, - nonterminal_produced: 288, + states_to_pop: 5, + nonterminal_produced: 289, } } 936 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, - nonterminal_produced: 288, + states_to_pop: 3, + nonterminal_produced: 289, } } 937 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 2, - nonterminal_produced: 288, + states_to_pop: 6, + nonterminal_produced: 289, } } 938 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, + states_to_pop: 4, nonterminal_produced: 289, } } 939 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 5, - nonterminal_produced: 290, + states_to_pop: 1, + nonterminal_produced: 289, } } 940 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 4, - nonterminal_produced: 290, + states_to_pop: 2, + nonterminal_produced: 289, } } 941 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 291, + states_to_pop: 1, + nonterminal_produced: 290, } } 942 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, + states_to_pop: 5, nonterminal_produced: 291, } } 943 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, - nonterminal_produced: 292, + states_to_pop: 4, + nonterminal_produced: 291, } } 944 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, + states_to_pop: 3, nonterminal_produced: 292, } } 945 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 2, - nonterminal_produced: 293, + states_to_pop: 1, + nonterminal_produced: 292, } } 946 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 1, + states_to_pop: 3, nonterminal_produced: 293, } } 947 => { __state_machine::SimulatedReduce::Reduce { - states_to_pop: 3, + states_to_pop: 1, nonterminal_produced: 293, } } - 948 => __state_machine::SimulatedReduce::Accept, + 948 => { + __state_machine::SimulatedReduce::Reduce { + states_to_pop: 2, + nonterminal_produced: 294, + } + } 949 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 1, - nonterminal_produced: 295, + nonterminal_produced: 294, } } 950 => { + __state_machine::SimulatedReduce::Reduce { + states_to_pop: 3, + nonterminal_produced: 294, + } + } + 951 => __state_machine::SimulatedReduce::Accept, + 952 => { + __state_machine::SimulatedReduce::Reduce { + states_to_pop: 1, + nonterminal_produced: 296, + } + } + 953 => { __state_machine::SimulatedReduce::Reduce { states_to_pop: 0, - nonterminal_produced: 295, + nonterminal_produced: 296, } } _ => panic!("invalid reduction index {}", __reduce_index) @@ -11984,7 +12017,7 @@ mod __parse__Top { __reduce23(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 24 => { - // ("," >) = ",", "*", StarTypedParameter, ",", KwargParameter => ActionFn(966); + // ("," >) = ",", "*", StarTypedParameter, ",", KwargParameter => ActionFn(969); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -11993,7 +12026,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action966::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action969::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12001,7 +12034,7 @@ mod __parse__Top { (5, 14) } 25 => { - // ("," >) = ",", "*", ",", KwargParameter => ActionFn(967); + // ("," >) = ",", "*", ",", KwargParameter => ActionFn(970); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant9(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -12009,7 +12042,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action967::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action970::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12017,7 +12050,7 @@ mod __parse__Top { (4, 14) } 26 => { - // ("," >) = ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter => ActionFn(968); + // ("," >) = ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter => ActionFn(971); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant9(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -12027,7 +12060,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action968::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action971::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12035,7 +12068,7 @@ mod __parse__Top { (6, 14) } 27 => { - // ("," >) = ",", "*", ("," >)+, ",", KwargParameter => ActionFn(969); + // ("," >) = ",", "*", ("," >)+, ",", KwargParameter => ActionFn(972); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -12044,7 +12077,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action969::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action972::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12052,14 +12085,14 @@ mod __parse__Top { (5, 14) } 28 => { - // ("," >) = ",", "*", StarTypedParameter => ActionFn(970); + // ("," >) = ",", "*", StarTypedParameter => ActionFn(973); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant63(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action970::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action973::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12067,13 +12100,13 @@ mod __parse__Top { (3, 14) } 29 => { - // ("," >) = ",", "*" => ActionFn(971); + // ("," >) = ",", "*" => ActionFn(974); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action971::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action974::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12081,7 +12114,7 @@ mod __parse__Top { (2, 14) } 30 => { - // ("," >) = ",", "*", StarTypedParameter, ("," >)+ => ActionFn(972); + // ("," >) = ",", "*", StarTypedParameter, ("," >)+ => ActionFn(975); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant63(__symbols); @@ -12089,7 +12122,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action972::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action975::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12097,14 +12130,14 @@ mod __parse__Top { (4, 14) } 31 => { - // ("," >) = ",", "*", ("," >)+ => ActionFn(973); + // ("," >) = ",", "*", ("," >)+ => ActionFn(976); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant12(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action973::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action976::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12112,7 +12145,7 @@ mod __parse__Top { (3, 14) } 32 => { - // ("," >)? = ",", "*", StarTypedParameter, ",", KwargParameter => ActionFn(990); + // ("," >)? = ",", "*", StarTypedParameter, ",", KwargParameter => ActionFn(993); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -12121,7 +12154,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action990::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action993::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12129,7 +12162,7 @@ mod __parse__Top { (5, 15) } 33 => { - // ("," >)? = ",", "*", ",", KwargParameter => ActionFn(991); + // ("," >)? = ",", "*", ",", KwargParameter => ActionFn(994); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant9(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -12137,7 +12170,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action991::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action994::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12145,7 +12178,7 @@ mod __parse__Top { (4, 15) } 34 => { - // ("," >)? = ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter => ActionFn(992); + // ("," >)? = ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter => ActionFn(995); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant9(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -12155,7 +12188,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action992::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action995::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12163,7 +12196,7 @@ mod __parse__Top { (6, 15) } 35 => { - // ("," >)? = ",", "*", ("," >)+, ",", KwargParameter => ActionFn(993); + // ("," >)? = ",", "*", ("," >)+, ",", KwargParameter => ActionFn(996); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -12172,7 +12205,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action993::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action996::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12180,14 +12213,14 @@ mod __parse__Top { (5, 15) } 36 => { - // ("," >)? = ",", "*", StarTypedParameter => ActionFn(994); + // ("," >)? = ",", "*", StarTypedParameter => ActionFn(997); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant63(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action994::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action997::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12195,13 +12228,13 @@ mod __parse__Top { (3, 15) } 37 => { - // ("," >)? = ",", "*" => ActionFn(995); + // ("," >)? = ",", "*" => ActionFn(998); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action995::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action998::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12209,7 +12242,7 @@ mod __parse__Top { (2, 15) } 38 => { - // ("," >)? = ",", "*", StarTypedParameter, ("," >)+ => ActionFn(996); + // ("," >)? = ",", "*", StarTypedParameter, ("," >)+ => ActionFn(999); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant63(__symbols); @@ -12217,7 +12250,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action996::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action999::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12225,14 +12258,14 @@ mod __parse__Top { (4, 15) } 39 => { - // ("," >)? = ",", "*", ("," >)+ => ActionFn(997); + // ("," >)? = ",", "*", ("," >)+ => ActionFn(1000); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant12(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action997::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1000::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12243,7 +12276,7 @@ mod __parse__Top { __reduce40(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 41 => { - // ("," >) = ",", "*", StarUntypedParameter, ",", KwargParameter => ActionFn(1026); + // ("," >) = ",", "*", StarUntypedParameter, ",", KwargParameter => ActionFn(1029); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -12252,7 +12285,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1026::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1029::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12260,7 +12293,7 @@ mod __parse__Top { (5, 16) } 42 => { - // ("," >) = ",", "*", ",", KwargParameter => ActionFn(1027); + // ("," >) = ",", "*", ",", KwargParameter => ActionFn(1030); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant9(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -12268,7 +12301,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1027::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1030::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12276,7 +12309,7 @@ mod __parse__Top { (4, 16) } 43 => { - // ("," >) = ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1028); + // ("," >) = ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1031); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant9(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -12286,7 +12319,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1028::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1031::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12294,7 +12327,7 @@ mod __parse__Top { (6, 16) } 44 => { - // ("," >) = ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1029); + // ("," >) = ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1032); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -12303,7 +12336,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1029::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1032::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12311,14 +12344,14 @@ mod __parse__Top { (5, 16) } 45 => { - // ("," >) = ",", "*", StarUntypedParameter => ActionFn(1030); + // ("," >) = ",", "*", StarUntypedParameter => ActionFn(1033); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant63(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1030::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1033::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12326,13 +12359,13 @@ mod __parse__Top { (3, 16) } 46 => { - // ("," >) = ",", "*" => ActionFn(1031); + // ("," >) = ",", "*" => ActionFn(1034); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1031::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1034::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12340,7 +12373,7 @@ mod __parse__Top { (2, 16) } 47 => { - // ("," >) = ",", "*", StarUntypedParameter, ("," >)+ => ActionFn(1032); + // ("," >) = ",", "*", StarUntypedParameter, ("," >)+ => ActionFn(1035); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant63(__symbols); @@ -12348,7 +12381,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1032::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1035::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12356,14 +12389,14 @@ mod __parse__Top { (4, 16) } 48 => { - // ("," >) = ",", "*", ("," >)+ => ActionFn(1033); + // ("," >) = ",", "*", ("," >)+ => ActionFn(1036); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant12(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1033::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1036::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12371,7 +12404,7 @@ mod __parse__Top { (3, 16) } 49 => { - // ("," >)? = ",", "*", StarUntypedParameter, ",", KwargParameter => ActionFn(1050); + // ("," >)? = ",", "*", StarUntypedParameter, ",", KwargParameter => ActionFn(1053); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -12380,7 +12413,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1050::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1053::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12388,7 +12421,7 @@ mod __parse__Top { (5, 17) } 50 => { - // ("," >)? = ",", "*", ",", KwargParameter => ActionFn(1051); + // ("," >)? = ",", "*", ",", KwargParameter => ActionFn(1054); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant9(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -12396,7 +12429,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1051::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1054::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12404,7 +12437,7 @@ mod __parse__Top { (4, 17) } 51 => { - // ("," >)? = ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1052); + // ("," >)? = ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1055); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant9(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -12414,7 +12447,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1052::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1055::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12422,7 +12455,7 @@ mod __parse__Top { (6, 17) } 52 => { - // ("," >)? = ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1053); + // ("," >)? = ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1056); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -12431,7 +12464,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1053::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1056::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12439,14 +12472,14 @@ mod __parse__Top { (5, 17) } 53 => { - // ("," >)? = ",", "*", StarUntypedParameter => ActionFn(1054); + // ("," >)? = ",", "*", StarUntypedParameter => ActionFn(1057); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant63(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1054::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1057::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12454,13 +12487,13 @@ mod __parse__Top { (3, 17) } 54 => { - // ("," >)? = ",", "*" => ActionFn(1055); + // ("," >)? = ",", "*" => ActionFn(1058); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1055::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1058::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12468,7 +12501,7 @@ mod __parse__Top { (2, 17) } 55 => { - // ("," >)? = ",", "*", StarUntypedParameter, ("," >)+ => ActionFn(1056); + // ("," >)? = ",", "*", StarUntypedParameter, ("," >)+ => ActionFn(1059); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant63(__symbols); @@ -12476,7 +12509,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1056::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1059::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12484,14 +12517,14 @@ mod __parse__Top { (4, 17) } 56 => { - // ("," >)? = ",", "*", ("," >)+ => ActionFn(1057); + // ("," >)? = ",", "*", ("," >)+ => ActionFn(1060); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant12(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1057::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1060::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12811,14 +12844,14 @@ mod __parse__Top { __reduce160(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 161 => { - // Arguments = "(", FunctionArgument, ")" => ActionFn(1537); + // Arguments = "(", FunctionArgument, ")" => ActionFn(1541); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant31(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1537::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1541::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12826,13 +12859,13 @@ mod __parse__Top { (3, 84) } 162 => { - // Arguments = "(", ")" => ActionFn(1538); + // Arguments = "(", ")" => ActionFn(1542); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1538::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1542::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12840,7 +12873,7 @@ mod __parse__Top { (2, 84) } 163 => { - // Arguments = "(", ( ",")+, FunctionArgument, ")" => ActionFn(1539); + // Arguments = "(", ( ",")+, FunctionArgument, ")" => ActionFn(1543); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant31(__symbols); @@ -12848,7 +12881,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1539::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1543::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12856,14 +12889,14 @@ mod __parse__Top { (4, 84) } 164 => { - // Arguments = "(", ( ",")+, ")" => ActionFn(1540); + // Arguments = "(", ( ",")+, ")" => ActionFn(1544); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant32(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1540::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1544::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12889,14 +12922,14 @@ mod __parse__Top { __reduce170(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 171 => { - // AsPattern = OrPattern, "as", Identifier => ActionFn(1233); + // AsPattern = OrPattern, "as", Identifier => ActionFn(1236); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant35(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1233::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1236::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12934,16 +12967,7 @@ mod __parse__Top { __reduce181(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 182 => { - // Atom<"all"> = StringLiteralOrFString+ => ActionFn(1236); - let __sym0 = __pop_Variant95(__symbols); - let __start = __sym0.0; - let __end = __sym0.2; - let __nt = match super::__action1236::<>(source_code, mode, __sym0) { - Ok(v) => v, - Err(e) => return Some(Err(e)), - }; - __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 94) + __reduce182(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 183 => { __reduce183(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) @@ -12967,7 +12991,7 @@ mod __parse__Top { __reduce189(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 190 => { - // Atom<"all"> = "(", OneOrMore>, ",", NamedOrStarExpr, ",", ")" => ActionFn(1243); + // Atom<"all"> = "(", OneOrMore>, ",", NamedOrStarExpr, ",", ")" => ActionFn(1245); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -12977,7 +13001,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1243::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1245::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -12985,7 +13009,7 @@ mod __parse__Top { (6, 94) } 191 => { - // Atom<"all"> = "(", NamedOrStarExpr, ",", ")" => ActionFn(1244); + // Atom<"all"> = "(", NamedOrStarExpr, ",", ")" => ActionFn(1246); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -12993,7 +13017,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1244::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1246::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13001,7 +13025,7 @@ mod __parse__Top { (4, 94) } 192 => { - // Atom<"all"> = "(", OneOrMore>, ",", NamedOrStarExpr, ("," )+, ",", ")" => ActionFn(1245); + // Atom<"all"> = "(", OneOrMore>, ",", NamedOrStarExpr, ("," )+, ",", ")" => ActionFn(1247); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -13012,7 +13036,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1245::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1247::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13020,7 +13044,7 @@ mod __parse__Top { (7, 94) } 193 => { - // Atom<"all"> = "(", NamedOrStarExpr, ("," )+, ",", ")" => ActionFn(1246); + // Atom<"all"> = "(", NamedOrStarExpr, ("," )+, ",", ")" => ActionFn(1248); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -13029,7 +13053,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1246::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1248::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13037,7 +13061,7 @@ mod __parse__Top { (5, 94) } 194 => { - // Atom<"all"> = "(", OneOrMore>, ",", NamedOrStarExpr, ")" => ActionFn(1247); + // Atom<"all"> = "(", OneOrMore>, ",", NamedOrStarExpr, ")" => ActionFn(1249); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant15(__symbols); @@ -13046,7 +13070,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1247::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1249::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13054,14 +13078,14 @@ mod __parse__Top { (5, 94) } 195 => { - // Atom<"all"> = "(", NamedOrStarExpr, ")" => ActionFn(1248); + // Atom<"all"> = "(", NamedOrStarExpr, ")" => ActionFn(1250); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1248::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1250::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13069,7 +13093,7 @@ mod __parse__Top { (3, 94) } 196 => { - // Atom<"all"> = "(", OneOrMore>, ",", NamedOrStarExpr, ("," )+, ")" => ActionFn(1249); + // Atom<"all"> = "(", OneOrMore>, ",", NamedOrStarExpr, ("," )+, ")" => ActionFn(1251); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant17(__symbols); @@ -13079,7 +13103,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1249::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1251::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13087,7 +13111,7 @@ mod __parse__Top { (6, 94) } 197 => { - // Atom<"all"> = "(", NamedOrStarExpr, ("," )+, ")" => ActionFn(1250); + // Atom<"all"> = "(", NamedOrStarExpr, ("," )+, ")" => ActionFn(1252); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant17(__symbols); @@ -13095,7 +13119,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1250::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1252::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13112,7 +13136,7 @@ mod __parse__Top { __reduce200(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 201 => { - // Atom<"all"> = "(", "**", Expression<"all">, ")" => ActionFn(1254); + // Atom<"all"> = "(", "**", Expression<"all">, ")" => ActionFn(1256); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant15(__symbols); @@ -13120,7 +13144,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1254::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1256::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13155,16 +13179,7 @@ mod __parse__Top { __reduce210(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 211 => { - // Atom<"no-withitems"> = StringLiteralOrFString+ => ActionFn(1263); - let __sym0 = __pop_Variant95(__symbols); - let __start = __sym0.0; - let __end = __sym0.2; - let __nt = match super::__action1263::<>(source_code, mode, __sym0) { - Ok(v) => v, - Err(e) => return Some(Err(e)), - }; - __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 95) + __reduce211(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 212 => { __reduce212(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) @@ -13182,7 +13197,7 @@ mod __parse__Top { __reduce216(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 217 => { - // Atom<"no-withitems"> = "(", OneOrMore>, ",", NamedOrStarExpr, ",", ")" => ActionFn(1268); + // Atom<"no-withitems"> = "(", OneOrMore>, ",", NamedOrStarExpr, ",", ")" => ActionFn(1269); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -13192,7 +13207,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1268::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1269::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13200,7 +13215,7 @@ mod __parse__Top { (6, 95) } 218 => { - // Atom<"no-withitems"> = "(", NamedOrStarExpr, ",", ")" => ActionFn(1269); + // Atom<"no-withitems"> = "(", NamedOrStarExpr, ",", ")" => ActionFn(1270); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -13208,7 +13223,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1269::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1270::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13216,7 +13231,7 @@ mod __parse__Top { (4, 95) } 219 => { - // Atom<"no-withitems"> = "(", OneOrMore>, ",", NamedOrStarExpr, ("," )+, ",", ")" => ActionFn(1270); + // Atom<"no-withitems"> = "(", OneOrMore>, ",", NamedOrStarExpr, ("," )+, ",", ")" => ActionFn(1271); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -13227,7 +13242,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1270::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1271::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13235,7 +13250,7 @@ mod __parse__Top { (7, 95) } 220 => { - // Atom<"no-withitems"> = "(", NamedOrStarExpr, ("," )+, ",", ")" => ActionFn(1271); + // Atom<"no-withitems"> = "(", NamedOrStarExpr, ("," )+, ",", ")" => ActionFn(1272); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -13244,7 +13259,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1271::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1272::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13252,7 +13267,7 @@ mod __parse__Top { (5, 95) } 221 => { - // Atom<"no-withitems"> = "(", OneOrMore>, ",", NamedOrStarExpr, ")" => ActionFn(1272); + // Atom<"no-withitems"> = "(", OneOrMore>, ",", NamedOrStarExpr, ")" => ActionFn(1273); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant15(__symbols); @@ -13261,7 +13276,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1272::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1273::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13269,14 +13284,14 @@ mod __parse__Top { (5, 95) } 222 => { - // Atom<"no-withitems"> = "(", NamedOrStarExpr, ")" => ActionFn(1273); + // Atom<"no-withitems"> = "(", NamedOrStarExpr, ")" => ActionFn(1274); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1273::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1274::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13284,7 +13299,7 @@ mod __parse__Top { (3, 95) } 223 => { - // Atom<"no-withitems"> = "(", OneOrMore>, ",", NamedOrStarExpr, ("," )+, ")" => ActionFn(1274); + // Atom<"no-withitems"> = "(", OneOrMore>, ",", NamedOrStarExpr, ("," )+, ")" => ActionFn(1275); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant17(__symbols); @@ -13294,7 +13309,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1274::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1275::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13302,7 +13317,7 @@ mod __parse__Top { (6, 95) } 224 => { - // Atom<"no-withitems"> = "(", NamedOrStarExpr, ("," )+, ")" => ActionFn(1275); + // Atom<"no-withitems"> = "(", NamedOrStarExpr, ("," )+, ")" => ActionFn(1276); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant17(__symbols); @@ -13310,7 +13325,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1275::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1276::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13327,7 +13342,7 @@ mod __parse__Top { __reduce227(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 228 => { - // Atom<"no-withitems"> = "(", "**", Expression<"all">, ")" => ActionFn(1279); + // Atom<"no-withitems"> = "(", "**", Expression<"all">, ")" => ActionFn(1280); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant15(__symbols); @@ -13335,7 +13350,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1279::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1280::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13727,11 +13742,11 @@ mod __parse__Top { __reduce356(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 357 => { - // ExpressionStatement = GenericList => ActionFn(1752); + // ExpressionStatement = GenericList => ActionFn(1756); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = match super::__action1752::<>(source_code, mode, __sym0) { + let __nt = match super::__action1756::<>(source_code, mode, __sym0) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13739,13 +13754,13 @@ mod __parse__Top { (1, 137) } 358 => { - // ExpressionStatement = GenericList, AssignSuffix+ => ActionFn(1753); + // ExpressionStatement = GenericList, AssignSuffix+ => ActionFn(1757); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant17(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1753::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1757::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13753,14 +13768,14 @@ mod __parse__Top { (2, 137) } 359 => { - // ExpressionStatement = GenericList, AugAssign, TestListOrYieldExpr => ActionFn(1754); + // ExpressionStatement = GenericList, AugAssign, TestListOrYieldExpr => ActionFn(1758); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant49(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1754::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1758::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13768,7 +13783,7 @@ mod __parse__Top { (3, 137) } 360 => { - // ExpressionStatement = Test<"all">, ":", Test<"all">, AssignSuffix => ActionFn(1531); + // ExpressionStatement = Test<"all">, ":", Test<"all">, AssignSuffix => ActionFn(1535); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant15(__symbols); let __sym2 = __pop_Variant15(__symbols); @@ -13776,7 +13791,7 @@ mod __parse__Top { let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1531::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1535::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13784,14 +13799,14 @@ mod __parse__Top { (4, 137) } 361 => { - // ExpressionStatement = Test<"all">, ":", Test<"all"> => ActionFn(1532); + // ExpressionStatement = Test<"all">, ":", Test<"all"> => ActionFn(1536); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1532::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1536::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13799,13 +13814,13 @@ mod __parse__Top { (3, 137) } 362 => { - // FStringConversion = "!", name => ActionFn(800); + // FStringConversion = "!", name => ActionFn(801); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant6(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action800::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action801::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13843,11 +13858,11 @@ mod __parse__Top { __reduce372(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 373 => { - // FStringMiddlePattern = fstring_middle => ActionFn(803); + // FStringMiddlePattern = fstring_middle => ActionFn(1315); let __sym0 = __pop_Variant3(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = match super::__action803::<>(source_code, mode, __sym0) { + let __nt = match super::__action1315::<>(source_code, mode, __sym0) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13867,7 +13882,7 @@ mod __parse__Top { __reduce377(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 378 => { - // FStringReplacementField = "{", TestListOrYieldExpr, "=", FStringConversion, FStringFormatSpecSuffix, "}" => ActionFn(1577); + // FStringReplacementField = "{", TestListOrYieldExpr, "=", FStringConversion, FStringFormatSpecSuffix, "}" => ActionFn(1581); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant44(__symbols); @@ -13877,7 +13892,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1577::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1581::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13885,7 +13900,7 @@ mod __parse__Top { (6, 147) } 379 => { - // FStringReplacementField = "{", TestListOrYieldExpr, "=", FStringConversion, "}" => ActionFn(1578); + // FStringReplacementField = "{", TestListOrYieldExpr, "=", FStringConversion, "}" => ActionFn(1582); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant67(__symbols); @@ -13894,7 +13909,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1578::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1582::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13902,7 +13917,7 @@ mod __parse__Top { (5, 147) } 380 => { - // FStringReplacementField = "{", TestListOrYieldExpr, "=", FStringFormatSpecSuffix, "}" => ActionFn(1579); + // FStringReplacementField = "{", TestListOrYieldExpr, "=", FStringFormatSpecSuffix, "}" => ActionFn(1583); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant44(__symbols); @@ -13911,7 +13926,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1579::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1583::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13919,7 +13934,7 @@ mod __parse__Top { (5, 147) } 381 => { - // FStringReplacementField = "{", TestListOrYieldExpr, "=", "}" => ActionFn(1580); + // FStringReplacementField = "{", TestListOrYieldExpr, "=", "}" => ActionFn(1584); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -13927,7 +13942,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1580::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1584::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13935,7 +13950,7 @@ mod __parse__Top { (4, 147) } 382 => { - // FStringReplacementField = "{", TestListOrYieldExpr, FStringConversion, FStringFormatSpecSuffix, "}" => ActionFn(1581); + // FStringReplacementField = "{", TestListOrYieldExpr, FStringConversion, FStringFormatSpecSuffix, "}" => ActionFn(1585); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant44(__symbols); @@ -13944,7 +13959,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1581::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1585::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13952,7 +13967,7 @@ mod __parse__Top { (5, 147) } 383 => { - // FStringReplacementField = "{", TestListOrYieldExpr, FStringConversion, "}" => ActionFn(1582); + // FStringReplacementField = "{", TestListOrYieldExpr, FStringConversion, "}" => ActionFn(1586); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant67(__symbols); @@ -13960,7 +13975,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1582::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1586::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13968,7 +13983,7 @@ mod __parse__Top { (4, 147) } 384 => { - // FStringReplacementField = "{", TestListOrYieldExpr, FStringFormatSpecSuffix, "}" => ActionFn(1583); + // FStringReplacementField = "{", TestListOrYieldExpr, FStringFormatSpecSuffix, "}" => ActionFn(1587); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant44(__symbols); @@ -13976,7 +13991,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1583::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1587::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -13984,14 +13999,14 @@ mod __parse__Top { (4, 147) } 385 => { - // FStringReplacementField = "{", TestListOrYieldExpr, "}" => ActionFn(1584); + // FStringReplacementField = "{", TestListOrYieldExpr, "}" => ActionFn(1588); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1584::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1588::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -14200,11 +14215,11 @@ mod __parse__Top { __reduce452(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 453 => { - // IpyEscapeCommandExpr = ipy_escape_command => ActionFn(1342); + // IpyEscapeCommandExpr = ipy_escape_command => ActionFn(1344); let __sym0 = __pop_Variant5(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = match super::__action1342::<>(source_code, mode, __sym0) { + let __nt = match super::__action1344::<>(source_code, mode, __sym0) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -14212,11 +14227,11 @@ mod __parse__Top { (1, 169) } 454 => { - // IpyEscapeCommandStatement = ipy_escape_command => ActionFn(1343); + // IpyEscapeCommandStatement = ipy_escape_command => ActionFn(1345); let __sym0 = __pop_Variant5(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = match super::__action1343::<>(source_code, mode, __sym0) { + let __nt = match super::__action1345::<>(source_code, mode, __sym0) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -14224,13 +14239,13 @@ mod __parse__Top { (1, 170) } 455 => { - // IpyHelpEndEscapeCommandStatement = Expression<"all">, ("?")+ => ActionFn(1344); + // IpyHelpEndEscapeCommandStatement = Expression<"all">, ("?")+ => ActionFn(1346); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant22(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1344::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1346::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -14250,7 +14265,7 @@ mod __parse__Top { __reduce459(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 460 => { - // LambdaDef = "lambda", ParameterList, ":", fstring_middle, Test<"all"> => ActionFn(1781); + // LambdaDef = "lambda", ParameterList, ":", fstring_middle, Test<"all"> => ActionFn(1785); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant15(__symbols); let __sym3 = __pop_Variant3(__symbols); @@ -14259,7 +14274,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1781::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1785::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -14267,7 +14282,7 @@ mod __parse__Top { (5, 174) } 461 => { - // LambdaDef = "lambda", ParameterList, ":", Test<"all"> => ActionFn(1782); + // LambdaDef = "lambda", ParameterList, ":", Test<"all"> => ActionFn(1786); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant15(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -14275,7 +14290,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1782::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1786::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -14283,7 +14298,7 @@ mod __parse__Top { (4, 174) } 462 => { - // LambdaDef = "lambda", ":", fstring_middle, Test<"all"> => ActionFn(1783); + // LambdaDef = "lambda", ":", fstring_middle, Test<"all"> => ActionFn(1787); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant15(__symbols); let __sym2 = __pop_Variant3(__symbols); @@ -14291,7 +14306,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1783::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1787::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -14299,14 +14314,14 @@ mod __parse__Top { (4, 174) } 463 => { - // LambdaDef = "lambda", ":", Test<"all"> => ActionFn(1784); + // LambdaDef = "lambda", ":", Test<"all"> => ActionFn(1788); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1784::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1788::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -14341,20 +14356,20 @@ mod __parse__Top { __reduce472(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 473 => { - // LiteralPattern = StringLiteral+ => ActionFn(1351); - let __sym0 = __pop_Variant95(__symbols); + __reduce473(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) + } + 474 => { + // LiteralPattern = TwoOrMore => ActionFn(1354); + let __sym0 = __pop_Variant96(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = match super::__action1351::<>(source_code, mode, __sym0) { + let __nt = match super::__action1354::<>(source_code, mode, __sym0) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (1, 177) } - 474 => { - __reduce474(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) - } 475 => { __reduce475(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } @@ -14371,16 +14386,7 @@ mod __parse__Top { __reduce479(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 480 => { - // MappingKey = StringLiteralOrFString+ => ActionFn(1355); - let __sym0 = __pop_Variant95(__symbols); - let __start = __sym0.0; - let __end = __sym0.2; - let __nt = match super::__action1355::<>(source_code, mode, __sym0) { - Ok(v) => v, - Err(e) => return Some(Err(e)), - }; - __symbols.push((__start, __Symbol::Variant44(__nt), __end)); - (1, 178) + __reduce480(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 481 => { __reduce481(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) @@ -14653,7 +14659,10 @@ mod __parse__Top { __reduce570(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 571 => { - // ParameterList = OneOrMore>, ",", "*", StarTypedParameter, ",", KwargParameter, "," => ActionFn(1603); + __reduce571(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) + } + 572 => { + // ParameterList = OneOrMore>, ",", "*", StarTypedParameter, ",", KwargParameter, "," => ActionFn(1607); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant9(__symbols); @@ -14664,15 +14673,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1603::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1607::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 219) } - 572 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter, ",", KwargParameter, "," => ActionFn(1604); + 573 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter, ",", KwargParameter, "," => ActionFn(1608); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant0(__symbols); let __sym7 = __pop_Variant9(__symbols); @@ -14685,15 +14694,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = match super::__action1604::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { + let __nt = match super::__action1608::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (9, 219) } - 573 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter, ",", KwargParameter, "," => ActionFn(1605); + 574 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter, ",", KwargParameter, "," => ActionFn(1609); assert!(__symbols.len() >= 10); let __sym9 = __pop_Variant0(__symbols); let __sym8 = __pop_Variant9(__symbols); @@ -14707,15 +14716,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym9.2; - let __nt = match super::__action1605::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { + let __nt = match super::__action1609::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (10, 219) } - 574 => { - // ParameterList = OneOrMore>, ",", "*", ",", KwargParameter, "," => ActionFn(1606); + 575 => { + // ParameterList = OneOrMore>, ",", "*", ",", KwargParameter, "," => ActionFn(1610); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant9(__symbols); @@ -14725,15 +14734,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1606::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1610::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 219) } - 575 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", ",", KwargParameter, "," => ActionFn(1607); + 576 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", ",", KwargParameter, "," => ActionFn(1611); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant0(__symbols); let __sym6 = __pop_Variant9(__symbols); @@ -14745,15 +14754,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1607::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1611::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 219) } - 576 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ",", KwargParameter, "," => ActionFn(1608); + 577 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ",", KwargParameter, "," => ActionFn(1612); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant0(__symbols); let __sym7 = __pop_Variant9(__symbols); @@ -14766,15 +14775,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = match super::__action1608::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { + let __nt = match super::__action1612::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (9, 219) } - 577 => { - // ParameterList = OneOrMore>, ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1609); + 578 => { + // ParameterList = OneOrMore>, ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1613); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant0(__symbols); let __sym6 = __pop_Variant9(__symbols); @@ -14786,15 +14795,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1609::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1613::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 219) } - 578 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1610); + 579 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1614); assert!(__symbols.len() >= 10); let __sym9 = __pop_Variant0(__symbols); let __sym8 = __pop_Variant9(__symbols); @@ -14808,15 +14817,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym9.2; - let __nt = match super::__action1610::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { + let __nt = match super::__action1614::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (10, 219) } - 579 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1611); + 580 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1615); assert!(__symbols.len() >= 11); let __sym10 = __pop_Variant0(__symbols); let __sym9 = __pop_Variant9(__symbols); @@ -14831,15 +14840,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym10.2; - let __nt = match super::__action1611::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9, __sym10) { + let __nt = match super::__action1615::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9, __sym10) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (11, 219) } - 580 => { - // ParameterList = OneOrMore>, ",", "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1612); + 581 => { + // ParameterList = OneOrMore>, ",", "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1616); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant9(__symbols); @@ -14850,15 +14859,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1612::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1616::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 219) } - 581 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1613); + 582 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1617); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant0(__symbols); let __sym7 = __pop_Variant9(__symbols); @@ -14871,15 +14880,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = match super::__action1613::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { + let __nt = match super::__action1617::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (9, 219) } - 582 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1614); + 583 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1618); assert!(__symbols.len() >= 10); let __sym9 = __pop_Variant0(__symbols); let __sym8 = __pop_Variant9(__symbols); @@ -14893,15 +14902,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym9.2; - let __nt = match super::__action1614::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { + let __nt = match super::__action1618::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (10, 219) } - 583 => { - // ParameterList = OneOrMore>, ",", "*", StarTypedParameter, "," => ActionFn(1615); + 584 => { + // ParameterList = OneOrMore>, ",", "*", StarTypedParameter, "," => ActionFn(1619); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant63(__symbols); @@ -14910,15 +14919,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1615::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1619::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 219) } - 584 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter, "," => ActionFn(1616); + 585 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter, "," => ActionFn(1620); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant63(__symbols); @@ -14929,15 +14938,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1616::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1620::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 219) } - 585 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter, "," => ActionFn(1617); + 586 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter, "," => ActionFn(1621); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant0(__symbols); let __sym6 = __pop_Variant63(__symbols); @@ -14949,15 +14958,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1617::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1621::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 219) } - 586 => { - // ParameterList = OneOrMore>, ",", "*", "," => ActionFn(1618); + 587 => { + // ParameterList = OneOrMore>, ",", "*", "," => ActionFn(1622); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -14965,15 +14974,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1618::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1622::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 219) } - 587 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", "," => ActionFn(1619); + 588 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", "," => ActionFn(1623); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -14983,15 +14992,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1619::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1623::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 219) } - 588 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", "," => ActionFn(1620); + 589 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", "," => ActionFn(1624); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -15002,15 +15011,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1620::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1624::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 219) } - 589 => { - // ParameterList = OneOrMore>, ",", "*", StarTypedParameter, ("," >)+, "," => ActionFn(1621); + 590 => { + // ParameterList = OneOrMore>, ",", "*", StarTypedParameter, ("," >)+, "," => ActionFn(1625); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant12(__symbols); @@ -15020,15 +15029,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1621::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1625::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 219) } - 590 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter, ("," >)+, "," => ActionFn(1622); + 591 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter, ("," >)+, "," => ActionFn(1626); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant0(__symbols); let __sym6 = __pop_Variant12(__symbols); @@ -15040,15 +15049,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1622::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1626::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 219) } - 591 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter, ("," >)+, "," => ActionFn(1623); + 592 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter, ("," >)+, "," => ActionFn(1627); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant0(__symbols); let __sym7 = __pop_Variant12(__symbols); @@ -15061,15 +15070,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = match super::__action1623::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { + let __nt = match super::__action1627::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (9, 219) } - 592 => { - // ParameterList = OneOrMore>, ",", "*", ("," >)+, "," => ActionFn(1624); + 593 => { + // ParameterList = OneOrMore>, ",", "*", ("," >)+, "," => ActionFn(1628); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant12(__symbols); @@ -15078,15 +15087,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1624::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1628::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 219) } - 593 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+, "," => ActionFn(1625); + 594 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+, "," => ActionFn(1629); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant12(__symbols); @@ -15097,15 +15106,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1625::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1629::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 219) } - 594 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+, "," => ActionFn(1626); + 595 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+, "," => ActionFn(1630); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant0(__symbols); let __sym6 = __pop_Variant12(__symbols); @@ -15117,29 +15126,29 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1626::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1630::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 219) } - 595 => { - // ParameterList = OneOrMore>, "," => ActionFn(1627); + 596 => { + // ParameterList = OneOrMore>, "," => ActionFn(1631); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1627::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1631::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (2, 219) } - 596 => { - // ParameterList = OneOrMore>, ",", "/", "," => ActionFn(1628); + 597 => { + // ParameterList = OneOrMore>, ",", "/", "," => ActionFn(1632); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -15147,15 +15156,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1628::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1632::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 219) } - 597 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, "," => ActionFn(1629); + 598 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, "," => ActionFn(1633); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant12(__symbols); @@ -15164,15 +15173,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1629::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1633::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 219) } - 598 => { - // ParameterList = OneOrMore>, ",", "*", StarTypedParameter, ",", KwargParameter => ActionFn(1630); + 599 => { + // ParameterList = OneOrMore>, ",", "*", StarTypedParameter, ",", KwargParameter => ActionFn(1634); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant9(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -15182,15 +15191,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1630::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1634::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 219) } - 599 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter, ",", KwargParameter => ActionFn(1631); + 600 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter, ",", KwargParameter => ActionFn(1635); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant9(__symbols); let __sym6 = __pop_Variant0(__symbols); @@ -15202,15 +15211,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1631::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1635::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 219) } - 600 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter, ",", KwargParameter => ActionFn(1632); + 601 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter, ",", KwargParameter => ActionFn(1636); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant9(__symbols); let __sym7 = __pop_Variant0(__symbols); @@ -15223,15 +15232,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = match super::__action1632::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { + let __nt = match super::__action1636::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (9, 219) } - 601 => { - // ParameterList = OneOrMore>, ",", "*", ",", KwargParameter => ActionFn(1633); + 602 => { + // ParameterList = OneOrMore>, ",", "*", ",", KwargParameter => ActionFn(1637); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -15240,15 +15249,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1633::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1637::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 219) } - 602 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", ",", KwargParameter => ActionFn(1634); + 603 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", ",", KwargParameter => ActionFn(1638); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant9(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -15259,15 +15268,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1634::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1638::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 219) } - 603 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ",", KwargParameter => ActionFn(1635); + 604 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ",", KwargParameter => ActionFn(1639); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant9(__symbols); let __sym6 = __pop_Variant0(__symbols); @@ -15279,15 +15288,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1635::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1639::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 219) } - 604 => { - // ParameterList = OneOrMore>, ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1636); + 605 => { + // ParameterList = OneOrMore>, ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1640); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant9(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -15298,15 +15307,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1636::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1640::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 219) } - 605 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1637); + 606 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1641); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant9(__symbols); let __sym7 = __pop_Variant0(__symbols); @@ -15319,15 +15328,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = match super::__action1637::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { + let __nt = match super::__action1641::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (9, 219) } - 606 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1638); + 607 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1642); assert!(__symbols.len() >= 10); let __sym9 = __pop_Variant9(__symbols); let __sym8 = __pop_Variant0(__symbols); @@ -15341,15 +15350,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym9.2; - let __nt = match super::__action1638::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { + let __nt = match super::__action1642::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (10, 219) } - 607 => { - // ParameterList = OneOrMore>, ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1639); + 608 => { + // ParameterList = OneOrMore>, ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1643); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant9(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -15359,15 +15368,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1639::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1643::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 219) } - 608 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1640); + 609 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1644); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant9(__symbols); let __sym6 = __pop_Variant0(__symbols); @@ -15379,15 +15388,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1640::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1644::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 219) } - 609 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1641); + 610 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1645); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant9(__symbols); let __sym7 = __pop_Variant0(__symbols); @@ -15400,15 +15409,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = match super::__action1641::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { + let __nt = match super::__action1645::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (9, 219) } - 610 => { - // ParameterList = OneOrMore>, ",", "*", StarTypedParameter => ActionFn(1642); + 611 => { + // ParameterList = OneOrMore>, ",", "*", StarTypedParameter => ActionFn(1646); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -15416,15 +15425,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1642::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1646::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 219) } - 611 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter => ActionFn(1643); + 612 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter => ActionFn(1647); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant63(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -15434,15 +15443,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1643::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1647::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 219) } - 612 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter => ActionFn(1644); + 613 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter => ActionFn(1648); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant63(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -15453,30 +15462,30 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1644::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1648::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 219) } - 613 => { - // ParameterList = OneOrMore>, ",", "*" => ActionFn(1645); + 614 => { + // ParameterList = OneOrMore>, ",", "*" => ActionFn(1649); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1645::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1649::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (3, 219) } - 614 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*" => ActionFn(1646); + 615 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*" => ActionFn(1650); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -15485,15 +15494,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1646::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1650::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 219) } - 615 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*" => ActionFn(1647); + 616 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*" => ActionFn(1651); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -15503,15 +15512,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1647::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1651::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 219) } - 616 => { - // ParameterList = OneOrMore>, ",", "*", StarTypedParameter, ("," >)+ => ActionFn(1648); + 617 => { + // ParameterList = OneOrMore>, ",", "*", StarTypedParameter, ("," >)+ => ActionFn(1652); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant12(__symbols); let __sym3 = __pop_Variant63(__symbols); @@ -15520,15 +15529,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1648::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1652::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 219) } - 617 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter, ("," >)+ => ActionFn(1649); + 618 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarTypedParameter, ("," >)+ => ActionFn(1653); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant12(__symbols); let __sym5 = __pop_Variant63(__symbols); @@ -15539,15 +15548,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1649::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1653::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 219) } - 618 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter, ("," >)+ => ActionFn(1650); + 619 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarTypedParameter, ("," >)+ => ActionFn(1654); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant12(__symbols); let __sym6 = __pop_Variant63(__symbols); @@ -15559,15 +15568,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1650::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1654::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 219) } - 619 => { - // ParameterList = OneOrMore>, ",", "*", ("," >)+ => ActionFn(1651); + 620 => { + // ParameterList = OneOrMore>, ",", "*", ("," >)+ => ActionFn(1655); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -15575,15 +15584,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1651::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1655::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 219) } - 620 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+ => ActionFn(1652); + 621 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+ => ActionFn(1656); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant12(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -15593,15 +15602,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1652::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1656::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 219) } - 621 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+ => ActionFn(1653); + 622 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+ => ActionFn(1657); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant12(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -15612,42 +15621,42 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1653::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1657::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 219) } - 622 => { - // ParameterList = OneOrMore> => ActionFn(1654); + 623 => { + // ParameterList = OneOrMore> => ActionFn(1658); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = match super::__action1654::<>(source_code, mode, __sym0) { + let __nt = match super::__action1658::<>(source_code, mode, __sym0) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (1, 219) } - 623 => { - // ParameterList = OneOrMore>, ",", "/" => ActionFn(1655); + 624 => { + // ParameterList = OneOrMore>, ",", "/" => ActionFn(1659); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1655::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1659::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (3, 219) } - 624 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+ => ActionFn(1656); + 625 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+ => ActionFn(1660); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -15655,15 +15664,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1656::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1660::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 219) } - 625 => { - // ParameterList = OneOrMore>, ",", KwargParameter, "," => ActionFn(1657); + 626 => { + // ParameterList = OneOrMore>, ",", KwargParameter, "," => ActionFn(1661); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant9(__symbols); @@ -15671,15 +15680,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1657::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1661::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 219) } - 626 => { - // ParameterList = OneOrMore>, ",", "/", ",", KwargParameter, "," => ActionFn(1658); + 627 => { + // ParameterList = OneOrMore>, ",", "/", ",", KwargParameter, "," => ActionFn(1662); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant9(__symbols); @@ -15689,15 +15698,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1658::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1662::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 219) } - 627 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", KwargParameter, "," => ActionFn(1659); + 628 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", KwargParameter, "," => ActionFn(1663); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant9(__symbols); @@ -15708,30 +15717,30 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1659::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1663::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 219) } - 628 => { - // ParameterList = OneOrMore>, ",", KwargParameter => ActionFn(1660); + 629 => { + // ParameterList = OneOrMore>, ",", KwargParameter => ActionFn(1664); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant9(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1660::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1664::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (3, 219) } - 629 => { - // ParameterList = OneOrMore>, ",", "/", ",", KwargParameter => ActionFn(1661); + 630 => { + // ParameterList = OneOrMore>, ",", "/", ",", KwargParameter => ActionFn(1665); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -15740,15 +15749,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1661::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1665::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 219) } - 630 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", KwargParameter => ActionFn(1662); + 631 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", KwargParameter => ActionFn(1666); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant9(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -15758,15 +15767,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1662::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1666::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 219) } - 631 => { - // ParameterList = "*", StarTypedParameter, ",", KwargParameter, "," => ActionFn(1402); + 632 => { + // ParameterList = "*", StarTypedParameter, ",", KwargParameter, "," => ActionFn(1404); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant9(__symbols); @@ -15775,15 +15784,15 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1402::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1404::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 219) } - 632 => { - // ParameterList = "*", ",", KwargParameter, "," => ActionFn(1403); + 633 => { + // ParameterList = "*", ",", KwargParameter, "," => ActionFn(1405); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant9(__symbols); @@ -15791,15 +15800,15 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1403::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1405::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 219) } - 633 => { - // ParameterList = "*", StarTypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1404); + 634 => { + // ParameterList = "*", StarTypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1406); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant9(__symbols); @@ -15809,15 +15818,15 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1404::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1406::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 219) } - 634 => { - // ParameterList = "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1405); + 635 => { + // ParameterList = "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1407); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant9(__symbols); @@ -15826,44 +15835,44 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1405::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1407::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 219) } - 635 => { - // ParameterList = "*", StarTypedParameter, "," => ActionFn(1406); + 636 => { + // ParameterList = "*", StarTypedParameter, "," => ActionFn(1408); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant63(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1406::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1408::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (3, 219) } - 636 => { - // ParameterList = "*", "," => ActionFn(1407); + 637 => { + // ParameterList = "*", "," => ActionFn(1409); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1407::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1409::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (2, 219) } - 637 => { - // ParameterList = "*", StarTypedParameter, ("," >)+, "," => ActionFn(1408); + 638 => { + // ParameterList = "*", StarTypedParameter, ("," >)+, "," => ActionFn(1410); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant12(__symbols); @@ -15871,30 +15880,30 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1408::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1410::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 219) } - 638 => { - // ParameterList = "*", ("," >)+, "," => ActionFn(1409); + 639 => { + // ParameterList = "*", ("," >)+, "," => ActionFn(1411); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant12(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1409::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1411::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (3, 219) } - 639 => { - // ParameterList = "*", StarTypedParameter, ",", KwargParameter => ActionFn(1410); + 640 => { + // ParameterList = "*", StarTypedParameter, ",", KwargParameter => ActionFn(1412); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant9(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -15902,30 +15911,30 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1410::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1412::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 219) } - 640 => { - // ParameterList = "*", ",", KwargParameter => ActionFn(1411); + 641 => { + // ParameterList = "*", ",", KwargParameter => ActionFn(1413); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant9(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1411::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1413::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (3, 219) } - 641 => { - // ParameterList = "*", StarTypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1412); + 642 => { + // ParameterList = "*", StarTypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1414); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -15934,15 +15943,15 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1412::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1414::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 219) } - 642 => { - // ParameterList = "*", ("," >)+, ",", KwargParameter => ActionFn(1413); + 643 => { + // ParameterList = "*", ("," >)+, ",", KwargParameter => ActionFn(1415); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant9(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -15950,76 +15959,76 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1413::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1415::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 219) } - 643 => { - // ParameterList = "*", StarTypedParameter => ActionFn(1414); + 644 => { + // ParameterList = "*", StarTypedParameter => ActionFn(1416); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant63(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1414::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1416::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (2, 219) } - 644 => { - // ParameterList = "*" => ActionFn(1415); + 645 => { + // ParameterList = "*" => ActionFn(1417); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = match super::__action1415::<>(source_code, mode, __sym0) { + let __nt = match super::__action1417::<>(source_code, mode, __sym0) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (1, 219) } - 645 => { - // ParameterList = "*", StarTypedParameter, ("," >)+ => ActionFn(1416); + 646 => { + // ParameterList = "*", StarTypedParameter, ("," >)+ => ActionFn(1418); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant12(__symbols); let __sym1 = __pop_Variant63(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1416::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1418::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (3, 219) } - 646 => { - // ParameterList = "*", ("," >)+ => ActionFn(1417); + 647 => { + // ParameterList = "*", ("," >)+ => ActionFn(1419); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant12(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1417::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1419::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (2, 219) } - 647 => { - __reduce647(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) - } 648 => { __reduce648(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 649 => { - // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter, ",", KwargParameter, "," => ActionFn(1663); + __reduce649(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) + } + 650 => { + // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter, ",", KwargParameter, "," => ActionFn(1667); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant9(__symbols); @@ -16030,15 +16039,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1663::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1667::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 220) } - 650 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter, ",", KwargParameter, "," => ActionFn(1664); + 651 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter, ",", KwargParameter, "," => ActionFn(1668); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant0(__symbols); let __sym7 = __pop_Variant9(__symbols); @@ -16051,15 +16060,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = match super::__action1664::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { + let __nt = match super::__action1668::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (9, 220) } - 651 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter, ",", KwargParameter, "," => ActionFn(1665); + 652 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter, ",", KwargParameter, "," => ActionFn(1669); assert!(__symbols.len() >= 10); let __sym9 = __pop_Variant0(__symbols); let __sym8 = __pop_Variant9(__symbols); @@ -16073,15 +16082,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym9.2; - let __nt = match super::__action1665::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { + let __nt = match super::__action1669::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (10, 220) } - 652 => { - // ParameterList = OneOrMore>, ",", "*", ",", KwargParameter, "," => ActionFn(1666); + 653 => { + // ParameterList = OneOrMore>, ",", "*", ",", KwargParameter, "," => ActionFn(1670); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant9(__symbols); @@ -16091,15 +16100,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1666::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1670::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 220) } - 653 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", ",", KwargParameter, "," => ActionFn(1667); + 654 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", ",", KwargParameter, "," => ActionFn(1671); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant0(__symbols); let __sym6 = __pop_Variant9(__symbols); @@ -16111,15 +16120,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1667::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1671::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 220) } - 654 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ",", KwargParameter, "," => ActionFn(1668); + 655 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ",", KwargParameter, "," => ActionFn(1672); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant0(__symbols); let __sym7 = __pop_Variant9(__symbols); @@ -16132,15 +16141,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = match super::__action1668::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { + let __nt = match super::__action1672::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (9, 220) } - 655 => { - // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1669); + 656 => { + // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1673); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant0(__symbols); let __sym6 = __pop_Variant9(__symbols); @@ -16152,15 +16161,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1669::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1673::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 220) } - 656 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1670); + 657 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1674); assert!(__symbols.len() >= 10); let __sym9 = __pop_Variant0(__symbols); let __sym8 = __pop_Variant9(__symbols); @@ -16174,15 +16183,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym9.2; - let __nt = match super::__action1670::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { + let __nt = match super::__action1674::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (10, 220) } - 657 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1671); + 658 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1675); assert!(__symbols.len() >= 11); let __sym10 = __pop_Variant0(__symbols); let __sym9 = __pop_Variant9(__symbols); @@ -16197,15 +16206,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym10.2; - let __nt = match super::__action1671::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9, __sym10) { + let __nt = match super::__action1675::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9, __sym10) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (11, 220) } - 658 => { - // ParameterList = OneOrMore>, ",", "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1672); + 659 => { + // ParameterList = OneOrMore>, ",", "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1676); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant9(__symbols); @@ -16216,15 +16225,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1672::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1676::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 220) } - 659 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1673); + 660 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1677); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant0(__symbols); let __sym7 = __pop_Variant9(__symbols); @@ -16237,15 +16246,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = match super::__action1673::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { + let __nt = match super::__action1677::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (9, 220) } - 660 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1674); + 661 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1678); assert!(__symbols.len() >= 10); let __sym9 = __pop_Variant0(__symbols); let __sym8 = __pop_Variant9(__symbols); @@ -16259,15 +16268,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym9.2; - let __nt = match super::__action1674::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { + let __nt = match super::__action1678::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (10, 220) } - 661 => { - // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter, "," => ActionFn(1675); + 662 => { + // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter, "," => ActionFn(1679); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant63(__symbols); @@ -16276,15 +16285,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1675::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1679::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 220) } - 662 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter, "," => ActionFn(1676); + 663 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter, "," => ActionFn(1680); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant63(__symbols); @@ -16295,15 +16304,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1676::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1680::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 220) } - 663 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter, "," => ActionFn(1677); + 664 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter, "," => ActionFn(1681); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant0(__symbols); let __sym6 = __pop_Variant63(__symbols); @@ -16315,15 +16324,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1677::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1681::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 220) } - 664 => { - // ParameterList = OneOrMore>, ",", "*", "," => ActionFn(1678); + 665 => { + // ParameterList = OneOrMore>, ",", "*", "," => ActionFn(1682); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -16331,15 +16340,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1678::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1682::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 220) } - 665 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", "," => ActionFn(1679); + 666 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", "," => ActionFn(1683); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -16349,15 +16358,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1679::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1683::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 220) } - 666 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", "," => ActionFn(1680); + 667 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", "," => ActionFn(1684); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -16368,15 +16377,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1680::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1684::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 220) } - 667 => { - // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter, ("," >)+, "," => ActionFn(1681); + 668 => { + // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter, ("," >)+, "," => ActionFn(1685); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant12(__symbols); @@ -16386,15 +16395,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1681::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1685::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 220) } - 668 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter, ("," >)+, "," => ActionFn(1682); + 669 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter, ("," >)+, "," => ActionFn(1686); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant0(__symbols); let __sym6 = __pop_Variant12(__symbols); @@ -16406,15 +16415,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1682::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1686::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 220) } - 669 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter, ("," >)+, "," => ActionFn(1683); + 670 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter, ("," >)+, "," => ActionFn(1687); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant0(__symbols); let __sym7 = __pop_Variant12(__symbols); @@ -16427,15 +16436,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = match super::__action1683::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { + let __nt = match super::__action1687::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (9, 220) } - 670 => { - // ParameterList = OneOrMore>, ",", "*", ("," >)+, "," => ActionFn(1684); + 671 => { + // ParameterList = OneOrMore>, ",", "*", ("," >)+, "," => ActionFn(1688); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant12(__symbols); @@ -16444,15 +16453,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1684::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1688::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 220) } - 671 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+, "," => ActionFn(1685); + 672 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+, "," => ActionFn(1689); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant12(__symbols); @@ -16463,15 +16472,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1685::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1689::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 220) } - 672 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+, "," => ActionFn(1686); + 673 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+, "," => ActionFn(1690); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant0(__symbols); let __sym6 = __pop_Variant12(__symbols); @@ -16483,29 +16492,29 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1686::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1690::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 220) } - 673 => { - // ParameterList = OneOrMore>, "," => ActionFn(1687); + 674 => { + // ParameterList = OneOrMore>, "," => ActionFn(1691); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1687::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1691::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (2, 220) } - 674 => { - // ParameterList = OneOrMore>, ",", "/", "," => ActionFn(1688); + 675 => { + // ParameterList = OneOrMore>, ",", "/", "," => ActionFn(1692); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -16513,15 +16522,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1688::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1692::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 220) } - 675 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, "," => ActionFn(1689); + 676 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, "," => ActionFn(1693); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant12(__symbols); @@ -16530,15 +16539,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1689::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1693::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 220) } - 676 => { - // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter, ",", KwargParameter => ActionFn(1690); + 677 => { + // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter, ",", KwargParameter => ActionFn(1694); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant9(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -16548,15 +16557,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1690::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1694::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 220) } - 677 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter, ",", KwargParameter => ActionFn(1691); + 678 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter, ",", KwargParameter => ActionFn(1695); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant9(__symbols); let __sym6 = __pop_Variant0(__symbols); @@ -16568,15 +16577,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1691::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1695::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 220) } - 678 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter, ",", KwargParameter => ActionFn(1692); + 679 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter, ",", KwargParameter => ActionFn(1696); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant9(__symbols); let __sym7 = __pop_Variant0(__symbols); @@ -16589,15 +16598,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = match super::__action1692::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { + let __nt = match super::__action1696::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (9, 220) } - 679 => { - // ParameterList = OneOrMore>, ",", "*", ",", KwargParameter => ActionFn(1693); + 680 => { + // ParameterList = OneOrMore>, ",", "*", ",", KwargParameter => ActionFn(1697); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -16606,15 +16615,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1693::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1697::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 220) } - 680 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", ",", KwargParameter => ActionFn(1694); + 681 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", ",", KwargParameter => ActionFn(1698); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant9(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -16625,15 +16634,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1694::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1698::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 220) } - 681 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ",", KwargParameter => ActionFn(1695); + 682 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ",", KwargParameter => ActionFn(1699); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant9(__symbols); let __sym6 = __pop_Variant0(__symbols); @@ -16645,15 +16654,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1695::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1699::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 220) } - 682 => { - // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1696); + 683 => { + // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1700); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant9(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -16664,15 +16673,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1696::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1700::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 220) } - 683 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1697); + 684 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1701); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant9(__symbols); let __sym7 = __pop_Variant0(__symbols); @@ -16685,15 +16694,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = match super::__action1697::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { + let __nt = match super::__action1701::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (9, 220) } - 684 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1698); + 685 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1702); assert!(__symbols.len() >= 10); let __sym9 = __pop_Variant9(__symbols); let __sym8 = __pop_Variant0(__symbols); @@ -16707,15 +16716,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym9.2; - let __nt = match super::__action1698::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { + let __nt = match super::__action1702::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (10, 220) } - 685 => { - // ParameterList = OneOrMore>, ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1699); + 686 => { + // ParameterList = OneOrMore>, ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1703); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant9(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -16725,15 +16734,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1699::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1703::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 220) } - 686 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1700); + 687 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1704); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant9(__symbols); let __sym6 = __pop_Variant0(__symbols); @@ -16745,15 +16754,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1700::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1704::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 220) } - 687 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1701); + 688 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+, ",", KwargParameter => ActionFn(1705); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant9(__symbols); let __sym7 = __pop_Variant0(__symbols); @@ -16766,15 +16775,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = match super::__action1701::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { + let __nt = match super::__action1705::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (9, 220) } - 688 => { - // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter => ActionFn(1702); + 689 => { + // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter => ActionFn(1706); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -16782,15 +16791,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1702::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1706::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 220) } - 689 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter => ActionFn(1703); + 690 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter => ActionFn(1707); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant63(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -16800,15 +16809,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1703::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1707::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 220) } - 690 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter => ActionFn(1704); + 691 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter => ActionFn(1708); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant63(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -16819,30 +16828,30 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1704::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1708::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 220) } - 691 => { - // ParameterList = OneOrMore>, ",", "*" => ActionFn(1705); + 692 => { + // ParameterList = OneOrMore>, ",", "*" => ActionFn(1709); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1705::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1709::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (3, 220) } - 692 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*" => ActionFn(1706); + 693 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*" => ActionFn(1710); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -16851,15 +16860,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1706::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1710::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 220) } - 693 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*" => ActionFn(1707); + 694 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*" => ActionFn(1711); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -16869,15 +16878,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1707::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1711::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 220) } - 694 => { - // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter, ("," >)+ => ActionFn(1708); + 695 => { + // ParameterList = OneOrMore>, ",", "*", StarUntypedParameter, ("," >)+ => ActionFn(1712); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant12(__symbols); let __sym3 = __pop_Variant63(__symbols); @@ -16886,15 +16895,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1708::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1712::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 220) } - 695 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter, ("," >)+ => ActionFn(1709); + 696 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", StarUntypedParameter, ("," >)+ => ActionFn(1713); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant12(__symbols); let __sym5 = __pop_Variant63(__symbols); @@ -16905,15 +16914,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1709::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1713::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 220) } - 696 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter, ("," >)+ => ActionFn(1710); + 697 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", StarUntypedParameter, ("," >)+ => ActionFn(1714); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant12(__symbols); let __sym6 = __pop_Variant63(__symbols); @@ -16925,15 +16934,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = match super::__action1710::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { + let __nt = match super::__action1714::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (8, 220) } - 697 => { - // ParameterList = OneOrMore>, ",", "*", ("," >)+ => ActionFn(1711); + 698 => { + // ParameterList = OneOrMore>, ",", "*", ("," >)+ => ActionFn(1715); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -16941,15 +16950,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1711::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1715::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 220) } - 698 => { - // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+ => ActionFn(1712); + 699 => { + // ParameterList = OneOrMore>, ",", "/", ",", "*", ("," >)+ => ActionFn(1716); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant12(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -16959,15 +16968,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1712::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1716::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 220) } - 699 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+ => ActionFn(1713); + 700 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", "*", ("," >)+ => ActionFn(1717); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant12(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -16978,42 +16987,42 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1713::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1717::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 220) } - 700 => { - // ParameterList = OneOrMore> => ActionFn(1714); + 701 => { + // ParameterList = OneOrMore> => ActionFn(1718); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = match super::__action1714::<>(source_code, mode, __sym0) { + let __nt = match super::__action1718::<>(source_code, mode, __sym0) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (1, 220) } - 701 => { - // ParameterList = OneOrMore>, ",", "/" => ActionFn(1715); + 702 => { + // ParameterList = OneOrMore>, ",", "/" => ActionFn(1719); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1715::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1719::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (3, 220) } - 702 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+ => ActionFn(1716); + 703 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+ => ActionFn(1720); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -17021,15 +17030,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1716::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1720::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 220) } - 703 => { - // ParameterList = OneOrMore>, ",", KwargParameter, "," => ActionFn(1717); + 704 => { + // ParameterList = OneOrMore>, ",", KwargParameter, "," => ActionFn(1721); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant9(__symbols); @@ -17037,15 +17046,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1717::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1721::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 220) } - 704 => { - // ParameterList = OneOrMore>, ",", "/", ",", KwargParameter, "," => ActionFn(1718); + 705 => { + // ParameterList = OneOrMore>, ",", "/", ",", KwargParameter, "," => ActionFn(1722); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant9(__symbols); @@ -17055,15 +17064,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1718::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1722::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 220) } - 705 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", KwargParameter, "," => ActionFn(1719); + 706 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", KwargParameter, "," => ActionFn(1723); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant9(__symbols); @@ -17074,30 +17083,30 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = match super::__action1719::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { + let __nt = match super::__action1723::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (7, 220) } - 706 => { - // ParameterList = OneOrMore>, ",", KwargParameter => ActionFn(1720); + 707 => { + // ParameterList = OneOrMore>, ",", KwargParameter => ActionFn(1724); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant9(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1720::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1724::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (3, 220) } - 707 => { - // ParameterList = OneOrMore>, ",", "/", ",", KwargParameter => ActionFn(1721); + 708 => { + // ParameterList = OneOrMore>, ",", "/", ",", KwargParameter => ActionFn(1725); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -17106,15 +17115,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1721::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1725::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 220) } - 708 => { - // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", KwargParameter => ActionFn(1722); + 709 => { + // ParameterList = OneOrMore>, ",", "/", ("," >)+, ",", KwargParameter => ActionFn(1726); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant9(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -17124,15 +17133,15 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1722::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1726::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 220) } - 709 => { - // ParameterList = "*", StarUntypedParameter, ",", KwargParameter, "," => ActionFn(1440); + 710 => { + // ParameterList = "*", StarUntypedParameter, ",", KwargParameter, "," => ActionFn(1442); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant9(__symbols); @@ -17141,15 +17150,15 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1440::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1442::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 220) } - 710 => { - // ParameterList = "*", ",", KwargParameter, "," => ActionFn(1441); + 711 => { + // ParameterList = "*", ",", KwargParameter, "," => ActionFn(1443); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant9(__symbols); @@ -17157,15 +17166,15 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1441::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1443::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 220) } - 711 => { - // ParameterList = "*", StarUntypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1442); + 712 => { + // ParameterList = "*", StarUntypedParameter, ("," >)+, ",", KwargParameter, "," => ActionFn(1444); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant9(__symbols); @@ -17175,15 +17184,15 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = match super::__action1442::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { + let __nt = match super::__action1444::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (6, 220) } - 712 => { - // ParameterList = "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1443); + 713 => { + // ParameterList = "*", ("," >)+, ",", KwargParameter, "," => ActionFn(1445); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant9(__symbols); @@ -17192,44 +17201,44 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1443::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1445::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 220) } - 713 => { - // ParameterList = "*", StarUntypedParameter, "," => ActionFn(1444); + 714 => { + // ParameterList = "*", StarUntypedParameter, "," => ActionFn(1446); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant63(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1444::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1446::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (3, 220) } - 714 => { - // ParameterList = "*", "," => ActionFn(1445); + 715 => { + // ParameterList = "*", "," => ActionFn(1447); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1445::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1447::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (2, 220) } - 715 => { - // ParameterList = "*", StarUntypedParameter, ("," >)+, "," => ActionFn(1446); + 716 => { + // ParameterList = "*", StarUntypedParameter, ("," >)+, "," => ActionFn(1448); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant12(__symbols); @@ -17237,30 +17246,30 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1446::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1448::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 220) } - 716 => { - // ParameterList = "*", ("," >)+, "," => ActionFn(1447); + 717 => { + // ParameterList = "*", ("," >)+, "," => ActionFn(1449); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant12(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1447::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1449::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (3, 220) } - 717 => { - // ParameterList = "*", StarUntypedParameter, ",", KwargParameter => ActionFn(1448); + 718 => { + // ParameterList = "*", StarUntypedParameter, ",", KwargParameter => ActionFn(1450); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant9(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -17268,30 +17277,30 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1448::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1450::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 220) } - 718 => { - // ParameterList = "*", ",", KwargParameter => ActionFn(1449); + 719 => { + // ParameterList = "*", ",", KwargParameter => ActionFn(1451); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant9(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1449::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1451::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (3, 220) } - 719 => { - // ParameterList = "*", StarUntypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1450); + 720 => { + // ParameterList = "*", StarUntypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1452); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -17300,15 +17309,15 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1450::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1452::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (5, 220) } - 720 => { - // ParameterList = "*", ("," >)+, ",", KwargParameter => ActionFn(1451); + 721 => { + // ParameterList = "*", ("," >)+, ",", KwargParameter => ActionFn(1453); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant9(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -17316,71 +17325,68 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1451::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1453::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (4, 220) } - 721 => { - // ParameterList = "*", StarUntypedParameter => ActionFn(1452); + 722 => { + // ParameterList = "*", StarUntypedParameter => ActionFn(1454); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant63(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1452::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1454::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (2, 220) } - 722 => { - // ParameterList = "*" => ActionFn(1453); + 723 => { + // ParameterList = "*" => ActionFn(1455); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = match super::__action1453::<>(source_code, mode, __sym0) { + let __nt = match super::__action1455::<>(source_code, mode, __sym0) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (1, 220) } - 723 => { - // ParameterList = "*", StarUntypedParameter, ("," >)+ => ActionFn(1454); + 724 => { + // ParameterList = "*", StarUntypedParameter, ("," >)+ => ActionFn(1456); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant12(__symbols); let __sym1 = __pop_Variant63(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1454::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1456::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (3, 220) } - 724 => { - // ParameterList = "*", ("," >)+ => ActionFn(1455); + 725 => { + // ParameterList = "*", ("," >)+ => ActionFn(1457); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant12(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1455::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1457::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (2, 220) } - 725 => { - __reduce725(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) - } 726 => { __reduce726(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } @@ -17391,7 +17397,10 @@ mod __parse__Top { __reduce728(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 729 => { - // ParameterListStarArgs = "*", StarTypedParameter, ",", KwargParameter => ActionFn(891); + __reduce729(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) + } + 730 => { + // ParameterListStarArgs = "*", StarTypedParameter, ",", KwargParameter => ActionFn(892); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant9(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -17399,30 +17408,30 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action891::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action892::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (4, 222) } - 730 => { - // ParameterListStarArgs = "*", ",", KwargParameter => ActionFn(892); + 731 => { + // ParameterListStarArgs = "*", ",", KwargParameter => ActionFn(893); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant9(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action892::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action893::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (3, 222) } - 731 => { - // ParameterListStarArgs = "*", StarTypedParameter, ("," >)+, ",", KwargParameter => ActionFn(893); + 732 => { + // ParameterListStarArgs = "*", StarTypedParameter, ("," >)+, ",", KwargParameter => ActionFn(894); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -17431,15 +17440,15 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action893::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action894::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (5, 222) } - 732 => { - // ParameterListStarArgs = "*", ("," >)+, ",", KwargParameter => ActionFn(894); + 733 => { + // ParameterListStarArgs = "*", ("," >)+, ",", KwargParameter => ActionFn(895); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant9(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -17447,70 +17456,70 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action894::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action895::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (4, 222) } - 733 => { - // ParameterListStarArgs = "*", StarTypedParameter => ActionFn(895); + 734 => { + // ParameterListStarArgs = "*", StarTypedParameter => ActionFn(896); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant63(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action895::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action896::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (2, 222) } - 734 => { - // ParameterListStarArgs = "*" => ActionFn(896); + 735 => { + // ParameterListStarArgs = "*" => ActionFn(897); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = match super::__action896::<>(source_code, mode, __sym0) { + let __nt = match super::__action897::<>(source_code, mode, __sym0) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (1, 222) } - 735 => { - // ParameterListStarArgs = "*", StarTypedParameter, ("," >)+ => ActionFn(897); + 736 => { + // ParameterListStarArgs = "*", StarTypedParameter, ("," >)+ => ActionFn(898); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant12(__symbols); let __sym1 = __pop_Variant63(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action897::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action898::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (3, 222) } - 736 => { - // ParameterListStarArgs = "*", ("," >)+ => ActionFn(898); + 737 => { + // ParameterListStarArgs = "*", ("," >)+ => ActionFn(899); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant12(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action898::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action899::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (2, 222) } - 737 => { - // ParameterListStarArgs = "*", StarUntypedParameter, ",", KwargParameter => ActionFn(1018); + 738 => { + // ParameterListStarArgs = "*", StarUntypedParameter, ",", KwargParameter => ActionFn(1021); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant9(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -17518,30 +17527,30 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1018::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1021::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (4, 223) } - 738 => { - // ParameterListStarArgs = "*", ",", KwargParameter => ActionFn(1019); + 739 => { + // ParameterListStarArgs = "*", ",", KwargParameter => ActionFn(1022); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant9(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1019::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1022::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (3, 223) } - 739 => { - // ParameterListStarArgs = "*", StarUntypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1020); + 740 => { + // ParameterListStarArgs = "*", StarUntypedParameter, ("," >)+, ",", KwargParameter => ActionFn(1023); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant9(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -17550,15 +17559,15 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = match super::__action1020::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { + let __nt = match super::__action1023::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (5, 223) } - 740 => { - // ParameterListStarArgs = "*", ("," >)+, ",", KwargParameter => ActionFn(1021); + 741 => { + // ParameterListStarArgs = "*", ("," >)+, ",", KwargParameter => ActionFn(1024); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant9(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -17566,100 +17575,97 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = match super::__action1021::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { + let __nt = match super::__action1024::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (4, 223) } - 741 => { - // ParameterListStarArgs = "*", StarUntypedParameter => ActionFn(1022); + 742 => { + // ParameterListStarArgs = "*", StarUntypedParameter => ActionFn(1025); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant63(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1022::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1025::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (2, 223) } - 742 => { - // ParameterListStarArgs = "*" => ActionFn(1023); + 743 => { + // ParameterListStarArgs = "*" => ActionFn(1026); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = match super::__action1023::<>(source_code, mode, __sym0) { + let __nt = match super::__action1026::<>(source_code, mode, __sym0) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (1, 223) } - 743 => { - // ParameterListStarArgs = "*", StarUntypedParameter, ("," >)+ => ActionFn(1024); + 744 => { + // ParameterListStarArgs = "*", StarUntypedParameter, ("," >)+ => ActionFn(1027); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant12(__symbols); let __sym1 = __pop_Variant63(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1024::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1027::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (3, 223) } - 744 => { - // ParameterListStarArgs = "*", ("," >)+ => ActionFn(1025); + 745 => { + // ParameterListStarArgs = "*", ("," >)+ => ActionFn(1028); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant12(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1025::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1028::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant13(__nt), __end)); (2, 223) } - 745 => { - // Parameters = "(", ParameterList, ")" => ActionFn(1458); + 746 => { + // Parameters = "(", ParameterList, ")" => ActionFn(1460); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant46(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = match super::__action1458::<>(source_code, mode, __sym0, __sym1, __sym2) { + let __nt = match super::__action1460::<>(source_code, mode, __sym0, __sym1, __sym2) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (3, 224) } - 746 => { - // Parameters = "(", ")" => ActionFn(1459); + 747 => { + // Parameters = "(", ")" => ActionFn(1461); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = match super::__action1459::<>(source_code, mode, __sym0, __sym1) { + let __nt = match super::__action1461::<>(source_code, mode, __sym0, __sym1) { Ok(v) => v, Err(e) => return Some(Err(e)), }; __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (2, 224) } - 747 => { - __reduce747(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) - } 748 => { __reduce748(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } @@ -17919,25 +17925,34 @@ mod __parse__Top { __reduce833(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 834 => { - // StringLiteral = string => ActionFn(934); - let __sym0 = __pop_Variant7(__symbols); + __reduce834(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) + } + 835 => { + __reduce835(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) + } + 836 => { + // String = TwoOrMore => ActionFn(1493); + let __sym0 = __pop_Variant96(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = match super::__action934::<>(source_code, mode, __sym0) { + let __nt = match super::__action1493::<>(source_code, mode, __sym0) { Ok(v) => v, Err(e) => return Some(Err(e)), }; - __symbols.push((__start, __Symbol::Variant69(__nt), __end)); + __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (1, 251) } - 835 => { - __reduce835(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) - } - 836 => { - __reduce836(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) - } 837 => { - __reduce837(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) + // StringLiteral = string => ActionFn(1494); + let __sym0 = __pop_Variant7(__symbols); + let __start = __sym0.0; + let __end = __sym0.2; + let __nt = match super::__action1494::<>(source_code, mode, __sym0) { + Ok(v) => v, + Err(e) => return Some(Err(e)), + }; + __symbols.push((__start, __Symbol::Variant69(__nt), __end)); + (1, 252) } 838 => { __reduce838(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) @@ -18270,18 +18285,27 @@ mod __parse__Top { __reduce947(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } 948 => { + __reduce948(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) + } + 949 => { + __reduce949(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) + } + 950 => { + __reduce950(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) + } + 951 => { // __Top = Top => ActionFn(0); - let __sym0 = __pop_Variant96(__symbols); + let __sym0 = __pop_Variant95(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action0::<>(source_code, mode, __sym0); return Some(Ok(__nt)); } - 949 => { - __reduce949(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) + 952 => { + __reduce952(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } - 950 => { - __reduce950(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) + 953 => { + __reduce953(source_code, mode, __lookahead_start, __symbols, core::marker::PhantomData::<()>) } _ => panic!("invalid action code {}", __action) }; @@ -18556,6 +18580,16 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } + fn __pop_Variant96< + >( + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> + ) -> (TextSize, Vec, TextSize) + { + match __symbols.pop() { + Some((__l, __Symbol::Variant96(__v), __r)) => (__l, __v, __r), + _ => __symbol_type_mismatch() + } + } fn __pop_Variant73< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> @@ -18696,16 +18730,6 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant95< - >( - __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, alloc::vec::Vec, TextSize) - { - match __symbols.pop() { - Some((__l, __Symbol::Variant95(__v), __r)) => (__l, __v, __r), - _ => __symbol_type_mismatch() - } - } fn __pop_Variant91< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> @@ -18916,13 +18940,13 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant96< + fn __pop_Variant95< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, ast::Mod, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant96(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant95(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -19325,11 +19349,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ","? = "," => ActionFn(381); + // ","? = "," => ActionFn(384); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action381::<>(source_code, mode, __sym0); + let __nt = super::__action384::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant8(__nt), __end)); (1, 0) } @@ -19342,10 +19366,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ","? = => ActionFn(382); + // ","? = => ActionFn(385); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action382::<>(source_code, mode, &__start, &__end); + let __nt = super::__action385::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant8(__nt), __end)); (0, 0) } @@ -19358,11 +19382,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ";"? = ";" => ActionFn(405); + // ";"? = ";" => ActionFn(408); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action405::<>(source_code, mode, __sym0); + let __nt = super::__action408::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant8(__nt), __end)); (1, 1) } @@ -19375,10 +19399,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ";"? = => ActionFn(406); + // ";"? = => ActionFn(409); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action406::<>(source_code, mode, &__start, &__end); + let __nt = super::__action409::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant8(__nt), __end)); (0, 1) } @@ -19391,11 +19415,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // "="? = "=" => ActionFn(268); + // "="? = "=" => ActionFn(271); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action268::<>(source_code, mode, __sym0); + let __nt = super::__action271::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant8(__nt), __end)); (1, 2) } @@ -19408,10 +19432,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // "="? = => ActionFn(269); + // "="? = => ActionFn(272); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action269::<>(source_code, mode, &__start, &__end); + let __nt = super::__action272::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant8(__nt), __end)); (0, 2) } @@ -19424,11 +19448,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // "async"? = "async" => ActionFn(332); + // "async"? = "async" => ActionFn(337); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action332::<>(source_code, mode, __sym0); + let __nt = super::__action337::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant8(__nt), __end)); (1, 3) } @@ -19441,10 +19465,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // "async"? = => ActionFn(333); + // "async"? = => ActionFn(338); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action333::<>(source_code, mode, &__start, &__end); + let __nt = super::__action338::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant8(__nt), __end)); (0, 3) } @@ -19457,13 +19481,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >) = ",", KwargParameter => ActionFn(437); + // ("," >) = ",", KwargParameter => ActionFn(440); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant9(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action437::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action440::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant9(__nt), __end)); (2, 4) } @@ -19476,13 +19500,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)? = ",", KwargParameter => ActionFn(686); + // ("," >)? = ",", KwargParameter => ActionFn(689); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant9(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action686::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action689::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant10(__nt), __end)); (2, 5) } @@ -19495,10 +19519,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)? = => ActionFn(490); + // ("," >)? = => ActionFn(493); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action490::<>(source_code, mode, &__start, &__end); + let __nt = super::__action493::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant10(__nt), __end)); (0, 5) } @@ -19511,13 +19535,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >) = ",", KwargParameter => ActionFn(445); + // ("," >) = ",", KwargParameter => ActionFn(448); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant9(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action445::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action448::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant9(__nt), __end)); (2, 6) } @@ -19530,13 +19554,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)? = ",", KwargParameter => ActionFn(691); + // ("," >)? = ",", KwargParameter => ActionFn(694); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant9(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action691::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action694::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant10(__nt), __end)); (2, 7) } @@ -19549,10 +19573,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)? = => ActionFn(479); + // ("," >)? = => ActionFn(482); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action479::<>(source_code, mode, &__start, &__end); + let __nt = super::__action482::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant10(__nt), __end)); (0, 7) } @@ -19565,13 +19589,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >) = ",", ParameterDef => ActionFn(493); + // ("," >) = ",", ParameterDef => ActionFn(496); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant11(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action493::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action496::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant11(__nt), __end)); (2, 8) } @@ -19584,10 +19608,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)* = => ActionFn(491); + // ("," >)* = => ActionFn(494); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action491::<>(source_code, mode, &__start, &__end); + let __nt = super::__action494::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant12(__nt), __end)); (0, 9) } @@ -19600,11 +19624,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)* = ("," >)+ => ActionFn(492); + // ("," >)* = ("," >)+ => ActionFn(495); let __sym0 = __pop_Variant12(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action492::<>(source_code, mode, __sym0); + let __nt = super::__action495::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant12(__nt), __end)); (1, 9) } @@ -19617,13 +19641,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)+ = ",", ParameterDef => ActionFn(696); + // ("," >)+ = ",", ParameterDef => ActionFn(699); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant11(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action696::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action699::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant12(__nt), __end)); (2, 10) } @@ -19636,14 +19660,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)+ = ("," >)+, ",", ParameterDef => ActionFn(697); + // ("," >)+ = ("," >)+, ",", ParameterDef => ActionFn(700); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant11(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant12(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action697::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action700::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant12(__nt), __end)); (3, 10) } @@ -19656,13 +19680,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >) = ",", ParameterDef => ActionFn(482); + // ("," >) = ",", ParameterDef => ActionFn(485); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant11(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action482::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action485::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant11(__nt), __end)); (2, 11) } @@ -19675,10 +19699,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)* = => ActionFn(480); + // ("," >)* = => ActionFn(483); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action480::<>(source_code, mode, &__start, &__end); + let __nt = super::__action483::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant12(__nt), __end)); (0, 12) } @@ -19691,11 +19715,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)* = ("," >)+ => ActionFn(481); + // ("," >)* = ("," >)+ => ActionFn(484); let __sym0 = __pop_Variant12(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action481::<>(source_code, mode, __sym0); + let __nt = super::__action484::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant12(__nt), __end)); (1, 12) } @@ -19708,13 +19732,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)+ = ",", ParameterDef => ActionFn(704); + // ("," >)+ = ",", ParameterDef => ActionFn(707); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant11(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action704::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action707::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant12(__nt), __end)); (2, 13) } @@ -19727,14 +19751,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)+ = ("," >)+, ",", ParameterDef => ActionFn(705); + // ("," >)+ = ("," >)+, ",", ParameterDef => ActionFn(708); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant11(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant12(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action705::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action708::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant12(__nt), __end)); (3, 13) } @@ -19747,10 +19771,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)? = => ActionFn(440); + // ("," >)? = => ActionFn(443); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action440::<>(source_code, mode, &__start, &__end); + let __nt = super::__action443::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant14(__nt), __end)); (0, 15) } @@ -19763,10 +19787,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)? = => ActionFn(448); + // ("," >)? = => ActionFn(451); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action448::<>(source_code, mode, &__start, &__end); + let __nt = super::__action451::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant14(__nt), __end)); (0, 17) } @@ -19779,13 +19803,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >) = ",", Test<"all"> => ActionFn(375); + // ("," >) = ",", Test<"all"> => ActionFn(378); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action375::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action378::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 18) } @@ -19798,13 +19822,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)? = ",", Test<"all"> => ActionFn(1076); + // ("," >)? = ",", Test<"all"> => ActionFn(1079); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1076::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1079::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (2, 19) } @@ -19817,10 +19841,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)? = => ActionFn(374); + // ("," >)? = => ActionFn(377); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action374::<>(source_code, mode, &__start, &__end); + let __nt = super::__action377::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (0, 19) } @@ -19833,13 +19857,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," ) = ",", TestOrStarNamedExpr => ActionFn(568); + // ("," ) = ",", TestOrStarNamedExpr => ActionFn(571); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action568::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action571::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 20) } @@ -19852,10 +19876,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," )* = => ActionFn(566); + // ("," )* = => ActionFn(569); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action566::<>(source_code, mode, &__start, &__end); + let __nt = super::__action569::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (0, 21) } @@ -19868,11 +19892,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," )* = ("," )+ => ActionFn(567); + // ("," )* = ("," )+ => ActionFn(570); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action567::<>(source_code, mode, __sym0); + let __nt = super::__action570::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (1, 21) } @@ -19885,13 +19909,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," )+ = ",", TestOrStarNamedExpr => ActionFn(1079); + // ("," )+ = ",", TestOrStarNamedExpr => ActionFn(1082); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1079::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1082::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (2, 22) } @@ -19904,14 +19928,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," )+ = ("," )+, ",", TestOrStarNamedExpr => ActionFn(1080); + // ("," )+ = ("," )+, ",", TestOrStarNamedExpr => ActionFn(1083); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1080::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1083::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (3, 22) } @@ -19924,13 +19948,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >) = ",", WithItem<"all"> => ActionFn(316); + // ("," >) = ",", WithItem<"all"> => ActionFn(321); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant18(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action316::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action321::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant18(__nt), __end)); (2, 23) } @@ -19943,10 +19967,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)* = => ActionFn(314); + // ("," >)* = => ActionFn(319); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action314::<>(source_code, mode, &__start, &__end); + let __nt = super::__action319::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant19(__nt), __end)); (0, 24) } @@ -19959,11 +19983,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)* = ("," >)+ => ActionFn(315); + // ("," >)* = ("," >)+ => ActionFn(320); let __sym0 = __pop_Variant19(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action315::<>(source_code, mode, __sym0); + let __nt = super::__action320::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant19(__nt), __end)); (1, 24) } @@ -19976,13 +20000,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)+ = ",", WithItem<"all"> => ActionFn(1089); + // ("," >)+ = ",", WithItem<"all"> => ActionFn(1092); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant18(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1089::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1092::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant19(__nt), __end)); (2, 25) } @@ -19995,14 +20019,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("," >)+ = ("," >)+, ",", WithItem<"all"> => ActionFn(1090); + // ("," >)+ = ("," >)+, ",", WithItem<"all"> => ActionFn(1093); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant18(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant19(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1090::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1093::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant19(__nt), __end)); (3, 25) } @@ -20015,13 +20039,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("->" >) = "->", Test<"all"> => ActionFn(303); + // ("->" >) = "->", Test<"all"> => ActionFn(308); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action303::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action308::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 26) } @@ -20034,13 +20058,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("->" >)? = "->", Test<"all"> => ActionFn(1095); + // ("->" >)? = "->", Test<"all"> => ActionFn(1098); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1095::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1098::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (2, 27) } @@ -20053,10 +20077,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("->" >)? = => ActionFn(302); + // ("->" >)? = => ActionFn(307); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action302::<>(source_code, mode, &__start, &__end); + let __nt = super::__action307::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (0, 27) } @@ -20069,13 +20093,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("." Identifier) = ".", Identifier => ActionFn(380); + // ("." Identifier) = ".", Identifier => ActionFn(383); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant23(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action380::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action383::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant20(__nt), __end)); (2, 28) } @@ -20088,13 +20112,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("." Identifier)+ = ".", Identifier => ActionFn(1100); + // ("." Identifier)+ = ".", Identifier => ActionFn(1103); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant23(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1100::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1103::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant21(__nt), __end)); (2, 29) } @@ -20107,14 +20131,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("." Identifier)+ = ("." Identifier)+, ".", Identifier => ActionFn(1101); + // ("." Identifier)+ = ("." Identifier)+, ".", Identifier => ActionFn(1104); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant21(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1101::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1104::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant21(__nt), __end)); (3, 29) } @@ -20127,13 +20151,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (":" >) = ":", Test<"all"> => ActionFn(293); + // (":" >) = ":", Test<"all"> => ActionFn(298); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action293::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action298::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 30) } @@ -20146,13 +20170,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (":" >)? = ":", Test<"all"> => ActionFn(1102); + // (":" >)? = ":", Test<"all"> => ActionFn(1105); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1102::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1105::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (2, 31) } @@ -20165,10 +20189,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (":" >)? = => ActionFn(292); + // (":" >)? = => ActionFn(297); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action292::<>(source_code, mode, &__start, &__end); + let __nt = super::__action297::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (0, 31) } @@ -20181,13 +20205,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (":" ) = ":", TestOrStarExpr => ActionFn(290); + // (":" ) = ":", TestOrStarExpr => ActionFn(295); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action290::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action295::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 32) } @@ -20200,13 +20224,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (":" )? = ":", TestOrStarExpr => ActionFn(1109); + // (":" )? = ":", TestOrStarExpr => ActionFn(1112); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1109::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1112::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (2, 33) } @@ -20219,10 +20243,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (":" )? = => ActionFn(289); + // (":" )? = => ActionFn(294); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action289::<>(source_code, mode, &__start, &__end); + let __nt = super::__action294::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (0, 33) } @@ -20235,11 +20259,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("?") = "?" => ActionFn(370); + // ("?") = "?" => ActionFn(373); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action370::<>(source_code, mode, __sym0); + let __nt = super::__action373::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant0(__nt), __end)); (1, 34) } @@ -20252,11 +20276,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("?")+ = "?" => ActionFn(1112); + // ("?")+ = "?" => ActionFn(1115); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1112::<>(source_code, mode, __sym0); + let __nt = super::__action1115::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant22(__nt), __end)); (1, 35) } @@ -20269,13 +20293,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("?")+ = ("?")+, "?" => ActionFn(1113); + // ("?")+ = ("?")+, "?" => ActionFn(1116); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant22(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1113::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1116::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant22(__nt), __end)); (2, 35) } @@ -20288,11 +20312,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("\n") = "\n" => ActionFn(412); + // ("\n") = "\n" => ActionFn(415); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action412::<>(source_code, mode, __sym0); + let __nt = super::__action415::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant0(__nt), __end)); (1, 36) } @@ -20305,10 +20329,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("\n")* = => ActionFn(410); + // ("\n")* = => ActionFn(413); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action410::<>(source_code, mode, &__start, &__end); + let __nt = super::__action413::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant22(__nt), __end)); (0, 37) } @@ -20321,11 +20345,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("\n")* = ("\n")+ => ActionFn(411); + // ("\n")* = ("\n")+ => ActionFn(414); let __sym0 = __pop_Variant22(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action411::<>(source_code, mode, __sym0); + let __nt = super::__action414::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant22(__nt), __end)); (1, 37) } @@ -20338,11 +20362,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("\n")+ = "\n" => ActionFn(1114); + // ("\n")+ = "\n" => ActionFn(1117); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1114::<>(source_code, mode, __sym0); + let __nt = super::__action1117::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant22(__nt), __end)); (1, 38) } @@ -20355,13 +20379,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("\n")+ = ("\n")+, "\n" => ActionFn(1115); + // ("\n")+ = ("\n")+, "\n" => ActionFn(1118); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant22(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1115::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1118::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant22(__nt), __end)); (2, 38) } @@ -20374,13 +20398,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("as" ) = "as", Identifier => ActionFn(423); + // ("as" ) = "as", Identifier => ActionFn(426); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant23(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action423::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action426::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant23(__nt), __end)); (2, 39) } @@ -20393,13 +20417,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("as" )? = "as", Identifier => ActionFn(1118); + // ("as" )? = "as", Identifier => ActionFn(1121); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant23(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1118::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1121::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant24(__nt), __end)); (2, 40) } @@ -20412,10 +20436,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("as" )? = => ActionFn(422); + // ("as" )? = => ActionFn(425); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action422::<>(source_code, mode, &__start, &__end); + let __nt = super::__action425::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant24(__nt), __end)); (0, 40) } @@ -20428,14 +20452,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("else" ":" ) = "else", ":", Suite => ActionFn(336); + // ("else" ":" ) = "else", ":", Suite => ActionFn(341); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant25(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action336::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action341::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant25(__nt), __end)); (3, 41) } @@ -20448,14 +20472,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("else" ":" )? = "else", ":", Suite => ActionFn(1123); + // ("else" ":" )? = "else", ":", Suite => ActionFn(1126); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant25(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1123::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1126::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant26(__nt), __end)); (3, 42) } @@ -20468,10 +20492,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("else" ":" )? = => ActionFn(335); + // ("else" ":" )? = => ActionFn(340); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action335::<>(source_code, mode, &__start, &__end); + let __nt = super::__action340::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant26(__nt), __end)); (0, 42) } @@ -20484,14 +20508,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("finally" ":" ) = "finally", ":", Suite => ActionFn(329); + // ("finally" ":" ) = "finally", ":", Suite => ActionFn(334); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant25(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action329::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action334::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant25(__nt), __end)); (3, 43) } @@ -20504,14 +20528,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("finally" ":" )? = "finally", ":", Suite => ActionFn(1134); + // ("finally" ":" )? = "finally", ":", Suite => ActionFn(1137); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant25(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1134::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1137::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant26(__nt), __end)); (3, 44) } @@ -20524,10 +20548,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("finally" ":" )? = => ActionFn(328); + // ("finally" ":" )? = => ActionFn(333); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action328::<>(source_code, mode, &__start, &__end); + let __nt = super::__action333::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant26(__nt), __end)); (0, 44) } @@ -20540,13 +20564,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("from" >) = "from", Test<"all"> => ActionFn(395); + // ("from" >) = "from", Test<"all"> => ActionFn(398); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action395::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action398::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 45) } @@ -20559,13 +20583,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("from" >)? = "from", Test<"all"> => ActionFn(1144); + // ("from" >)? = "from", Test<"all"> => ActionFn(1147); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1144::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1147::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (2, 46) } @@ -20578,10 +20602,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ("from" >)? = => ActionFn(394); + // ("from" >)? = => ActionFn(397); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action394::<>(source_code, mode, &__start, &__end); + let __nt = super::__action397::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (0, 46) } @@ -20594,7 +20618,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (<@L> "elif" ":" ) = "elif", NamedExpressionTest, ":", Suite => ActionFn(720); + // (<@L> "elif" ":" ) = "elif", NamedExpressionTest, ":", Suite => ActionFn(723); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant25(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -20602,7 +20626,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action720::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action723::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant27(__nt), __end)); (4, 47) } @@ -20615,10 +20639,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (<@L> "elif" ":" )* = => ActionFn(340); + // (<@L> "elif" ":" )* = => ActionFn(345); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action340::<>(source_code, mode, &__start, &__end); + let __nt = super::__action345::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant28(__nt), __end)); (0, 48) } @@ -20631,11 +20655,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (<@L> "elif" ":" )* = (<@L> "elif" ":" )+ => ActionFn(341); + // (<@L> "elif" ":" )* = (<@L> "elif" ":" )+ => ActionFn(346); let __sym0 = __pop_Variant28(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action341::<>(source_code, mode, __sym0); + let __nt = super::__action346::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant28(__nt), __end)); (1, 48) } @@ -20648,7 +20672,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (<@L> "elif" ":" )+ = "elif", NamedExpressionTest, ":", Suite => ActionFn(1147); + // (<@L> "elif" ":" )+ = "elif", NamedExpressionTest, ":", Suite => ActionFn(1150); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant25(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -20656,7 +20680,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1147::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1150::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant28(__nt), __end)); (4, 49) } @@ -20669,7 +20693,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (<@L> "elif" ":" )+ = (<@L> "elif" ":" )+, "elif", NamedExpressionTest, ":", Suite => ActionFn(1148); + // (<@L> "elif" ":" )+ = (<@L> "elif" ":" )+, "elif", NamedExpressionTest, ":", Suite => ActionFn(1151); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant25(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -20678,7 +20702,7 @@ mod __parse__Top { let __sym0 = __pop_Variant28(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1148::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1151::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant28(__nt), __end)); (5, 49) } @@ -20691,14 +20715,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (<@L> "else" ":" ) = "else", ":", Suite => ActionFn(721); + // (<@L> "else" ":" ) = "else", ":", Suite => ActionFn(724); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant25(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action721::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action724::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant29(__nt), __end)); (3, 50) } @@ -20711,14 +20735,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (<@L> "else" ":" )? = "else", ":", Suite => ActionFn(1151); + // (<@L> "else" ":" )? = "else", ":", Suite => ActionFn(1154); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant25(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1151::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1154::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant30(__nt), __end)); (3, 51) } @@ -20731,10 +20755,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (<@L> "else" ":" )? = => ActionFn(338); + // (<@L> "else" ":" )? = => ActionFn(343); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action338::<>(source_code, mode, &__start, &__end); + let __nt = super::__action343::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant30(__nt), __end)); (0, 51) } @@ -20747,13 +20771,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (> "or") = AndTest<"all">, "or" => ActionFn(459); + // (> "or") = AndTest<"all">, "or" => ActionFn(462); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action459::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action462::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 52) } @@ -20766,13 +20790,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (> "or")+ = AndTest<"all">, "or" => ActionFn(1156); + // (> "or")+ = AndTest<"all">, "or" => ActionFn(1159); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1156::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1159::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (2, 53) } @@ -20785,14 +20809,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (> "or")+ = (> "or")+, AndTest<"all">, "or" => ActionFn(1157); + // (> "or")+ = (> "or")+, AndTest<"all">, "or" => ActionFn(1160); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1157::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1160::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (3, 53) } @@ -20805,13 +20829,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ",") = FunctionArgument, "," => ActionFn(468); + // ( ",") = FunctionArgument, "," => ActionFn(471); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant31(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action468::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action471::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant31(__nt), __end)); (2, 54) } @@ -20824,10 +20848,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ",")* = => ActionFn(466); + // ( ",")* = => ActionFn(469); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action466::<>(source_code, mode, &__start, &__end); + let __nt = super::__action469::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant32(__nt), __end)); (0, 55) } @@ -20840,11 +20864,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ",")* = ( ",")+ => ActionFn(467); + // ( ",")* = ( ",")+ => ActionFn(470); let __sym0 = __pop_Variant32(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action467::<>(source_code, mode, __sym0); + let __nt = super::__action470::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant32(__nt), __end)); (1, 55) } @@ -20857,13 +20881,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ",")+ = FunctionArgument, "," => ActionFn(1158); + // ( ",")+ = FunctionArgument, "," => ActionFn(1161); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant31(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1158::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1161::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant32(__nt), __end)); (2, 56) } @@ -20876,14 +20900,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ",")+ = ( ",")+, FunctionArgument, "," => ActionFn(1159); + // ( ",")+ = ( ",")+, FunctionArgument, "," => ActionFn(1162); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant31(__symbols); let __sym0 = __pop_Variant32(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1159::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1162::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant32(__nt), __end)); (3, 56) } @@ -20896,13 +20920,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (> "and") = NotTest<"all">, "and" => ActionFn(473); + // (> "and") = NotTest<"all">, "and" => ActionFn(476); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action473::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action476::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 57) } @@ -20915,13 +20939,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (> "and")+ = NotTest<"all">, "and" => ActionFn(1162); + // (> "and")+ = NotTest<"all">, "and" => ActionFn(1165); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1162::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1165::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (2, 58) } @@ -20934,14 +20958,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (> "and")+ = (> "and")+, NotTest<"all">, "and" => ActionFn(1163); + // (> "and")+ = (> "and")+, NotTest<"all">, "and" => ActionFn(1166); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1163::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1166::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (3, 58) } @@ -20954,13 +20978,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (>> ",") = OneOrMore>, "," => ActionFn(571); + // (>> ",") = OneOrMore>, "," => ActionFn(574); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action571::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action574::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (2, 59) } @@ -20973,13 +20997,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (>> ",")? = OneOrMore>, "," => ActionFn(1164); + // (>> ",")? = OneOrMore>, "," => ActionFn(1167); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1164::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1167::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant34(__nt), __end)); (2, 60) } @@ -20992,10 +21016,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (>> ",")? = => ActionFn(570); + // (>> ",")? = => ActionFn(573); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action570::<>(source_code, mode, &__start, &__end); + let __nt = super::__action573::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant34(__nt), __end)); (0, 60) } @@ -21008,13 +21032,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ",") = Pattern, "," => ActionFn(356); + // ( ",") = Pattern, "," => ActionFn(359); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant35(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action356::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action359::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (2, 61) } @@ -21027,10 +21051,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ",")* = => ActionFn(428); + // ( ",")* = => ActionFn(431); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action428::<>(source_code, mode, &__start, &__end); + let __nt = super::__action431::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant36(__nt), __end)); (0, 62) } @@ -21043,11 +21067,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ",")* = ( ",")+ => ActionFn(429); + // ( ",")* = ( ",")+ => ActionFn(432); let __sym0 = __pop_Variant36(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action429::<>(source_code, mode, __sym0); + let __nt = super::__action432::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant36(__nt), __end)); (1, 62) } @@ -21060,13 +21084,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ",")+ = Pattern, "," => ActionFn(1181); + // ( ",")+ = Pattern, "," => ActionFn(1184); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant35(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1181::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1184::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant36(__nt), __end)); (2, 63) } @@ -21079,14 +21103,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ",")+ = ( ",")+, Pattern, "," => ActionFn(1182); + // ( ",")+ = ( ",")+, Pattern, "," => ActionFn(1185); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant35(__symbols); let __sym0 = __pop_Variant36(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1182::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1185::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant36(__nt), __end)); (3, 63) } @@ -21099,13 +21123,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ";") = SmallStatement, ";" => ActionFn(409); + // ( ";") = SmallStatement, ";" => ActionFn(412); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant37(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action409::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action412::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (2, 64) } @@ -21118,10 +21142,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ";")* = => ActionFn(407); + // ( ";")* = => ActionFn(410); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action407::<>(source_code, mode, &__start, &__end); + let __nt = super::__action410::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant38(__nt), __end)); (0, 65) } @@ -21134,11 +21158,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ";")* = ( ";")+ => ActionFn(408); + // ( ";")* = ( ";")+ => ActionFn(411); let __sym0 = __pop_Variant38(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action408::<>(source_code, mode, __sym0); + let __nt = super::__action411::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant38(__nt), __end)); (1, 65) } @@ -21151,13 +21175,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ";")+ = SmallStatement, ";" => ActionFn(1185); + // ( ";")+ = SmallStatement, ";" => ActionFn(1188); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant37(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1185::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1188::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant38(__nt), __end)); (2, 66) } @@ -21170,14 +21194,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ";")+ = ( ";")+, SmallStatement, ";" => ActionFn(1186); + // ( ";")+ = ( ";")+, SmallStatement, ";" => ActionFn(1189); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant37(__symbols); let __sym0 = __pop_Variant38(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1186::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1189::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant38(__nt), __end)); (3, 66) } @@ -21190,14 +21214,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (> "as" ) = Test<"all">, "as", Identifier => ActionFn(324); + // (> "as" ) = Test<"all">, "as", Identifier => ActionFn(329); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action324::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action329::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant39(__nt), __end)); (3, 67) } @@ -21210,13 +21234,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ",") = OneOrMore>, "," => ActionFn(1205); + // ( ",") = OneOrMore>, "," => ActionFn(1208); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1205::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1208::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); (2, 68) } @@ -21229,13 +21253,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ",")? = OneOrMore>, "," => ActionFn(1208); + // ( ",")? = OneOrMore>, "," => ActionFn(1211); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1208::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1211::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant41(__nt), __end)); (2, 69) } @@ -21248,10 +21272,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ( ",")? = => ActionFn(320); + // ( ",")? = => ActionFn(325); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action320::<>(source_code, mode, &__start, &__end); + let __nt = super::__action325::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant41(__nt), __end)); (0, 69) } @@ -21264,13 +21288,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (CompOp Expression<"all">) = CompOp, Expression<"all"> => ActionFn(516); + // (CompOp Expression<"all">) = CompOp, Expression<"all"> => ActionFn(519); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant56(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action516::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action519::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant42(__nt), __end)); (2, 70) } @@ -21283,13 +21307,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (CompOp Expression<"all">)+ = CompOp, Expression<"all"> => ActionFn(1217); + // (CompOp Expression<"all">)+ = CompOp, Expression<"all"> => ActionFn(1220); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant56(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1217::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1220::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant43(__nt), __end)); (2, 71) } @@ -21302,14 +21326,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (CompOp Expression<"all">)+ = (CompOp Expression<"all">)+, CompOp, Expression<"all"> => ActionFn(1218); + // (CompOp Expression<"all">)+ = (CompOp Expression<"all">)+, CompOp, Expression<"all"> => ActionFn(1221); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant56(__symbols); let __sym0 = __pop_Variant43(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1218::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1221::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant43(__nt), __end)); (3, 71) } @@ -21322,11 +21346,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (Guard) = Guard => ActionFn(363); + // (Guard) = Guard => ActionFn(366); let __sym0 = __pop_Variant44(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action363::<>(source_code, mode, __sym0); + let __nt = super::__action366::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (1, 72) } @@ -21339,11 +21363,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (Guard)? = Guard => ActionFn(1219); + // (Guard)? = Guard => ActionFn(1222); let __sym0 = __pop_Variant44(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1219::<>(source_code, mode, __sym0); + let __nt = super::__action1222::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant45(__nt), __end)); (1, 73) } @@ -21356,10 +21380,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (Guard)? = => ActionFn(362); + // (Guard)? = => ActionFn(365); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action362::<>(source_code, mode, &__start, &__end); + let __nt = super::__action365::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant45(__nt), __end)); (0, 73) } @@ -21372,11 +21396,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (ParameterList) = ParameterList => ActionFn(296); + // (ParameterList) = ParameterList => ActionFn(301); let __sym0 = __pop_Variant46(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action296::<>(source_code, mode, __sym0); + let __nt = super::__action301::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (1, 74) } @@ -21389,11 +21413,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (ParameterList)? = ParameterList => ActionFn(1222); + // (ParameterList)? = ParameterList => ActionFn(1225); let __sym0 = __pop_Variant46(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1222::<>(source_code, mode, __sym0); + let __nt = super::__action1225::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant47(__nt), __end)); (1, 75) } @@ -21406,10 +21430,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // (ParameterList)? = => ActionFn(295); + // (ParameterList)? = => ActionFn(300); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action295::<>(source_code, mode, &__start, &__end); + let __nt = super::__action300::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant47(__nt), __end)); (0, 75) } @@ -21422,10 +21446,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // @L = => ActionFn(414); + // @L = => ActionFn(417); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action414::<>(source_code, mode, &__start, &__end); + let __nt = super::__action417::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant48(__nt), __end)); (0, 76) } @@ -21438,10 +21462,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // @R = => ActionFn(413); + // @R = => ActionFn(416); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action413::<>(source_code, mode, &__start, &__end); + let __nt = super::__action416::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant48(__nt), __end)); (0, 77) } @@ -21454,11 +21478,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AddOp = "+" => ActionFn(196); + // AddOp = "+" => ActionFn(197); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action196::<>(source_code, mode, __sym0); + let __nt = super::__action197::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant49(__nt), __end)); (1, 78) } @@ -21471,11 +21495,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AddOp = "-" => ActionFn(197); + // AddOp = "-" => ActionFn(198); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action197::<>(source_code, mode, __sym0); + let __nt = super::__action198::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant49(__nt), __end)); (1, 78) } @@ -21488,14 +21512,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AddOpExpr = NumberExpr, AddOp, NumberAtom => ActionFn(1225); + // AddOpExpr = NumberExpr, AddOp, NumberAtom => ActionFn(1228); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant49(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1225::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1228::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 79) } @@ -21508,14 +21532,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AndExpression<"all"> = AndExpression<"all">, "&", ShiftExpression<"all"> => ActionFn(1226); + // AndExpression<"all"> = AndExpression<"all">, "&", ShiftExpression<"all"> => ActionFn(1229); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1226::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1229::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 80) } @@ -21528,11 +21552,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AndExpression<"all"> = ShiftExpression<"all"> => ActionFn(503); + // AndExpression<"all"> = ShiftExpression<"all"> => ActionFn(506); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action503::<>(source_code, mode, __sym0); + let __nt = super::__action506::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 80) } @@ -21545,14 +21569,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AndExpression<"no-withitems"> = AndExpression<"all">, "&", ShiftExpression<"all"> => ActionFn(1227); + // AndExpression<"no-withitems"> = AndExpression<"all">, "&", ShiftExpression<"all"> => ActionFn(1230); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1227::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1230::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 81) } @@ -21565,11 +21589,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AndExpression<"no-withitems"> = ShiftExpression<"no-withitems"> => ActionFn(534); + // AndExpression<"no-withitems"> = ShiftExpression<"no-withitems"> => ActionFn(537); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action534::<>(source_code, mode, __sym0); + let __nt = super::__action537::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 81) } @@ -21582,13 +21606,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AndTest<"all"> = (> "and")+, NotTest<"all"> => ActionFn(1228); + // AndTest<"all"> = (> "and")+, NotTest<"all"> => ActionFn(1231); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1228::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1231::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 82) } @@ -21601,11 +21625,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AndTest<"all"> = NotTest<"all"> => ActionFn(461); + // AndTest<"all"> = NotTest<"all"> => ActionFn(464); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action461::<>(source_code, mode, __sym0); + let __nt = super::__action464::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 82) } @@ -21618,13 +21642,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AndTest<"no-withitems"> = (> "and")+, NotTest<"all"> => ActionFn(1229); + // AndTest<"no-withitems"> = (> "and")+, NotTest<"all"> => ActionFn(1232); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1229::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1232::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 83) } @@ -21637,11 +21661,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AndTest<"no-withitems"> = NotTest<"no-withitems"> => ActionFn(507); + // AndTest<"no-withitems"> = NotTest<"no-withitems"> => ActionFn(510); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action507::<>(source_code, mode, __sym0); + let __nt = super::__action510::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 83) } @@ -21654,11 +21678,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Arguments? = Arguments => ActionFn(286); + // Arguments? = Arguments => ActionFn(291); let __sym0 = __pop_Variant50(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action286::<>(source_code, mode, __sym0); + let __nt = super::__action291::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant51(__nt), __end)); (1, 85) } @@ -21671,10 +21695,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Arguments? = => ActionFn(287); + // Arguments? = => ActionFn(292); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action287::<>(source_code, mode, &__start, &__end); + let __nt = super::__action292::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant51(__nt), __end)); (0, 85) } @@ -21687,14 +21711,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ArithmeticExpression<"all"> = ArithmeticExpression<"all">, AddOp, Term<"all"> => ActionFn(1231); + // ArithmeticExpression<"all"> = ArithmeticExpression<"all">, AddOp, Term<"all"> => ActionFn(1234); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant49(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1231::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1234::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 86) } @@ -21707,11 +21731,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ArithmeticExpression<"all"> = Term<"all"> => ActionFn(520); + // ArithmeticExpression<"all"> = Term<"all"> => ActionFn(523); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action520::<>(source_code, mode, __sym0); + let __nt = super::__action523::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 86) } @@ -21724,14 +21748,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ArithmeticExpression<"no-withitems"> = ArithmeticExpression<"all">, AddOp, Term<"all"> => ActionFn(1232); + // ArithmeticExpression<"no-withitems"> = ArithmeticExpression<"all">, AddOp, Term<"all"> => ActionFn(1235); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant49(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1232::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1235::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 87) } @@ -21744,11 +21768,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ArithmeticExpression<"no-withitems"> = Term<"no-withitems"> => ActionFn(544); + // ArithmeticExpression<"no-withitems"> = Term<"no-withitems"> => ActionFn(547); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action544::<>(source_code, mode, __sym0); + let __nt = super::__action547::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 87) } @@ -21761,7 +21785,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AssertStatement = "assert", Test<"all">, ",", Test<"all"> => ActionFn(1234); + // AssertStatement = "assert", Test<"all">, ",", Test<"all"> => ActionFn(1237); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant15(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -21769,7 +21793,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1234::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1237::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (4, 89) } @@ -21782,13 +21806,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AssertStatement = "assert", Test<"all"> => ActionFn(1235); + // AssertStatement = "assert", Test<"all"> => ActionFn(1238); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1235::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1238::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (2, 89) } @@ -21839,10 +21863,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AssignSuffix* = => ActionFn(403); + // AssignSuffix* = => ActionFn(406); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action403::<>(source_code, mode, &__start, &__end); + let __nt = super::__action406::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (0, 91) } @@ -21855,11 +21879,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AssignSuffix* = AssignSuffix+ => ActionFn(404); + // AssignSuffix* = AssignSuffix+ => ActionFn(407); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action404::<>(source_code, mode, __sym0); + let __nt = super::__action407::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (1, 91) } @@ -21872,11 +21896,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AssignSuffix+ = AssignSuffix => ActionFn(419); + // AssignSuffix+ = AssignSuffix => ActionFn(422); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action419::<>(source_code, mode, __sym0); + let __nt = super::__action422::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (1, 92) } @@ -21889,13 +21913,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AssignSuffix+ = AssignSuffix+, AssignSuffix => ActionFn(420); + // AssignSuffix+ = AssignSuffix+, AssignSuffix => ActionFn(423); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action420::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action423::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (2, 92) } @@ -21908,11 +21932,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AssignSuffix? = AssignSuffix => ActionFn(398); + // AssignSuffix? = AssignSuffix => ActionFn(401); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action398::<>(source_code, mode, __sym0); + let __nt = super::__action401::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (1, 93) } @@ -21925,13 +21949,30 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AssignSuffix? = => ActionFn(399); + // AssignSuffix? = => ActionFn(402); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action399::<>(source_code, mode, &__start, &__end); + let __nt = super::__action402::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); (0, 93) } + pub(crate) fn __reduce182< + >( + source_code: &str, + mode: Mode, + __lookahead_start: Option<&TextSize>, + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)>, + _: core::marker::PhantomData<()>, + ) -> (usize, usize) + { + // Atom<"all"> = String => ActionFn(548); + let __sym0 = __pop_Variant44(__symbols); + let __start = __sym0.0; + let __end = __sym0.2; + let __nt = super::__action548::<>(source_code, mode, __sym0); + __symbols.push((__start, __Symbol::Variant15(__nt), __end)); + (1, 94) + } pub(crate) fn __reduce183< >( source_code: &str, @@ -21941,11 +21982,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = Number => ActionFn(1237); + // Atom<"all"> = Number => ActionFn(1239); let __sym0 = __pop_Variant81(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1237::<>(source_code, mode, __sym0); + let __nt = super::__action1239::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 94) } @@ -21958,11 +21999,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = Identifier => ActionFn(1238); + // Atom<"all"> = Identifier => ActionFn(1240); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1238::<>(source_code, mode, __sym0); + let __nt = super::__action1240::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 94) } @@ -21975,14 +22016,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "[", ListLiteralValues, "]" => ActionFn(1599); + // Atom<"all"> = "[", ListLiteralValues, "]" => ActionFn(1603); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant33(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1599::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1603::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 94) } @@ -21995,13 +22036,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "[", "]" => ActionFn(1600); + // Atom<"all"> = "[", "]" => ActionFn(1604); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1600::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1604::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 94) } @@ -22014,7 +22055,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "[", TestOrStarNamedExpr, CompFor, "]" => ActionFn(1240); + // Atom<"all"> = "[", TestOrStarNamedExpr, CompFor, "]" => ActionFn(1242); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant54(__symbols); @@ -22022,7 +22063,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1240::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1242::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (4, 94) } @@ -22035,7 +22076,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "(", OneOrMore>, ",", ")" => ActionFn(1241); + // Atom<"all"> = "(", OneOrMore>, ",", ")" => ActionFn(1243); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -22043,7 +22084,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1241::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1243::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (4, 94) } @@ -22056,14 +22097,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "(", OneOrMore>, ")" => ActionFn(1242); + // Atom<"all"> = "(", OneOrMore>, ")" => ActionFn(1244); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant33(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1242::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1244::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 94) } @@ -22076,13 +22117,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "(", ")" => ActionFn(1251); + // Atom<"all"> = "(", ")" => ActionFn(1253); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1251::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1253::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 94) } @@ -22095,14 +22136,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "(", YieldExpr, ")" => ActionFn(1252); + // Atom<"all"> = "(", YieldExpr, ")" => ActionFn(1254); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1252::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1254::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 94) } @@ -22115,7 +22156,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "(", NamedExpressionTest, CompFor, ")" => ActionFn(1253); + // Atom<"all"> = "(", NamedExpressionTest, CompFor, ")" => ActionFn(1255); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant54(__symbols); @@ -22123,7 +22164,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1253::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1255::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (4, 94) } @@ -22136,14 +22177,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "{", DictLiteralValues, "}" => ActionFn(1567); + // Atom<"all"> = "{", DictLiteralValues, "}" => ActionFn(1571); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant61(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1567::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1571::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 94) } @@ -22156,13 +22197,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "{", "}" => ActionFn(1568); + // Atom<"all"> = "{", "}" => ActionFn(1572); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1568::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1572::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 94) } @@ -22175,7 +22216,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "{", DictEntry, CompFor, "}" => ActionFn(1256); + // Atom<"all"> = "{", DictEntry, CompFor, "}" => ActionFn(1258); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant54(__symbols); @@ -22183,7 +22224,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1256::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1258::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (4, 94) } @@ -22196,14 +22237,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "{", SetLiteralValues, "}" => ActionFn(1257); + // Atom<"all"> = "{", SetLiteralValues, "}" => ActionFn(1259); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant33(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1257::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1259::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 94) } @@ -22216,7 +22257,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "{", NamedExpressionTest, CompFor, "}" => ActionFn(1258); + // Atom<"all"> = "{", NamedExpressionTest, CompFor, "}" => ActionFn(1260); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant54(__symbols); @@ -22224,7 +22265,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1258::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1260::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (4, 94) } @@ -22237,11 +22278,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "True" => ActionFn(1259); + // Atom<"all"> = "True" => ActionFn(1261); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1259::<>(source_code, mode, __sym0); + let __nt = super::__action1261::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 94) } @@ -22254,11 +22295,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "False" => ActionFn(1260); + // Atom<"all"> = "False" => ActionFn(1262); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1260::<>(source_code, mode, __sym0); + let __nt = super::__action1262::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 94) } @@ -22271,11 +22312,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "None" => ActionFn(1261); + // Atom<"all"> = "None" => ActionFn(1263); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1261::<>(source_code, mode, __sym0); + let __nt = super::__action1263::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 94) } @@ -22288,14 +22329,31 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"all"> = "..." => ActionFn(1262); + // Atom<"all"> = "..." => ActionFn(1264); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1262::<>(source_code, mode, __sym0); + let __nt = super::__action1264::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 94) } + pub(crate) fn __reduce211< + >( + source_code: &str, + mode: Mode, + __lookahead_start: Option<&TextSize>, + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)>, + _: core::marker::PhantomData<()>, + ) -> (usize, usize) + { + // Atom<"no-withitems"> = String => ActionFn(591); + let __sym0 = __pop_Variant44(__symbols); + let __start = __sym0.0; + let __end = __sym0.2; + let __nt = super::__action591::<>(source_code, mode, __sym0); + __symbols.push((__start, __Symbol::Variant15(__nt), __end)); + (1, 95) + } pub(crate) fn __reduce212< >( source_code: &str, @@ -22305,11 +22363,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = Number => ActionFn(1264); + // Atom<"no-withitems"> = Number => ActionFn(1265); let __sym0 = __pop_Variant81(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1264::<>(source_code, mode, __sym0); + let __nt = super::__action1265::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 95) } @@ -22322,11 +22380,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = Identifier => ActionFn(1265); + // Atom<"no-withitems"> = Identifier => ActionFn(1266); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1265::<>(source_code, mode, __sym0); + let __nt = super::__action1266::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 95) } @@ -22339,14 +22397,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = "[", ListLiteralValues, "]" => ActionFn(1601); + // Atom<"no-withitems"> = "[", ListLiteralValues, "]" => ActionFn(1605); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant33(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1601::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1605::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 95) } @@ -22359,13 +22417,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = "[", "]" => ActionFn(1602); + // Atom<"no-withitems"> = "[", "]" => ActionFn(1606); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1602::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1606::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 95) } @@ -22378,7 +22436,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = "[", TestOrStarNamedExpr, CompFor, "]" => ActionFn(1267); + // Atom<"no-withitems"> = "[", TestOrStarNamedExpr, CompFor, "]" => ActionFn(1268); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant54(__symbols); @@ -22386,7 +22444,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1267::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1268::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (4, 95) } @@ -22399,13 +22457,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = "(", ")" => ActionFn(1276); + // Atom<"no-withitems"> = "(", ")" => ActionFn(1277); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1276::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1277::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 95) } @@ -22418,14 +22476,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = "(", YieldExpr, ")" => ActionFn(1277); + // Atom<"no-withitems"> = "(", YieldExpr, ")" => ActionFn(1278); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1277::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1278::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 95) } @@ -22438,7 +22496,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = "(", NamedExpressionTest, CompFor, ")" => ActionFn(1278); + // Atom<"no-withitems"> = "(", NamedExpressionTest, CompFor, ")" => ActionFn(1279); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant54(__symbols); @@ -22446,7 +22504,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1278::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1279::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (4, 95) } @@ -22459,14 +22517,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = "{", DictLiteralValues, "}" => ActionFn(1569); + // Atom<"no-withitems"> = "{", DictLiteralValues, "}" => ActionFn(1573); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant61(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1569::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1573::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 95) } @@ -22479,13 +22537,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = "{", "}" => ActionFn(1570); + // Atom<"no-withitems"> = "{", "}" => ActionFn(1574); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1570::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1574::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 95) } @@ -22498,7 +22556,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = "{", DictEntry, CompFor, "}" => ActionFn(1281); + // Atom<"no-withitems"> = "{", DictEntry, CompFor, "}" => ActionFn(1282); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant54(__symbols); @@ -22506,7 +22564,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1281::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1282::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (4, 95) } @@ -22519,14 +22577,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = "{", SetLiteralValues, "}" => ActionFn(1282); + // Atom<"no-withitems"> = "{", SetLiteralValues, "}" => ActionFn(1283); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant33(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1282::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1283::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 95) } @@ -22539,7 +22597,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = "{", NamedExpressionTest, CompFor, "}" => ActionFn(1283); + // Atom<"no-withitems"> = "{", NamedExpressionTest, CompFor, "}" => ActionFn(1284); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant54(__symbols); @@ -22547,7 +22605,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1283::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1284::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (4, 95) } @@ -22560,11 +22618,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = "True" => ActionFn(1284); + // Atom<"no-withitems"> = "True" => ActionFn(1285); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1284::<>(source_code, mode, __sym0); + let __nt = super::__action1285::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 95) } @@ -22577,11 +22635,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = "False" => ActionFn(1285); + // Atom<"no-withitems"> = "False" => ActionFn(1286); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1285::<>(source_code, mode, __sym0); + let __nt = super::__action1286::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 95) } @@ -22594,11 +22652,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = "None" => ActionFn(1286); + // Atom<"no-withitems"> = "None" => ActionFn(1287); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1286::<>(source_code, mode, __sym0); + let __nt = super::__action1287::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 95) } @@ -22611,11 +22669,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Atom<"no-withitems"> = "..." => ActionFn(1287); + // Atom<"no-withitems"> = "..." => ActionFn(1288); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1287::<>(source_code, mode, __sym0); + let __nt = super::__action1288::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 95) } @@ -22628,11 +22686,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AtomExpr2<"all"> = Atom<"all"> => ActionFn(537); + // AtomExpr2<"all"> = Atom<"all"> => ActionFn(540); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action537::<>(source_code, mode, __sym0); + let __nt = super::__action540::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 96) } @@ -22645,13 +22703,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AtomExpr2<"all"> = AtomExpr2<"all">, Arguments => ActionFn(1288); + // AtomExpr2<"all"> = AtomExpr2<"all">, Arguments => ActionFn(1289); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant50(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1288::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1289::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 96) } @@ -22664,7 +22722,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AtomExpr2<"all"> = AtomExpr2<"all">, "[", SubscriptList, "]" => ActionFn(1289); + // AtomExpr2<"all"> = AtomExpr2<"all">, "[", SubscriptList, "]" => ActionFn(1290); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant15(__symbols); @@ -22672,7 +22730,7 @@ mod __parse__Top { let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1289::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1290::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (4, 96) } @@ -22685,14 +22743,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AtomExpr2<"all"> = AtomExpr2<"all">, ".", Identifier => ActionFn(1290); + // AtomExpr2<"all"> = AtomExpr2<"all">, ".", Identifier => ActionFn(1291); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1290::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1291::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 96) } @@ -22705,11 +22763,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AtomExpr2<"no-withitems"> = Atom<"no-withitems"> => ActionFn(584); + // AtomExpr2<"no-withitems"> = Atom<"no-withitems"> => ActionFn(587); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action584::<>(source_code, mode, __sym0); + let __nt = super::__action587::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 97) } @@ -22722,13 +22780,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AtomExpr2<"no-withitems"> = AtomExpr2<"all">, Arguments => ActionFn(1291); + // AtomExpr2<"no-withitems"> = AtomExpr2<"all">, Arguments => ActionFn(1292); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant50(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1291::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1292::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 97) } @@ -22741,7 +22799,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AtomExpr2<"no-withitems"> = AtomExpr2<"all">, "[", SubscriptList, "]" => ActionFn(1292); + // AtomExpr2<"no-withitems"> = AtomExpr2<"all">, "[", SubscriptList, "]" => ActionFn(1293); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant15(__symbols); @@ -22749,7 +22807,7 @@ mod __parse__Top { let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1292::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1293::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (4, 97) } @@ -22762,14 +22820,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AtomExpr2<"no-withitems"> = AtomExpr2<"all">, ".", Identifier => ActionFn(1293); + // AtomExpr2<"no-withitems"> = AtomExpr2<"all">, ".", Identifier => ActionFn(1294); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1293::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1294::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 97) } @@ -22782,13 +22840,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AtomExpr<"all"> = "await", AtomExpr2<"all"> => ActionFn(1294); + // AtomExpr<"all"> = "await", AtomExpr2<"all"> => ActionFn(1295); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1294::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1295::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 98) } @@ -22801,11 +22859,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AtomExpr<"all"> = AtomExpr2<"all"> => ActionFn(536); + // AtomExpr<"all"> = AtomExpr2<"all"> => ActionFn(539); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action536::<>(source_code, mode, __sym0); + let __nt = super::__action539::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 98) } @@ -22818,13 +22876,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AtomExpr<"no-withitems"> = "await", AtomExpr2<"all"> => ActionFn(1295); + // AtomExpr<"no-withitems"> = "await", AtomExpr2<"all"> => ActionFn(1296); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1295::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1296::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 99) } @@ -22837,11 +22895,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // AtomExpr<"no-withitems"> = AtomExpr2<"no-withitems"> => ActionFn(583); + // AtomExpr<"no-withitems"> = AtomExpr2<"no-withitems"> => ActionFn(586); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action583::<>(source_code, mode, __sym0); + let __nt = super::__action586::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 99) } @@ -23075,11 +23133,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // CapturePattern = Identifier => ActionFn(1296); + // CapturePattern = Identifier => ActionFn(1297); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1296::<>(source_code, mode, __sym0); + let __nt = super::__action1297::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (1, 101) } @@ -23092,7 +23150,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ClassDef = "class", Identifier, TypeParams, Arguments, ":", Suite => ActionFn(1755); + // ClassDef = "class", Identifier, TypeParams, Arguments, ":", Suite => ActionFn(1759); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant25(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -23102,7 +23160,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = super::__action1755::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); + let __nt = super::__action1759::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (6, 102) } @@ -23115,7 +23173,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ClassDef = "class", Identifier, Arguments, ":", Suite => ActionFn(1756); + // ClassDef = "class", Identifier, Arguments, ":", Suite => ActionFn(1760); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant25(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -23124,7 +23182,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1756::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1760::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (5, 102) } @@ -23137,7 +23195,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ClassDef = Decorator+, "class", Identifier, TypeParams, Arguments, ":", Suite => ActionFn(1757); + // ClassDef = Decorator+, "class", Identifier, TypeParams, Arguments, ":", Suite => ActionFn(1761); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -23148,7 +23206,7 @@ mod __parse__Top { let __sym0 = __pop_Variant58(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1757::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1761::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (7, 102) } @@ -23161,7 +23219,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ClassDef = Decorator+, "class", Identifier, Arguments, ":", Suite => ActionFn(1758); + // ClassDef = Decorator+, "class", Identifier, Arguments, ":", Suite => ActionFn(1762); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant25(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -23171,7 +23229,7 @@ mod __parse__Top { let __sym0 = __pop_Variant58(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = super::__action1758::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); + let __nt = super::__action1762::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (6, 102) } @@ -23184,7 +23242,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ClassDef = "class", Identifier, TypeParams, ":", Suite => ActionFn(1759); + // ClassDef = "class", Identifier, TypeParams, ":", Suite => ActionFn(1763); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant25(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -23193,7 +23251,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1759::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1763::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (5, 102) } @@ -23206,7 +23264,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ClassDef = "class", Identifier, ":", Suite => ActionFn(1760); + // ClassDef = "class", Identifier, ":", Suite => ActionFn(1764); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant25(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -23214,7 +23272,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1760::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1764::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (4, 102) } @@ -23227,7 +23285,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ClassDef = Decorator+, "class", Identifier, TypeParams, ":", Suite => ActionFn(1761); + // ClassDef = Decorator+, "class", Identifier, TypeParams, ":", Suite => ActionFn(1765); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant25(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -23237,7 +23295,7 @@ mod __parse__Top { let __sym0 = __pop_Variant58(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = super::__action1761::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); + let __nt = super::__action1765::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (6, 102) } @@ -23250,7 +23308,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ClassDef = Decorator+, "class", Identifier, ":", Suite => ActionFn(1762); + // ClassDef = Decorator+, "class", Identifier, ":", Suite => ActionFn(1766); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant25(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -23259,7 +23317,7 @@ mod __parse__Top { let __sym0 = __pop_Variant58(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1762::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1766::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (5, 102) } @@ -23272,13 +23330,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ClassPattern = MatchName, PatternArguments => ActionFn(1297); + // ClassPattern = MatchName, PatternArguments => ActionFn(1298); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant89(__symbols); let __sym0 = __pop_Variant44(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1297::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1298::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (2, 103) } @@ -23291,13 +23349,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ClassPattern = MatchNameOrAttr, PatternArguments => ActionFn(1298); + // ClassPattern = MatchNameOrAttr, PatternArguments => ActionFn(1299); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant89(__symbols); let __sym0 = __pop_Variant44(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1298::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1299::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (2, 103) } @@ -23429,11 +23487,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Comma = FunctionArgument => ActionFn(1533); + // Comma = FunctionArgument => ActionFn(1537); let __sym0 = __pop_Variant31(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1533::<>(source_code, mode, __sym0); + let __nt = super::__action1537::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant52(__nt), __end)); (1, 105) } @@ -23446,10 +23504,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Comma = => ActionFn(1534); + // Comma = => ActionFn(1538); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action1534::<>(source_code, mode, &__start, &__end); + let __nt = super::__action1538::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant52(__nt), __end)); (0, 105) } @@ -23462,13 +23520,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Comma = ( ",")+, FunctionArgument => ActionFn(1535); + // Comma = ( ",")+, FunctionArgument => ActionFn(1539); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant31(__symbols); let __sym0 = __pop_Variant32(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1535::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1539::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant52(__nt), __end)); (2, 105) } @@ -23481,11 +23539,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Comma = ( ",")+ => ActionFn(1536); + // Comma = ( ",")+ => ActionFn(1540); let __sym0 = __pop_Variant32(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1536::<>(source_code, mode, __sym0); + let __nt = super::__action1540::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant52(__nt), __end)); (1, 105) } @@ -23498,11 +23556,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Comma = Pattern => ActionFn(1541); + // Comma = Pattern => ActionFn(1545); let __sym0 = __pop_Variant35(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1541::<>(source_code, mode, __sym0); + let __nt = super::__action1545::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); (1, 106) } @@ -23515,10 +23573,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Comma = => ActionFn(1542); + // Comma = => ActionFn(1546); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action1542::<>(source_code, mode, &__start, &__end); + let __nt = super::__action1546::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); (0, 106) } @@ -23531,13 +23589,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Comma = ( ",")+, Pattern => ActionFn(1543); + // Comma = ( ",")+, Pattern => ActionFn(1547); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant35(__symbols); let __sym0 = __pop_Variant36(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1543::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1547::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); (2, 106) } @@ -23550,11 +23608,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Comma = ( ",")+ => ActionFn(1544); + // Comma = ( ",")+ => ActionFn(1548); let __sym0 = __pop_Variant36(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1544::<>(source_code, mode, __sym0); + let __nt = super::__action1548::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); (1, 106) } @@ -23567,11 +23625,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // CompFor = SingleForComprehension+ => ActionFn(234); + // CompFor = SingleForComprehension+ => ActionFn(237); let __sym0 = __pop_Variant91(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action234::<>(source_code, mode, __sym0); + let __nt = super::__action237::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant54(__nt), __end)); (1, 107) } @@ -23584,11 +23642,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // CompFor? = CompFor => ActionFn(247); + // CompFor? = CompFor => ActionFn(250); let __sym0 = __pop_Variant54(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action247::<>(source_code, mode, __sym0); + let __nt = super::__action250::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant55(__nt), __end)); (1, 108) } @@ -23601,10 +23659,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // CompFor? = => ActionFn(248); + // CompFor? = => ActionFn(251); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action248::<>(source_code, mode, &__start, &__end); + let __nt = super::__action251::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant55(__nt), __end)); (0, 108) } @@ -23617,11 +23675,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // CompOp = "==" => ActionFn(184); + // CompOp = "==" => ActionFn(185); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action184::<>(source_code, mode, __sym0); + let __nt = super::__action185::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant56(__nt), __end)); (1, 109) } @@ -23634,11 +23692,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // CompOp = "!=" => ActionFn(185); + // CompOp = "!=" => ActionFn(186); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action185::<>(source_code, mode, __sym0); + let __nt = super::__action186::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant56(__nt), __end)); (1, 109) } @@ -23651,11 +23709,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // CompOp = "<" => ActionFn(186); + // CompOp = "<" => ActionFn(187); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action186::<>(source_code, mode, __sym0); + let __nt = super::__action187::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant56(__nt), __end)); (1, 109) } @@ -23668,11 +23726,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // CompOp = "<=" => ActionFn(187); + // CompOp = "<=" => ActionFn(188); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action187::<>(source_code, mode, __sym0); + let __nt = super::__action188::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant56(__nt), __end)); (1, 109) } @@ -23685,11 +23743,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // CompOp = ">" => ActionFn(188); + // CompOp = ">" => ActionFn(189); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action188::<>(source_code, mode, __sym0); + let __nt = super::__action189::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant56(__nt), __end)); (1, 109) } @@ -23702,11 +23760,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // CompOp = ">=" => ActionFn(189); + // CompOp = ">=" => ActionFn(190); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action189::<>(source_code, mode, __sym0); + let __nt = super::__action190::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant56(__nt), __end)); (1, 109) } @@ -23719,11 +23777,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // CompOp = "in" => ActionFn(190); + // CompOp = "in" => ActionFn(191); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action190::<>(source_code, mode, __sym0); + let __nt = super::__action191::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant56(__nt), __end)); (1, 109) } @@ -23736,13 +23794,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // CompOp = "not", "in" => ActionFn(191); + // CompOp = "not", "in" => ActionFn(192); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action191::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action192::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant56(__nt), __end)); (2, 109) } @@ -23755,11 +23813,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // CompOp = "is" => ActionFn(192); + // CompOp = "is" => ActionFn(193); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action192::<>(source_code, mode, __sym0); + let __nt = super::__action193::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant56(__nt), __end)); (1, 109) } @@ -23772,13 +23830,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // CompOp = "is", "not" => ActionFn(193); + // CompOp = "is", "not" => ActionFn(194); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action193::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action194::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant56(__nt), __end)); (2, 109) } @@ -23791,13 +23849,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Comparison<"all"> = Expression<"all">, (CompOp Expression<"all">)+ => ActionFn(1299); + // Comparison<"all"> = Expression<"all">, (CompOp Expression<"all">)+ => ActionFn(1300); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant43(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1299::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1300::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 110) } @@ -23810,11 +23868,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Comparison<"all"> = Expression<"all"> => ActionFn(513); + // Comparison<"all"> = Expression<"all"> => ActionFn(516); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action513::<>(source_code, mode, __sym0); + let __nt = super::__action516::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 110) } @@ -23827,13 +23885,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Comparison<"no-withitems"> = Expression<"all">, (CompOp Expression<"all">)+ => ActionFn(1300); + // Comparison<"no-withitems"> = Expression<"all">, (CompOp Expression<"all">)+ => ActionFn(1301); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant43(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1300::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1301::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 111) } @@ -23846,11 +23904,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Comparison<"no-withitems"> = Expression<"no-withitems"> => ActionFn(524); + // Comparison<"no-withitems"> = Expression<"no-withitems"> => ActionFn(527); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action524::<>(source_code, mode, __sym0); + let __nt = super::__action527::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 111) } @@ -23999,13 +24057,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ComprehensionIf = "if", ExpressionNoCond => ActionFn(237); + // ComprehensionIf = "if", ExpressionNoCond => ActionFn(240); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action237::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action240::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 113) } @@ -24018,10 +24076,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ComprehensionIf* = => ActionFn(250); + // ComprehensionIf* = => ActionFn(253); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action250::<>(source_code, mode, &__start, &__end); + let __nt = super::__action253::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (0, 114) } @@ -24034,11 +24092,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ComprehensionIf* = ComprehensionIf+ => ActionFn(251); + // ComprehensionIf* = ComprehensionIf+ => ActionFn(254); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action251::<>(source_code, mode, __sym0); + let __nt = super::__action254::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (1, 114) } @@ -24051,11 +24109,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ComprehensionIf+ = ComprehensionIf => ActionFn(462); + // ComprehensionIf+ = ComprehensionIf => ActionFn(465); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action462::<>(source_code, mode, __sym0); + let __nt = super::__action465::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (1, 115) } @@ -24068,13 +24126,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ComprehensionIf+ = ComprehensionIf+, ComprehensionIf => ActionFn(463); + // ComprehensionIf+ = ComprehensionIf+, ComprehensionIf => ActionFn(466); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action463::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action466::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant17(__nt), __end)); (2, 115) } @@ -24087,14 +24145,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Decorator = "@", NamedExpressionTest, "\n" => ActionFn(1301); + // Decorator = "@", NamedExpressionTest, "\n" => ActionFn(1302); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1301::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1302::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant57(__nt), __end)); (3, 116) } @@ -24107,10 +24165,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Decorator* = => ActionFn(306); + // Decorator* = => ActionFn(311); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action306::<>(source_code, mode, &__start, &__end); + let __nt = super::__action311::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant58(__nt), __end)); (0, 117) } @@ -24123,11 +24181,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Decorator* = Decorator+ => ActionFn(307); + // Decorator* = Decorator+ => ActionFn(312); let __sym0 = __pop_Variant58(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action307::<>(source_code, mode, __sym0); + let __nt = super::__action312::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant58(__nt), __end)); (1, 117) } @@ -24140,11 +24198,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Decorator+ = Decorator => ActionFn(435); + // Decorator+ = Decorator => ActionFn(438); let __sym0 = __pop_Variant57(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action435::<>(source_code, mode, __sym0); + let __nt = super::__action438::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant58(__nt), __end)); (1, 118) } @@ -24157,13 +24215,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Decorator+ = Decorator+, Decorator => ActionFn(436); + // Decorator+ = Decorator+, Decorator => ActionFn(439); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant57(__symbols); let __sym0 = __pop_Variant58(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action436::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action439::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant58(__nt), __end)); (2, 118) } @@ -24176,13 +24234,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // DelStatement = "del", ExpressionList2 => ActionFn(1302); + // DelStatement = "del", ExpressionList2 => ActionFn(1303); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant33(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1302::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1303::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (2, 119) } @@ -24195,11 +24253,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // DictElement = DictEntry => ActionFn(225); + // DictElement = DictEntry => ActionFn(228); let __sym0 = __pop_Variant60(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action225::<>(source_code, mode, __sym0); + let __nt = super::__action228::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant59(__nt), __end)); (1, 120) } @@ -24212,13 +24270,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // DictElement = "**", Expression<"all"> => ActionFn(226); + // DictElement = "**", Expression<"all"> => ActionFn(229); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action226::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action229::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant59(__nt), __end)); (2, 120) } @@ -24231,14 +24289,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // DictEntry = Test<"all">, ":", Test<"all"> => ActionFn(224); + // DictEntry = Test<"all">, ":", Test<"all"> => ActionFn(227); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action224::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action227::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant60(__nt), __end)); (3, 121) } @@ -24251,13 +24309,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // DictLiteralValues = OneOrMore, "," => ActionFn(612); + // DictLiteralValues = OneOrMore, "," => ActionFn(615); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant61(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action612::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action615::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant61(__nt), __end)); (2, 122) } @@ -24270,11 +24328,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // DictLiteralValues = OneOrMore => ActionFn(613); + // DictLiteralValues = OneOrMore => ActionFn(616); let __sym0 = __pop_Variant61(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action613::<>(source_code, mode, __sym0); + let __nt = super::__action616::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant61(__nt), __end)); (1, 122) } @@ -24287,11 +24345,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // DictLiteralValues? = DictLiteralValues => ActionFn(564); + // DictLiteralValues? = DictLiteralValues => ActionFn(567); let __sym0 = __pop_Variant61(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action564::<>(source_code, mode, __sym0); + let __nt = super::__action567::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant62(__nt), __end)); (1, 123) } @@ -24304,10 +24362,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // DictLiteralValues? = => ActionFn(565); + // DictLiteralValues? = => ActionFn(568); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action565::<>(source_code, mode, &__start, &__end); + let __nt = super::__action568::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant62(__nt), __end)); (0, 123) } @@ -24320,11 +24378,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // DottedName = name => ActionFn(1303); + // DottedName = name => ActionFn(1304); let __sym0 = __pop_Variant6(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1303::<>(source_code, mode, __sym0); + let __nt = super::__action1304::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant23(__nt), __end)); (1, 124) } @@ -24337,13 +24395,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // DottedName = name, ("." Identifier)+ => ActionFn(1304); + // DottedName = name, ("." Identifier)+ => ActionFn(1305); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant21(__symbols); let __sym0 = __pop_Variant6(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1304::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1305::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant23(__nt), __end)); (2, 124) } @@ -24356,14 +24414,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // DoubleStarTypedParameter = Identifier, ":", Test<"all"> => ActionFn(1305); + // DoubleStarTypedParameter = Identifier, ":", Test<"all"> => ActionFn(1306); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1305::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1306::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant63(__nt), __end)); (3, 125) } @@ -24376,11 +24434,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // DoubleStarTypedParameter = Identifier => ActionFn(1306); + // DoubleStarTypedParameter = Identifier => ActionFn(1307); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1306::<>(source_code, mode, __sym0); + let __nt = super::__action1307::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant63(__nt), __end)); (1, 125) } @@ -24393,11 +24451,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // DoubleStarTypedParameter? = DoubleStarTypedParameter => ActionFn(498); + // DoubleStarTypedParameter? = DoubleStarTypedParameter => ActionFn(501); let __sym0 = __pop_Variant63(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action498::<>(source_code, mode, __sym0); + let __nt = super::__action501::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant64(__nt), __end)); (1, 126) } @@ -24410,10 +24468,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // DoubleStarTypedParameter? = => ActionFn(499); + // DoubleStarTypedParameter? = => ActionFn(502); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action499::<>(source_code, mode, &__start, &__end); + let __nt = super::__action502::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant64(__nt), __end)); (0, 126) } @@ -24426,7 +24484,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ExceptClause = "except", Test<"all">, ":", Suite => ActionFn(1727); + // ExceptClause = "except", Test<"all">, ":", Suite => ActionFn(1731); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant25(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -24434,7 +24492,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1727::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1731::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant65(__nt), __end)); (4, 127) } @@ -24447,14 +24505,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ExceptClause = "except", ":", Suite => ActionFn(1728); + // ExceptClause = "except", ":", Suite => ActionFn(1732); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant25(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1728::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1732::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant65(__nt), __end)); (3, 127) } @@ -24467,7 +24525,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ExceptClause = "except", Test<"all">, "as", Identifier, ":", Suite => ActionFn(1203); + // ExceptClause = "except", Test<"all">, "as", Identifier, ":", Suite => ActionFn(1206); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant25(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -24477,7 +24535,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = super::__action1203::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); + let __nt = super::__action1206::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant65(__nt), __end)); (6, 127) } @@ -24490,11 +24548,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ExceptClause+ = ExceptClause => ActionFn(330); + // ExceptClause+ = ExceptClause => ActionFn(335); let __sym0 = __pop_Variant65(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action330::<>(source_code, mode, __sym0); + let __nt = super::__action335::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant66(__nt), __end)); (1, 128) } @@ -24507,13 +24565,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ExceptClause+ = ExceptClause+, ExceptClause => ActionFn(331); + // ExceptClause+ = ExceptClause+, ExceptClause => ActionFn(336); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant65(__symbols); let __sym0 = __pop_Variant66(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action331::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action336::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant66(__nt), __end)); (2, 128) } @@ -24526,7 +24584,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ExceptStarClause = "except", "*", Test<"all">, ":", Suite => ActionFn(793); + // ExceptStarClause = "except", "*", Test<"all">, ":", Suite => ActionFn(794); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant25(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -24535,7 +24593,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action793::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action794::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant65(__nt), __end)); (5, 129) } @@ -24548,7 +24606,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ExceptStarClause = "except", "*", Test<"all">, "as", Identifier, ":", Suite => ActionFn(1204); + // ExceptStarClause = "except", "*", Test<"all">, "as", Identifier, ":", Suite => ActionFn(1207); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -24559,7 +24617,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1204::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1207::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant65(__nt), __end)); (7, 129) } @@ -24572,11 +24630,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ExceptStarClause+ = ExceptStarClause => ActionFn(325); + // ExceptStarClause+ = ExceptStarClause => ActionFn(330); let __sym0 = __pop_Variant65(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action325::<>(source_code, mode, __sym0); + let __nt = super::__action330::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant66(__nt), __end)); (1, 130) } @@ -24589,13 +24647,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ExceptStarClause+ = ExceptStarClause+, ExceptStarClause => ActionFn(326); + // ExceptStarClause+ = ExceptStarClause+, ExceptStarClause => ActionFn(331); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant65(__symbols); let __sym0 = __pop_Variant66(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action326::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action331::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant66(__nt), __end)); (2, 130) } @@ -24608,14 +24666,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Expression<"all"> = Expression<"all">, "|", XorExpression<"all"> => ActionFn(1307); + // Expression<"all"> = Expression<"all">, "|", XorExpression<"all"> => ActionFn(1308); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1307::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1308::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 131) } @@ -24628,11 +24686,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Expression<"all"> = XorExpression<"all"> => ActionFn(372); + // Expression<"all"> = XorExpression<"all"> => ActionFn(375); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action372::<>(source_code, mode, __sym0); + let __nt = super::__action375::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 131) } @@ -24645,14 +24703,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Expression<"no-withitems"> = Expression<"all">, "|", XorExpression<"all"> => ActionFn(1308); + // Expression<"no-withitems"> = Expression<"all">, "|", XorExpression<"all"> => ActionFn(1309); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1308::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1309::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 132) } @@ -24665,11 +24723,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Expression<"no-withitems"> = XorExpression<"no-withitems"> => ActionFn(526); + // Expression<"no-withitems"> = XorExpression<"no-withitems"> => ActionFn(529); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action526::<>(source_code, mode, __sym0); + let __nt = super::__action529::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 132) } @@ -24682,11 +24740,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ExpressionList = GenericList => ActionFn(230); + // ExpressionList = GenericList => ActionFn(233); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action230::<>(source_code, mode, __sym0); + let __nt = super::__action233::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 133) } @@ -24699,13 +24757,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ExpressionList2 = OneOrMore, "," => ActionFn(614); + // ExpressionList2 = OneOrMore, "," => ActionFn(617); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action614::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action617::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (2, 134) } @@ -24718,11 +24776,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ExpressionList2 = OneOrMore => ActionFn(615); + // ExpressionList2 = OneOrMore => ActionFn(618); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action615::<>(source_code, mode, __sym0); + let __nt = super::__action618::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (1, 134) } @@ -24735,11 +24793,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ExpressionNoCond = OrTest<"all"> => ActionFn(236); + // ExpressionNoCond = OrTest<"all"> => ActionFn(239); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action236::<>(source_code, mode, __sym0); + let __nt = super::__action239::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 135) } @@ -24752,11 +24810,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ExpressionOrStarExpression = Expression<"all"> => ActionFn(228); + // ExpressionOrStarExpression = Expression<"all"> => ActionFn(231); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action228::<>(source_code, mode, __sym0); + let __nt = super::__action231::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 136) } @@ -24769,11 +24827,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ExpressionOrStarExpression = StarExpr => ActionFn(229); + // ExpressionOrStarExpression = StarExpr => ActionFn(232); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action229::<>(source_code, mode, __sym0); + let __nt = super::__action232::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 136) } @@ -24786,11 +24844,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FStringConversion? = FStringConversion => ActionFn(266); + // FStringConversion? = FStringConversion => ActionFn(269); let __sym0 = __pop_Variant67(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action266::<>(source_code, mode, __sym0); + let __nt = super::__action269::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant68(__nt), __end)); (1, 139) } @@ -24803,10 +24861,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FStringConversion? = => ActionFn(267); + // FStringConversion? = => ActionFn(270); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action267::<>(source_code, mode, &__start, &__end); + let __nt = super::__action270::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant68(__nt), __end)); (0, 139) } @@ -24819,13 +24877,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FStringExpr = FStringStart, FStringEnd => ActionFn(1585); + // FStringExpr = FStringStart, FStringEnd => ActionFn(1589); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1585::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1589::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant69(__nt), __end)); (2, 140) } @@ -24838,14 +24896,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FStringExpr = FStringStart, FStringMiddlePattern+, FStringEnd => ActionFn(1586); + // FStringExpr = FStringStart, FStringMiddlePattern+, FStringEnd => ActionFn(1590); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant70(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1586::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1590::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant69(__nt), __end)); (3, 140) } @@ -24858,10 +24916,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FStringFormatSpec = => ActionFn(1587); + // FStringFormatSpec = => ActionFn(1591); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action1587::<>(source_code, mode, &__start, &__end); + let __nt = super::__action1591::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (0, 141) } @@ -24874,11 +24932,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FStringFormatSpec = FStringMiddlePattern+ => ActionFn(1588); + // FStringFormatSpec = FStringMiddlePattern+ => ActionFn(1592); let __sym0 = __pop_Variant70(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1588::<>(source_code, mode, __sym0); + let __nt = super::__action1592::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (1, 141) } @@ -24891,13 +24949,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FStringFormatSpecSuffix = ":", FStringFormatSpec => ActionFn(219); + // FStringFormatSpecSuffix = ":", FStringFormatSpec => ActionFn(222); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant44(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action219::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action222::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (2, 142) } @@ -24910,11 +24968,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FStringFormatSpecSuffix? = FStringFormatSpecSuffix => ActionFn(264); + // FStringFormatSpecSuffix? = FStringFormatSpecSuffix => ActionFn(267); let __sym0 = __pop_Variant44(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action264::<>(source_code, mode, __sym0); + let __nt = super::__action267::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant45(__nt), __end)); (1, 143) } @@ -24927,10 +24985,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FStringFormatSpecSuffix? = => ActionFn(265); + // FStringFormatSpecSuffix? = => ActionFn(268); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action265::<>(source_code, mode, &__start, &__end); + let __nt = super::__action268::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant45(__nt), __end)); (0, 143) } @@ -24943,11 +25001,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FStringMiddlePattern = FStringReplacementField => ActionFn(216); + // FStringMiddlePattern = FStringReplacementField => ActionFn(219); let __sym0 = __pop_Variant44(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action216::<>(source_code, mode, __sym0); + let __nt = super::__action219::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (1, 144) } @@ -24960,10 +25018,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FStringMiddlePattern* = => ActionFn(270); + // FStringMiddlePattern* = => ActionFn(273); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action270::<>(source_code, mode, &__start, &__end); + let __nt = super::__action273::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant70(__nt), __end)); (0, 145) } @@ -24976,11 +25034,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FStringMiddlePattern* = FStringMiddlePattern+ => ActionFn(271); + // FStringMiddlePattern* = FStringMiddlePattern+ => ActionFn(274); let __sym0 = __pop_Variant70(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action271::<>(source_code, mode, __sym0); + let __nt = super::__action274::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant70(__nt), __end)); (1, 145) } @@ -24993,11 +25051,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FStringMiddlePattern+ = FStringMiddlePattern => ActionFn(453); + // FStringMiddlePattern+ = FStringMiddlePattern => ActionFn(456); let __sym0 = __pop_Variant44(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action453::<>(source_code, mode, __sym0); + let __nt = super::__action456::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant70(__nt), __end)); (1, 146) } @@ -25010,13 +25068,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FStringMiddlePattern+ = FStringMiddlePattern+, FStringMiddlePattern => ActionFn(454); + // FStringMiddlePattern+ = FStringMiddlePattern+, FStringMiddlePattern => ActionFn(457); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant44(__symbols); let __sym0 = __pop_Variant70(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action454::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action457::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant70(__nt), __end)); (2, 146) } @@ -25029,13 +25087,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Factor<"all"> = UnaryOp, Factor<"all"> => ActionFn(1316); + // Factor<"all"> = UnaryOp, Factor<"all"> => ActionFn(1318); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant100(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1316::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1318::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 148) } @@ -25048,11 +25106,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Factor<"all"> = Power<"all"> => ActionFn(528); + // Factor<"all"> = Power<"all"> => ActionFn(531); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action528::<>(source_code, mode, __sym0); + let __nt = super::__action531::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 148) } @@ -25065,13 +25123,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Factor<"no-withitems"> = UnaryOp, Factor<"all"> => ActionFn(1317); + // Factor<"no-withitems"> = UnaryOp, Factor<"all"> => ActionFn(1319); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant100(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1317::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1319::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 149) } @@ -25084,11 +25142,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Factor<"no-withitems"> = Power<"no-withitems"> => ActionFn(577); + // Factor<"no-withitems"> = Power<"no-withitems"> => ActionFn(580); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action577::<>(source_code, mode, __sym0); + let __nt = super::__action580::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 149) } @@ -25101,11 +25159,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FlowStatement = "break" => ActionFn(1318); + // FlowStatement = "break" => ActionFn(1320); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1318::<>(source_code, mode, __sym0); + let __nt = super::__action1320::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 150) } @@ -25118,11 +25176,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FlowStatement = "continue" => ActionFn(1319); + // FlowStatement = "continue" => ActionFn(1321); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1319::<>(source_code, mode, __sym0); + let __nt = super::__action1321::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 150) } @@ -25135,13 +25193,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FlowStatement = "return", GenericList => ActionFn(1748); + // FlowStatement = "return", GenericList => ActionFn(1752); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1748::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1752::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (2, 150) } @@ -25154,11 +25212,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FlowStatement = "return" => ActionFn(1749); + // FlowStatement = "return" => ActionFn(1753); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1749::<>(source_code, mode, __sym0); + let __nt = super::__action1753::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 150) } @@ -25171,11 +25229,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FlowStatement = YieldExpr => ActionFn(1321); + // FlowStatement = YieldExpr => ActionFn(1323); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1321::<>(source_code, mode, __sym0); + let __nt = super::__action1323::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 150) } @@ -25205,7 +25263,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ForStatement = "async", "for", ExpressionList, "in", GenericList, ":", Suite, "else", ":", Suite => ActionFn(1739); + // ForStatement = "async", "for", ExpressionList, "in", GenericList, ":", Suite, "else", ":", Suite => ActionFn(1743); assert!(__symbols.len() >= 10); let __sym9 = __pop_Variant25(__symbols); let __sym8 = __pop_Variant0(__symbols); @@ -25219,7 +25277,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym9.2; - let __nt = super::__action1739::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9); + let __nt = super::__action1743::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (10, 151) } @@ -25232,7 +25290,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ForStatement = "async", "for", ExpressionList, "in", GenericList, ":", Suite => ActionFn(1740); + // ForStatement = "async", "for", ExpressionList, "in", GenericList, ":", Suite => ActionFn(1744); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -25243,7 +25301,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1740::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1744::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (7, 151) } @@ -25256,7 +25314,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ForStatement = "for", ExpressionList, "in", GenericList, ":", Suite, "else", ":", Suite => ActionFn(1741); + // ForStatement = "for", ExpressionList, "in", GenericList, ":", Suite, "else", ":", Suite => ActionFn(1745); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant25(__symbols); let __sym7 = __pop_Variant0(__symbols); @@ -25269,7 +25327,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = super::__action1741::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8); + let __nt = super::__action1745::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (9, 151) } @@ -25282,7 +25340,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ForStatement = "for", ExpressionList, "in", GenericList, ":", Suite => ActionFn(1742); + // ForStatement = "for", ExpressionList, "in", GenericList, ":", Suite => ActionFn(1746); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant25(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -25292,7 +25350,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = super::__action1742::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); + let __nt = super::__action1746::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (6, 151) } @@ -25305,7 +25363,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = "async", "def", Identifier, TypeParams, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1763); + // FuncDef = "async", "def", Identifier, TypeParams, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1767); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant25(__symbols); let __sym7 = __pop_Variant0(__symbols); @@ -25318,7 +25376,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = super::__action1763::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8); + let __nt = super::__action1767::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (9, 152) } @@ -25331,7 +25389,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = "async", "def", Identifier, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1764); + // FuncDef = "async", "def", Identifier, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1768); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant25(__symbols); let __sym6 = __pop_Variant0(__symbols); @@ -25343,7 +25401,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = super::__action1764::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7); + let __nt = super::__action1768::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (8, 152) } @@ -25356,7 +25414,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = Decorator+, "async", "def", Identifier, TypeParams, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1765); + // FuncDef = Decorator+, "async", "def", Identifier, TypeParams, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1769); assert!(__symbols.len() >= 10); let __sym9 = __pop_Variant25(__symbols); let __sym8 = __pop_Variant0(__symbols); @@ -25370,7 +25428,7 @@ mod __parse__Top { let __sym0 = __pop_Variant58(__symbols); let __start = __sym0.0; let __end = __sym9.2; - let __nt = super::__action1765::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9); + let __nt = super::__action1769::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (10, 152) } @@ -25383,7 +25441,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = Decorator+, "async", "def", Identifier, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1766); + // FuncDef = Decorator+, "async", "def", Identifier, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1770); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant25(__symbols); let __sym7 = __pop_Variant0(__symbols); @@ -25396,7 +25454,7 @@ mod __parse__Top { let __sym0 = __pop_Variant58(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = super::__action1766::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8); + let __nt = super::__action1770::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (9, 152) } @@ -25409,7 +25467,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = "async", "def", Identifier, TypeParams, Parameters, ":", Suite => ActionFn(1767); + // FuncDef = "async", "def", Identifier, TypeParams, Parameters, ":", Suite => ActionFn(1771); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -25420,7 +25478,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1767::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1771::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (7, 152) } @@ -25433,7 +25491,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = "async", "def", Identifier, Parameters, ":", Suite => ActionFn(1768); + // FuncDef = "async", "def", Identifier, Parameters, ":", Suite => ActionFn(1772); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant25(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -25443,7 +25501,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = super::__action1768::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); + let __nt = super::__action1772::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (6, 152) } @@ -25456,7 +25514,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = Decorator+, "async", "def", Identifier, TypeParams, Parameters, ":", Suite => ActionFn(1769); + // FuncDef = Decorator+, "async", "def", Identifier, TypeParams, Parameters, ":", Suite => ActionFn(1773); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant25(__symbols); let __sym6 = __pop_Variant0(__symbols); @@ -25468,7 +25526,7 @@ mod __parse__Top { let __sym0 = __pop_Variant58(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = super::__action1769::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7); + let __nt = super::__action1773::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (8, 152) } @@ -25481,7 +25539,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = Decorator+, "async", "def", Identifier, Parameters, ":", Suite => ActionFn(1770); + // FuncDef = Decorator+, "async", "def", Identifier, Parameters, ":", Suite => ActionFn(1774); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -25492,7 +25550,7 @@ mod __parse__Top { let __sym0 = __pop_Variant58(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1770::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1774::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (7, 152) } @@ -25505,7 +25563,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = "def", Identifier, TypeParams, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1771); + // FuncDef = "def", Identifier, TypeParams, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1775); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant25(__symbols); let __sym6 = __pop_Variant0(__symbols); @@ -25517,7 +25575,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = super::__action1771::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7); + let __nt = super::__action1775::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (8, 152) } @@ -25530,7 +25588,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = "def", Identifier, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1772); + // FuncDef = "def", Identifier, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1776); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -25541,7 +25599,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1772::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1776::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (7, 152) } @@ -25554,7 +25612,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = Decorator+, "def", Identifier, TypeParams, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1773); + // FuncDef = Decorator+, "def", Identifier, TypeParams, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1777); assert!(__symbols.len() >= 9); let __sym8 = __pop_Variant25(__symbols); let __sym7 = __pop_Variant0(__symbols); @@ -25567,7 +25625,7 @@ mod __parse__Top { let __sym0 = __pop_Variant58(__symbols); let __start = __sym0.0; let __end = __sym8.2; - let __nt = super::__action1773::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8); + let __nt = super::__action1777::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (9, 152) } @@ -25580,7 +25638,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = Decorator+, "def", Identifier, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1774); + // FuncDef = Decorator+, "def", Identifier, Parameters, "->", Test<"all">, ":", Suite => ActionFn(1778); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant25(__symbols); let __sym6 = __pop_Variant0(__symbols); @@ -25592,7 +25650,7 @@ mod __parse__Top { let __sym0 = __pop_Variant58(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = super::__action1774::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7); + let __nt = super::__action1778::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (8, 152) } @@ -25605,7 +25663,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = "def", Identifier, TypeParams, Parameters, ":", Suite => ActionFn(1775); + // FuncDef = "def", Identifier, TypeParams, Parameters, ":", Suite => ActionFn(1779); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant25(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -25615,7 +25673,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = super::__action1775::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); + let __nt = super::__action1779::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (6, 152) } @@ -25628,7 +25686,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = "def", Identifier, Parameters, ":", Suite => ActionFn(1776); + // FuncDef = "def", Identifier, Parameters, ":", Suite => ActionFn(1780); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant25(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -25637,7 +25695,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1776::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1780::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (5, 152) } @@ -25650,7 +25708,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = Decorator+, "def", Identifier, TypeParams, Parameters, ":", Suite => ActionFn(1777); + // FuncDef = Decorator+, "def", Identifier, TypeParams, Parameters, ":", Suite => ActionFn(1781); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -25661,7 +25719,7 @@ mod __parse__Top { let __sym0 = __pop_Variant58(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1777::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1781::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (7, 152) } @@ -25674,7 +25732,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FuncDef = Decorator+, "def", Identifier, Parameters, ":", Suite => ActionFn(1778); + // FuncDef = Decorator+, "def", Identifier, Parameters, ":", Suite => ActionFn(1782); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant25(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -25684,7 +25742,7 @@ mod __parse__Top { let __sym0 = __pop_Variant58(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = super::__action1778::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); + let __nt = super::__action1782::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (6, 152) } @@ -25697,13 +25755,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FunctionArgument = NamedExpressionTest, CompFor => ActionFn(1549); + // FunctionArgument = NamedExpressionTest, CompFor => ActionFn(1553); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant54(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1549::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1553::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant31(__nt), __end)); (2, 153) } @@ -25716,11 +25774,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FunctionArgument = NamedExpressionTest => ActionFn(1550); + // FunctionArgument = NamedExpressionTest => ActionFn(1554); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1550::<>(source_code, mode, __sym0); + let __nt = super::__action1554::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant31(__nt), __end)); (1, 153) } @@ -25733,14 +25791,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FunctionArgument = Identifier, "=", Test<"all"> => ActionFn(1323); + // FunctionArgument = Identifier, "=", Test<"all"> => ActionFn(1325); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1323::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1325::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant31(__nt), __end)); (3, 153) } @@ -25753,13 +25811,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FunctionArgument = "*", Test<"all"> => ActionFn(1324); + // FunctionArgument = "*", Test<"all"> => ActionFn(1326); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1324::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1326::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant31(__nt), __end)); (2, 153) } @@ -25772,13 +25830,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FunctionArgument = "**", Test<"all"> => ActionFn(1325); + // FunctionArgument = "**", Test<"all"> => ActionFn(1327); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1325::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1327::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant31(__nt), __end)); (2, 153) } @@ -25791,11 +25849,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FunctionArgument? = FunctionArgument => ActionFn(464); + // FunctionArgument? = FunctionArgument => ActionFn(467); let __sym0 = __pop_Variant31(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action464::<>(source_code, mode, __sym0); + let __nt = super::__action467::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (1, 154) } @@ -25808,10 +25866,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // FunctionArgument? = => ActionFn(465); + // FunctionArgument? = => ActionFn(468); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action465::<>(source_code, mode, &__start, &__end); + let __nt = super::__action468::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (0, 154) } @@ -25824,13 +25882,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // GenericList = OneOrMore, "," => ActionFn(1326); + // GenericList = OneOrMore, "," => ActionFn(1328); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1326::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1328::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 155) } @@ -25843,11 +25901,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // GenericList = OneOrMore => ActionFn(1327); + // GenericList = OneOrMore => ActionFn(1329); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1327::<>(source_code, mode, __sym0); + let __nt = super::__action1329::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 155) } @@ -25860,13 +25918,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // GenericList = OneOrMore, "," => ActionFn(1328); + // GenericList = OneOrMore, "," => ActionFn(1330); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1328::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1330::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 156) } @@ -25879,11 +25937,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // GenericList = OneOrMore => ActionFn(1329); + // GenericList = OneOrMore => ActionFn(1331); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1329::<>(source_code, mode, __sym0); + let __nt = super::__action1331::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 156) } @@ -25896,13 +25954,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // GlobalStatement = "global", OneOrMore => ActionFn(1330); + // GlobalStatement = "global", OneOrMore => ActionFn(1332); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant82(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1330::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1332::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (2, 157) } @@ -25934,11 +25992,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Identifier = name => ActionFn(1331); + // Identifier = name => ActionFn(1333); let __sym0 = __pop_Variant6(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1331::<>(source_code, mode, __sym0); + let __nt = super::__action1333::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant23(__nt), __end)); (1, 159) } @@ -25951,7 +26009,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // IfStatement = "if", NamedExpressionTest, ":", Suite, "else", ":", Suite => ActionFn(1152); + // IfStatement = "if", NamedExpressionTest, ":", Suite, "else", ":", Suite => ActionFn(1155); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -25962,7 +26020,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1152::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1155::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (7, 160) } @@ -25975,7 +26033,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // IfStatement = "if", NamedExpressionTest, ":", Suite => ActionFn(1153); + // IfStatement = "if", NamedExpressionTest, ":", Suite => ActionFn(1156); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant25(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -25983,7 +26041,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1153::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1156::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (4, 160) } @@ -25996,7 +26054,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // IfStatement = "if", NamedExpressionTest, ":", Suite, (<@L> "elif" ":" )+, "else", ":", Suite => ActionFn(1154); + // IfStatement = "if", NamedExpressionTest, ":", Suite, (<@L> "elif" ":" )+, "else", ":", Suite => ActionFn(1157); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant25(__symbols); let __sym6 = __pop_Variant0(__symbols); @@ -26008,7 +26066,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = super::__action1154::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7); + let __nt = super::__action1157::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (8, 160) } @@ -26021,7 +26079,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // IfStatement = "if", NamedExpressionTest, ":", Suite, (<@L> "elif" ":" )+ => ActionFn(1155); + // IfStatement = "if", NamedExpressionTest, ":", Suite, (<@L> "elif" ":" )+ => ActionFn(1158); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant28(__symbols); let __sym3 = __pop_Variant25(__symbols); @@ -26030,7 +26088,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1155::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1158::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (5, 160) } @@ -26043,14 +26101,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportAsAlias = DottedName, "as", Identifier => ActionFn(1332); + // ImportAsAlias = DottedName, "as", Identifier => ActionFn(1334); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1332::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1334::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant72(__nt), __end)); (3, 161) } @@ -26063,11 +26121,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportAsAlias = DottedName => ActionFn(1333); + // ImportAsAlias = DottedName => ActionFn(1335); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1333::<>(source_code, mode, __sym0); + let __nt = super::__action1335::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant72(__nt), __end)); (1, 161) } @@ -26080,14 +26138,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportAsAlias = Identifier, "as", Identifier => ActionFn(1334); + // ImportAsAlias = Identifier, "as", Identifier => ActionFn(1336); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1334::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1336::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant72(__nt), __end)); (3, 162) } @@ -26100,11 +26158,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportAsAlias = Identifier => ActionFn(1335); + // ImportAsAlias = Identifier => ActionFn(1337); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1335::<>(source_code, mode, __sym0); + let __nt = super::__action1337::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant72(__nt), __end)); (1, 162) } @@ -26117,11 +26175,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportAsNames = OneOrMore> => ActionFn(1336); + // ImportAsNames = OneOrMore> => ActionFn(1338); let __sym0 = __pop_Variant73(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1336::<>(source_code, mode, __sym0); + let __nt = super::__action1338::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (1, 163) } @@ -26134,7 +26192,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportAsNames = "(", OneOrMore>, ",", ")" => ActionFn(1337); + // ImportAsNames = "(", OneOrMore>, ",", ")" => ActionFn(1339); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -26142,7 +26200,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1337::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1339::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (4, 163) } @@ -26155,14 +26213,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportAsNames = "(", OneOrMore>, ")" => ActionFn(1338); + // ImportAsNames = "(", OneOrMore>, ")" => ActionFn(1340); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant73(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1338::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1340::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (3, 163) } @@ -26175,11 +26233,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportAsNames = "*" => ActionFn(1339); + // ImportAsNames = "*" => ActionFn(1341); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1339::<>(source_code, mode, __sym0); + let __nt = super::__action1341::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (1, 163) } @@ -26226,10 +26284,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportDots* = => ActionFn(388); + // ImportDots* = => ActionFn(391); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action388::<>(source_code, mode, &__start, &__end); + let __nt = super::__action391::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant75(__nt), __end)); (0, 165) } @@ -26242,11 +26300,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportDots* = ImportDots+ => ActionFn(389); + // ImportDots* = ImportDots+ => ActionFn(392); let __sym0 = __pop_Variant75(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action389::<>(source_code, mode, __sym0); + let __nt = super::__action392::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant75(__nt), __end)); (1, 165) } @@ -26259,11 +26317,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportDots+ = ImportDots => ActionFn(386); + // ImportDots+ = ImportDots => ActionFn(389); let __sym0 = __pop_Variant74(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action386::<>(source_code, mode, __sym0); + let __nt = super::__action389::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant75(__nt), __end)); (1, 166) } @@ -26276,13 +26334,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportDots+ = ImportDots+, ImportDots => ActionFn(387); + // ImportDots+ = ImportDots+, ImportDots => ActionFn(390); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant74(__symbols); let __sym0 = __pop_Variant75(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action387::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action390::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant75(__nt), __end)); (2, 166) } @@ -26295,11 +26353,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportFromLocation = DottedName => ActionFn(1597); + // ImportFromLocation = DottedName => ActionFn(1601); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1597::<>(source_code, mode, __sym0); + let __nt = super::__action1601::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant76(__nt), __end)); (1, 167) } @@ -26312,13 +26370,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportFromLocation = ImportDots+, DottedName => ActionFn(1598); + // ImportFromLocation = ImportDots+, DottedName => ActionFn(1602); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant23(__symbols); let __sym0 = __pop_Variant75(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1598::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1602::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant76(__nt), __end)); (2, 167) } @@ -26348,13 +26406,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportStatement = "import", OneOrMore> => ActionFn(1340); + // ImportStatement = "import", OneOrMore> => ActionFn(1342); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant73(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1340::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1342::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (2, 168) } @@ -26367,7 +26425,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ImportStatement = "from", ImportFromLocation, "import", ImportAsNames => ActionFn(1341); + // ImportStatement = "from", ImportFromLocation, "import", ImportAsNames => ActionFn(1343); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant73(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -26375,7 +26433,7 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1341::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1343::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (4, 168) } @@ -26388,13 +26446,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // KwargParameter = "**", DoubleStarTypedParameter => ActionFn(1571); + // KwargParameter = "**", DoubleStarTypedParameter => ActionFn(1575); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant63(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1571::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1575::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant9(__nt), __end)); (2, 172) } @@ -26407,11 +26465,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // KwargParameter = "**" => ActionFn(1572); + // KwargParameter = "**" => ActionFn(1576); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1572::<>(source_code, mode, __sym0); + let __nt = super::__action1576::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant9(__nt), __end)); (1, 172) } @@ -26424,13 +26482,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // KwargParameter = "**", StarUntypedParameter => ActionFn(1016); + // KwargParameter = "**", StarUntypedParameter => ActionFn(1019); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant63(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1016::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1019::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant9(__nt), __end)); (2, 173) } @@ -26443,11 +26501,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // KwargParameter = "**" => ActionFn(1017); + // KwargParameter = "**" => ActionFn(1020); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1017::<>(source_code, mode, __sym0); + let __nt = super::__action1020::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant9(__nt), __end)); (1, 173) } @@ -26460,13 +26518,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ListLiteralValues = OneOrMore, "," => ActionFn(622); + // ListLiteralValues = OneOrMore, "," => ActionFn(625); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action622::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action625::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (2, 175) } @@ -26479,11 +26537,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ListLiteralValues = OneOrMore => ActionFn(623); + // ListLiteralValues = OneOrMore => ActionFn(626); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action623::<>(source_code, mode, __sym0); + let __nt = super::__action626::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (1, 175) } @@ -26496,11 +26554,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ListLiteralValues? = ListLiteralValues => ActionFn(572); + // ListLiteralValues? = ListLiteralValues => ActionFn(575); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action572::<>(source_code, mode, __sym0); + let __nt = super::__action575::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant34(__nt), __end)); (1, 176) } @@ -26513,10 +26571,10 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ListLiteralValues? = => ActionFn(573); + // ListLiteralValues? = => ActionFn(576); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action573::<>(source_code, mode, &__start, &__end); + let __nt = super::__action576::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant34(__nt), __end)); (0, 176) } @@ -26529,11 +26587,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // LiteralPattern = "None" => ActionFn(1346); + // LiteralPattern = "None" => ActionFn(1348); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1346::<>(source_code, mode, __sym0); + let __nt = super::__action1348::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (1, 177) } @@ -26546,11 +26604,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // LiteralPattern = "True" => ActionFn(1347); + // LiteralPattern = "True" => ActionFn(1349); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1347::<>(source_code, mode, __sym0); + let __nt = super::__action1349::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (1, 177) } @@ -26563,11 +26621,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // LiteralPattern = "False" => ActionFn(1348); + // LiteralPattern = "False" => ActionFn(1350); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1348::<>(source_code, mode, __sym0); + let __nt = super::__action1350::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (1, 177) } @@ -26580,11 +26638,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // LiteralPattern = NumberExpr => ActionFn(1349); + // LiteralPattern = NumberExpr => ActionFn(1351); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1349::<>(source_code, mode, __sym0); + let __nt = super::__action1351::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (1, 177) } @@ -26597,15 +26655,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // LiteralPattern = AddOpExpr => ActionFn(1350); + // LiteralPattern = AddOpExpr => ActionFn(1352); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1350::<>(source_code, mode, __sym0); + let __nt = super::__action1352::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (1, 177) } - pub(crate) fn __reduce474< + pub(crate) fn __reduce473< >( source_code: &str, mode: Mode, @@ -26614,13 +26672,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MappingKey = MatchNameOrAttr => ActionFn(126); - let __sym0 = __pop_Variant44(__symbols); + // LiteralPattern = StringLiteral => ActionFn(1353); + let __sym0 = __pop_Variant69(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action126::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant44(__nt), __end)); - (1, 178) + let __nt = super::__action1353::<>(source_code, mode, __sym0); + __symbols.push((__start, __Symbol::Variant35(__nt), __end)); + (1, 177) } pub(crate) fn __reduce475< >( @@ -26631,8 +26689,8 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MappingKey = NumberExpr => ActionFn(127); - let __sym0 = __pop_Variant15(__symbols); + // MappingKey = MatchNameOrAttr => ActionFn(127); + let __sym0 = __pop_Variant44(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action127::<>(source_code, mode, __sym0); @@ -26648,8 +26706,8 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MappingKey = AddOpExpr => ActionFn(128); - let __sym0 = __pop_Variant15(__symbols); + // MappingKey = String => ActionFn(128); + let __sym0 = __pop_Variant44(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action128::<>(source_code, mode, __sym0); @@ -26665,11 +26723,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MappingKey = "None" => ActionFn(1352); - let __sym0 = __pop_Variant0(__symbols); + // MappingKey = NumberExpr => ActionFn(129); + let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1352::<>(source_code, mode, __sym0); + let __nt = super::__action129::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (1, 178) } @@ -26682,11 +26740,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MappingKey = "True" => ActionFn(1353); - let __sym0 = __pop_Variant0(__symbols); + // MappingKey = AddOpExpr => ActionFn(130); + let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1353::<>(source_code, mode, __sym0); + let __nt = super::__action130::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (1, 178) } @@ -26699,11 +26757,28 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MappingKey = "False" => ActionFn(1354); + // MappingKey = "None" => ActionFn(1355); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1354::<>(source_code, mode, __sym0); + let __nt = super::__action1355::<>(source_code, mode, __sym0); + __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + (1, 178) + } + pub(crate) fn __reduce480< + >( + source_code: &str, + mode: Mode, + __lookahead_start: Option<&TextSize>, + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)>, + _: core::marker::PhantomData<()>, + ) -> (usize, usize) + { + // MappingKey = "True" => ActionFn(1356); + let __sym0 = __pop_Variant0(__symbols); + let __start = __sym0.0; + let __end = __sym0.2; + let __nt = super::__action1356::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (1, 178) } @@ -26716,17 +26791,34 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MappingPattern = "{", "}" => ActionFn(1356); + // MappingKey = "False" => ActionFn(1357); + let __sym0 = __pop_Variant0(__symbols); + let __start = __sym0.0; + let __end = __sym0.2; + let __nt = super::__action1357::<>(source_code, mode, __sym0); + __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + (1, 178) + } + pub(crate) fn __reduce482< + >( + source_code: &str, + mode: Mode, + __lookahead_start: Option<&TextSize>, + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)>, + _: core::marker::PhantomData<()>, + ) -> (usize, usize) + { + // MappingPattern = "{", "}" => ActionFn(1358); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1356::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1358::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (2, 179) } - pub(crate) fn __reduce482< + pub(crate) fn __reduce483< >( source_code: &str, mode: Mode, @@ -26735,7 +26827,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MappingPattern = "{", OneOrMore, ",", "}" => ActionFn(1357); + // MappingPattern = "{", OneOrMore, ",", "}" => ActionFn(1359); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -26743,11 +26835,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1357::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1359::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (4, 179) } - pub(crate) fn __reduce483< + pub(crate) fn __reduce484< >( source_code: &str, mode: Mode, @@ -26756,18 +26848,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MappingPattern = "{", OneOrMore, "}" => ActionFn(1358); + // MappingPattern = "{", OneOrMore, "}" => ActionFn(1360); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant84(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1358::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1360::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (3, 179) } - pub(crate) fn __reduce484< + pub(crate) fn __reduce485< >( source_code: &str, mode: Mode, @@ -26776,7 +26868,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MappingPattern = "{", "**", Identifier, ",", "}" => ActionFn(1359); + // MappingPattern = "{", "**", Identifier, ",", "}" => ActionFn(1361); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -26785,11 +26877,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1359::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1361::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (5, 179) } - pub(crate) fn __reduce485< + pub(crate) fn __reduce486< >( source_code: &str, mode: Mode, @@ -26798,7 +26890,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MappingPattern = "{", "**", Identifier, "}" => ActionFn(1360); + // MappingPattern = "{", "**", Identifier, "}" => ActionFn(1362); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant23(__symbols); @@ -26806,11 +26898,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1360::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1362::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (4, 179) } - pub(crate) fn __reduce486< + pub(crate) fn __reduce487< >( source_code: &str, mode: Mode, @@ -26819,7 +26911,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MappingPattern = "{", OneOrMore, ",", "**", Identifier, ",", "}" => ActionFn(1361); + // MappingPattern = "{", OneOrMore, ",", "**", Identifier, ",", "}" => ActionFn(1363); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -26830,11 +26922,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1361::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1363::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (7, 179) } - pub(crate) fn __reduce487< + pub(crate) fn __reduce488< >( source_code: &str, mode: Mode, @@ -26843,7 +26935,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MappingPattern = "{", OneOrMore, ",", "**", Identifier, "}" => ActionFn(1362); + // MappingPattern = "{", OneOrMore, ",", "**", Identifier, "}" => ActionFn(1364); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant23(__symbols); @@ -26853,11 +26945,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = super::__action1362::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); + let __nt = super::__action1364::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (6, 179) } - pub(crate) fn __reduce488< + pub(crate) fn __reduce489< >( source_code: &str, mode: Mode, @@ -26866,7 +26958,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MatchCase = "case", Patterns, Guard, ":", Suite => ActionFn(1220); + // MatchCase = "case", Patterns, Guard, ":", Suite => ActionFn(1223); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant25(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -26875,11 +26967,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1220::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1223::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant77(__nt), __end)); (5, 180) } - pub(crate) fn __reduce489< + pub(crate) fn __reduce490< >( source_code: &str, mode: Mode, @@ -26888,7 +26980,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MatchCase = "case", Patterns, ":", Suite => ActionFn(1221); + // MatchCase = "case", Patterns, ":", Suite => ActionFn(1224); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant25(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -26896,11 +26988,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1221::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1224::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant77(__nt), __end)); (4, 180) } - pub(crate) fn __reduce490< + pub(crate) fn __reduce491< >( source_code: &str, mode: Mode, @@ -26909,15 +27001,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MatchCase+ = MatchCase => ActionFn(366); + // MatchCase+ = MatchCase => ActionFn(369); let __sym0 = __pop_Variant77(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action366::<>(source_code, mode, __sym0); + let __nt = super::__action369::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant78(__nt), __end)); (1, 181) } - pub(crate) fn __reduce491< + pub(crate) fn __reduce492< >( source_code: &str, mode: Mode, @@ -26926,17 +27018,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MatchCase+ = MatchCase+, MatchCase => ActionFn(367); + // MatchCase+ = MatchCase+, MatchCase => ActionFn(370); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant77(__symbols); let __sym0 = __pop_Variant78(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action367::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action370::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant78(__nt), __end)); (2, 181) } - pub(crate) fn __reduce492< + pub(crate) fn __reduce493< >( source_code: &str, mode: Mode, @@ -26945,18 +27037,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MatchKeywordEntry = Identifier, "=", Pattern => ActionFn(1363); + // MatchKeywordEntry = Identifier, "=", Pattern => ActionFn(1365); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant35(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1363::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1365::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant79(__nt), __end)); (3, 182) } - pub(crate) fn __reduce493< + pub(crate) fn __reduce494< >( source_code: &str, mode: Mode, @@ -26965,18 +27057,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MatchMappingEntry = MappingKey, ":", Pattern => ActionFn(133); + // MatchMappingEntry = MappingKey, ":", Pattern => ActionFn(134); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant35(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant44(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action133::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action134::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant80(__nt), __end)); (3, 183) } - pub(crate) fn __reduce494< + pub(crate) fn __reduce495< >( source_code: &str, mode: Mode, @@ -26985,15 +27077,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MatchName = Identifier => ActionFn(1364); + // MatchName = Identifier => ActionFn(1366); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1364::<>(source_code, mode, __sym0); + let __nt = super::__action1366::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (1, 184) } - pub(crate) fn __reduce495< + pub(crate) fn __reduce496< >( source_code: &str, mode: Mode, @@ -27002,18 +27094,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MatchNameOrAttr = MatchName, ".", Identifier => ActionFn(1365); + // MatchNameOrAttr = MatchName, ".", Identifier => ActionFn(1367); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant44(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1365::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1367::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (3, 185) } - pub(crate) fn __reduce496< + pub(crate) fn __reduce497< >( source_code: &str, mode: Mode, @@ -27022,18 +27114,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MatchNameOrAttr = MatchNameOrAttr, ".", Identifier => ActionFn(1366); + // MatchNameOrAttr = MatchNameOrAttr, ".", Identifier => ActionFn(1368); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant44(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1366::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1368::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); (3, 185) } - pub(crate) fn __reduce497< + pub(crate) fn __reduce498< >( source_code: &str, mode: Mode, @@ -27042,7 +27134,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MatchStatement = "match", TestOrStarNamedExpr, ":", "\n", Indent, MatchCase+, Dedent => ActionFn(861); + // MatchStatement = "match", TestOrStarNamedExpr, ":", "\n", Indent, MatchCase+, Dedent => ActionFn(862); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant78(__symbols); @@ -27053,11 +27145,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action861::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action862::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (7, 186) } - pub(crate) fn __reduce498< + pub(crate) fn __reduce499< >( source_code: &str, mode: Mode, @@ -27066,7 +27158,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MatchStatement = "match", TestOrStarNamedExpr, ",", ":", "\n", Indent, MatchCase+, Dedent => ActionFn(1367); + // MatchStatement = "match", TestOrStarNamedExpr, ",", ":", "\n", Indent, MatchCase+, Dedent => ActionFn(1369); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant0(__symbols); let __sym6 = __pop_Variant78(__symbols); @@ -27078,11 +27170,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = super::__action1367::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7); + let __nt = super::__action1369::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (8, 186) } - pub(crate) fn __reduce499< + pub(crate) fn __reduce500< >( source_code: &str, mode: Mode, @@ -27091,7 +27183,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MatchStatement = "match", TwoOrMore, ",", ":", "\n", Indent, MatchCase+, Dedent => ActionFn(1368); + // MatchStatement = "match", TwoOrMoreSep, ",", ":", "\n", Indent, MatchCase+, Dedent => ActionFn(1370); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant0(__symbols); let __sym6 = __pop_Variant78(__symbols); @@ -27103,11 +27195,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym7.2; - let __nt = super::__action1368::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7); + let __nt = super::__action1370::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (8, 186) } - pub(crate) fn __reduce500< + pub(crate) fn __reduce501< >( source_code: &str, mode: Mode, @@ -27116,7 +27208,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MatchStatement = "match", TwoOrMore, ":", "\n", Indent, MatchCase+, Dedent => ActionFn(1369); + // MatchStatement = "match", TwoOrMoreSep, ":", "\n", Indent, MatchCase+, Dedent => ActionFn(1371); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant78(__symbols); @@ -27127,11 +27219,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1369::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1371::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (7, 186) } - pub(crate) fn __reduce501< + pub(crate) fn __reduce502< >( source_code: &str, mode: Mode, @@ -27140,15 +27232,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MulOp = "*" => ActionFn(198); + // MulOp = "*" => ActionFn(199); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action198::<>(source_code, mode, __sym0); + let __nt = super::__action199::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant49(__nt), __end)); (1, 187) } - pub(crate) fn __reduce502< + pub(crate) fn __reduce503< >( source_code: &str, mode: Mode, @@ -27157,15 +27249,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MulOp = "/" => ActionFn(199); + // MulOp = "/" => ActionFn(200); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action199::<>(source_code, mode, __sym0); + let __nt = super::__action200::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant49(__nt), __end)); (1, 187) } - pub(crate) fn __reduce503< + pub(crate) fn __reduce504< >( source_code: &str, mode: Mode, @@ -27174,15 +27266,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MulOp = "//" => ActionFn(200); + // MulOp = "//" => ActionFn(201); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action200::<>(source_code, mode, __sym0); + let __nt = super::__action201::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant49(__nt), __end)); (1, 187) } - pub(crate) fn __reduce504< + pub(crate) fn __reduce505< >( source_code: &str, mode: Mode, @@ -27191,15 +27283,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MulOp = "%" => ActionFn(201); + // MulOp = "%" => ActionFn(202); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action201::<>(source_code, mode, __sym0); + let __nt = super::__action202::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant49(__nt), __end)); (1, 187) } - pub(crate) fn __reduce505< + pub(crate) fn __reduce506< >( source_code: &str, mode: Mode, @@ -27208,15 +27300,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // MulOp = "@" => ActionFn(202); + // MulOp = "@" => ActionFn(203); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action202::<>(source_code, mode, __sym0); + let __nt = super::__action203::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant49(__nt), __end)); (1, 187) } - pub(crate) fn __reduce506< + pub(crate) fn __reduce507< >( source_code: &str, mode: Mode, @@ -27225,18 +27317,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // NamedExpression = NamedExpressionName, ":=", Test<"all"> => ActionFn(1370); + // NamedExpression = NamedExpressionName, ":=", Test<"all"> => ActionFn(1372); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1370::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1372::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 188) } - pub(crate) fn __reduce507< + pub(crate) fn __reduce508< >( source_code: &str, mode: Mode, @@ -27245,15 +27337,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // NamedExpressionName = Identifier => ActionFn(1371); + // NamedExpressionName = Identifier => ActionFn(1373); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1371::<>(source_code, mode, __sym0); + let __nt = super::__action1373::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 189) } - pub(crate) fn __reduce508< + pub(crate) fn __reduce509< >( source_code: &str, mode: Mode, @@ -27262,15 +27354,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // NamedExpressionTest = NamedExpression => ActionFn(179); + // NamedExpressionTest = NamedExpression => ActionFn(180); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action179::<>(source_code, mode, __sym0); + let __nt = super::__action180::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 190) } - pub(crate) fn __reduce509< + pub(crate) fn __reduce510< >( source_code: &str, mode: Mode, @@ -27279,15 +27371,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // NamedExpressionTest = Test<"all"> => ActionFn(180); + // NamedExpressionTest = Test<"all"> => ActionFn(181); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action180::<>(source_code, mode, __sym0); + let __nt = super::__action181::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 190) } - pub(crate) fn __reduce510< + pub(crate) fn __reduce511< >( source_code: &str, mode: Mode, @@ -27304,7 +27396,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 191) } - pub(crate) fn __reduce511< + pub(crate) fn __reduce512< >( source_code: &str, mode: Mode, @@ -27321,7 +27413,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 191) } - pub(crate) fn __reduce512< + pub(crate) fn __reduce513< >( source_code: &str, mode: Mode, @@ -27330,17 +27422,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // NonlocalStatement = "nonlocal", OneOrMore => ActionFn(1372); + // NonlocalStatement = "nonlocal", OneOrMore => ActionFn(1374); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant82(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1372::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1374::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (2, 192) } - pub(crate) fn __reduce513< + pub(crate) fn __reduce514< >( source_code: &str, mode: Mode, @@ -27349,17 +27441,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // NotTest<"all"> = "not", NotTest<"all"> => ActionFn(1373); + // NotTest<"all"> = "not", NotTest<"all"> => ActionFn(1375); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1373::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1375::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 193) } - pub(crate) fn __reduce514< + pub(crate) fn __reduce515< >( source_code: &str, mode: Mode, @@ -27368,15 +27460,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // NotTest<"all"> = Comparison<"all"> => ActionFn(475); + // NotTest<"all"> = Comparison<"all"> => ActionFn(478); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action475::<>(source_code, mode, __sym0); + let __nt = super::__action478::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 193) } - pub(crate) fn __reduce515< + pub(crate) fn __reduce516< >( source_code: &str, mode: Mode, @@ -27385,17 +27477,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // NotTest<"no-withitems"> = "not", NotTest<"all"> => ActionFn(1374); + // NotTest<"no-withitems"> = "not", NotTest<"all"> => ActionFn(1376); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1374::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1376::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 194) } - pub(crate) fn __reduce516< + pub(crate) fn __reduce517< >( source_code: &str, mode: Mode, @@ -27404,15 +27496,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // NotTest<"no-withitems"> = Comparison<"no-withitems"> => ActionFn(518); + // NotTest<"no-withitems"> = Comparison<"no-withitems"> => ActionFn(521); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action518::<>(source_code, mode, __sym0); + let __nt = super::__action521::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 194) } - pub(crate) fn __reduce517< + pub(crate) fn __reduce518< >( source_code: &str, mode: Mode, @@ -27421,15 +27513,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Number = int => ActionFn(243); + // Number = int => ActionFn(246); let __sym0 = __pop_Variant4(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action243::<>(source_code, mode, __sym0); + let __nt = super::__action246::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant81(__nt), __end)); (1, 195) } - pub(crate) fn __reduce518< + pub(crate) fn __reduce519< >( source_code: &str, mode: Mode, @@ -27438,15 +27530,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Number = float => ActionFn(244); + // Number = float => ActionFn(247); let __sym0 = __pop_Variant2(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action244::<>(source_code, mode, __sym0); + let __nt = super::__action247::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant81(__nt), __end)); (1, 195) } - pub(crate) fn __reduce519< + pub(crate) fn __reduce520< >( source_code: &str, mode: Mode, @@ -27455,15 +27547,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Number = complex => ActionFn(245); + // Number = complex => ActionFn(248); let __sym0 = __pop_Variant1(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action245::<>(source_code, mode, __sym0); + let __nt = super::__action248::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant81(__nt), __end)); (1, 195) } - pub(crate) fn __reduce520< + pub(crate) fn __reduce521< >( source_code: &str, mode: Mode, @@ -27472,15 +27564,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // NumberAtom = Number => ActionFn(1375); + // NumberAtom = Number => ActionFn(1377); let __sym0 = __pop_Variant81(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1375::<>(source_code, mode, __sym0); + let __nt = super::__action1377::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 196) } - pub(crate) fn __reduce521< + pub(crate) fn __reduce522< >( source_code: &str, mode: Mode, @@ -27497,7 +27589,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 197) } - pub(crate) fn __reduce522< + pub(crate) fn __reduce523< >( source_code: &str, mode: Mode, @@ -27506,17 +27598,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // NumberExpr = "-", NumberAtom => ActionFn(1376); + // NumberExpr = "-", NumberAtom => ActionFn(1378); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1376::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1378::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 197) } - pub(crate) fn __reduce523< + pub(crate) fn __reduce524< >( source_code: &str, mode: Mode, @@ -27525,15 +27617,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = DictElement => ActionFn(260); + // OneOrMore = DictElement => ActionFn(263); let __sym0 = __pop_Variant59(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action260::<>(source_code, mode, __sym0); + let __nt = super::__action263::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant61(__nt), __end)); (1, 198) } - pub(crate) fn __reduce524< + pub(crate) fn __reduce525< >( source_code: &str, mode: Mode, @@ -27542,18 +27634,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = OneOrMore, ",", DictElement => ActionFn(261); + // OneOrMore = OneOrMore, ",", DictElement => ActionFn(264); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant59(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant61(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action261::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action264::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant61(__nt), __end)); (3, 198) } - pub(crate) fn __reduce525< + pub(crate) fn __reduce526< >( source_code: &str, mode: Mode, @@ -27562,15 +27654,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = ExpressionOrStarExpression => ActionFn(257); + // OneOrMore = ExpressionOrStarExpression => ActionFn(260); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action257::<>(source_code, mode, __sym0); + let __nt = super::__action260::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (1, 199) } - pub(crate) fn __reduce526< + pub(crate) fn __reduce527< >( source_code: &str, mode: Mode, @@ -27579,18 +27671,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = OneOrMore, ",", ExpressionOrStarExpression => ActionFn(258); + // OneOrMore = OneOrMore, ",", ExpressionOrStarExpression => ActionFn(261); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action258::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action261::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (3, 199) } - pub(crate) fn __reduce527< + pub(crate) fn __reduce528< >( source_code: &str, mode: Mode, @@ -27599,15 +27691,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = Identifier => ActionFn(376); + // OneOrMore = Identifier => ActionFn(379); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action376::<>(source_code, mode, __sym0); + let __nt = super::__action379::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant82(__nt), __end)); (1, 200) } - pub(crate) fn __reduce528< + pub(crate) fn __reduce529< >( source_code: &str, mode: Mode, @@ -27616,18 +27708,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = OneOrMore, ",", Identifier => ActionFn(377); + // OneOrMore = OneOrMore, ",", Identifier => ActionFn(380); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant82(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action377::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action380::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant82(__nt), __end)); (3, 200) } - pub(crate) fn __reduce529< + pub(crate) fn __reduce530< >( source_code: &str, mode: Mode, @@ -27636,18 +27728,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore> = DottedName, "as", Identifier => ActionFn(1589); + // OneOrMore> = DottedName, "as", Identifier => ActionFn(1593); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1589::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1593::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (3, 201) } - pub(crate) fn __reduce530< + pub(crate) fn __reduce531< >( source_code: &str, mode: Mode, @@ -27656,15 +27748,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore> = DottedName => ActionFn(1590); + // OneOrMore> = DottedName => ActionFn(1594); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1590::<>(source_code, mode, __sym0); + let __nt = super::__action1594::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (1, 201) } - pub(crate) fn __reduce531< + pub(crate) fn __reduce532< >( source_code: &str, mode: Mode, @@ -27673,7 +27765,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore> = OneOrMore>, ",", DottedName, "as", Identifier => ActionFn(1591); + // OneOrMore> = OneOrMore>, ",", DottedName, "as", Identifier => ActionFn(1595); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant23(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -27682,11 +27774,11 @@ mod __parse__Top { let __sym0 = __pop_Variant73(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1591::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1595::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (5, 201) } - pub(crate) fn __reduce532< + pub(crate) fn __reduce533< >( source_code: &str, mode: Mode, @@ -27695,18 +27787,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore> = OneOrMore>, ",", DottedName => ActionFn(1592); + // OneOrMore> = OneOrMore>, ",", DottedName => ActionFn(1596); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant73(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1592::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1596::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (3, 201) } - pub(crate) fn __reduce533< + pub(crate) fn __reduce534< >( source_code: &str, mode: Mode, @@ -27715,18 +27807,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore> = Identifier, "as", Identifier => ActionFn(1593); + // OneOrMore> = Identifier, "as", Identifier => ActionFn(1597); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1593::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1597::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (3, 202) } - pub(crate) fn __reduce534< + pub(crate) fn __reduce535< >( source_code: &str, mode: Mode, @@ -27735,15 +27827,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore> = Identifier => ActionFn(1594); + // OneOrMore> = Identifier => ActionFn(1598); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1594::<>(source_code, mode, __sym0); + let __nt = super::__action1598::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (1, 202) } - pub(crate) fn __reduce535< + pub(crate) fn __reduce536< >( source_code: &str, mode: Mode, @@ -27752,7 +27844,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore> = OneOrMore>, ",", Identifier, "as", Identifier => ActionFn(1595); + // OneOrMore> = OneOrMore>, ",", Identifier, "as", Identifier => ActionFn(1599); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant23(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -27761,11 +27853,11 @@ mod __parse__Top { let __sym0 = __pop_Variant73(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1595::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1599::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (5, 202) } - pub(crate) fn __reduce536< + pub(crate) fn __reduce537< >( source_code: &str, mode: Mode, @@ -27774,18 +27866,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore> = OneOrMore>, ",", Identifier => ActionFn(1596); + // OneOrMore> = OneOrMore>, ",", Identifier => ActionFn(1600); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant73(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1596::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1600::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (3, 202) } - pub(crate) fn __reduce537< + pub(crate) fn __reduce538< >( source_code: &str, mode: Mode, @@ -27794,15 +27886,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = MatchKeywordEntry => ActionFn(343); + // OneOrMore = MatchKeywordEntry => ActionFn(348); let __sym0 = __pop_Variant79(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action343::<>(source_code, mode, __sym0); + let __nt = super::__action348::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant83(__nt), __end)); (1, 203) } - pub(crate) fn __reduce538< + pub(crate) fn __reduce539< >( source_code: &str, mode: Mode, @@ -27811,18 +27903,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = OneOrMore, ",", MatchKeywordEntry => ActionFn(344); + // OneOrMore = OneOrMore, ",", MatchKeywordEntry => ActionFn(349); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant79(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant83(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action344::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action349::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant83(__nt), __end)); (3, 203) } - pub(crate) fn __reduce539< + pub(crate) fn __reduce540< >( source_code: &str, mode: Mode, @@ -27831,15 +27923,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = MatchMappingEntry => ActionFn(347); + // OneOrMore = MatchMappingEntry => ActionFn(352); let __sym0 = __pop_Variant80(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action347::<>(source_code, mode, __sym0); + let __nt = super::__action352::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant84(__nt), __end)); (1, 204) } - pub(crate) fn __reduce540< + pub(crate) fn __reduce541< >( source_code: &str, mode: Mode, @@ -27848,18 +27940,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = OneOrMore, ",", MatchMappingEntry => ActionFn(348); + // OneOrMore = OneOrMore, ",", MatchMappingEntry => ActionFn(353); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant80(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant84(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action348::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action353::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant84(__nt), __end)); (3, 204) } - pub(crate) fn __reduce541< + pub(crate) fn __reduce542< >( source_code: &str, mode: Mode, @@ -27868,15 +27960,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore> = ParameterDef => ActionFn(487); + // OneOrMore> = ParameterDef => ActionFn(490); let __sym0 = __pop_Variant11(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action487::<>(source_code, mode, __sym0); + let __nt = super::__action490::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant85(__nt), __end)); (1, 205) } - pub(crate) fn __reduce542< + pub(crate) fn __reduce543< >( source_code: &str, mode: Mode, @@ -27885,18 +27977,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore> = OneOrMore>, ",", ParameterDef => ActionFn(488); + // OneOrMore> = OneOrMore>, ",", ParameterDef => ActionFn(491); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant11(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action488::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action491::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant85(__nt), __end)); (3, 205) } - pub(crate) fn __reduce543< + pub(crate) fn __reduce544< >( source_code: &str, mode: Mode, @@ -27905,15 +27997,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore> = ParameterDef => ActionFn(476); + // OneOrMore> = ParameterDef => ActionFn(479); let __sym0 = __pop_Variant11(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action476::<>(source_code, mode, __sym0); + let __nt = super::__action479::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant85(__nt), __end)); (1, 206) } - pub(crate) fn __reduce544< + pub(crate) fn __reduce545< >( source_code: &str, mode: Mode, @@ -27922,18 +28014,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore> = OneOrMore>, ",", ParameterDef => ActionFn(477); + // OneOrMore> = OneOrMore>, ",", ParameterDef => ActionFn(480); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant11(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action477::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action480::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant85(__nt), __end)); (3, 206) } - pub(crate) fn __reduce545< + pub(crate) fn __reduce546< >( source_code: &str, mode: Mode, @@ -27942,15 +28034,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = Pattern => ActionFn(345); + // OneOrMore = Pattern => ActionFn(350); let __sym0 = __pop_Variant35(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action345::<>(source_code, mode, __sym0); + let __nt = super::__action350::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); (1, 207) } - pub(crate) fn __reduce546< + pub(crate) fn __reduce547< >( source_code: &str, mode: Mode, @@ -27959,18 +28051,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = OneOrMore, ",", Pattern => ActionFn(346); + // OneOrMore = OneOrMore, ",", Pattern => ActionFn(351); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant35(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant53(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action346::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action351::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); (3, 207) } - pub(crate) fn __reduce547< + pub(crate) fn __reduce548< >( source_code: &str, mode: Mode, @@ -27979,15 +28071,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore> = Test<"all"> => ActionFn(308); + // OneOrMore> = Test<"all"> => ActionFn(313); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action308::<>(source_code, mode, __sym0); + let __nt = super::__action313::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (1, 208) } - pub(crate) fn __reduce548< + pub(crate) fn __reduce549< >( source_code: &str, mode: Mode, @@ -27996,18 +28088,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore> = OneOrMore>, ",", Test<"all"> => ActionFn(309); + // OneOrMore> = OneOrMore>, ",", Test<"all"> => ActionFn(314); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action309::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action314::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (3, 208) } - pub(crate) fn __reduce549< + pub(crate) fn __reduce550< >( source_code: &str, mode: Mode, @@ -28016,15 +28108,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = TestOrStarExpr => ActionFn(455); + // OneOrMore = TestOrStarExpr => ActionFn(458); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action455::<>(source_code, mode, __sym0); + let __nt = super::__action458::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (1, 209) } - pub(crate) fn __reduce550< + pub(crate) fn __reduce551< >( source_code: &str, mode: Mode, @@ -28033,18 +28125,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = OneOrMore, ",", TestOrStarExpr => ActionFn(456); + // OneOrMore = OneOrMore, ",", TestOrStarExpr => ActionFn(459); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action456::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action459::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (3, 209) } - pub(crate) fn __reduce551< + pub(crate) fn __reduce552< >( source_code: &str, mode: Mode, @@ -28053,15 +28145,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = TestOrStarNamedExpr => ActionFn(262); + // OneOrMore = TestOrStarNamedExpr => ActionFn(265); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action262::<>(source_code, mode, __sym0); + let __nt = super::__action265::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (1, 210) } - pub(crate) fn __reduce552< + pub(crate) fn __reduce553< >( source_code: &str, mode: Mode, @@ -28070,18 +28162,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = OneOrMore, ",", TestOrStarNamedExpr => ActionFn(263); + // OneOrMore = OneOrMore, ",", TestOrStarNamedExpr => ActionFn(266); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action263::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action266::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (3, 210) } - pub(crate) fn __reduce553< + pub(crate) fn __reduce554< >( source_code: &str, mode: Mode, @@ -28090,15 +28182,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = TypeParam => ActionFn(284); + // OneOrMore = TypeParam => ActionFn(289); let __sym0 = __pop_Variant97(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action284::<>(source_code, mode, __sym0); + let __nt = super::__action289::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant86(__nt), __end)); (1, 211) } - pub(crate) fn __reduce554< + pub(crate) fn __reduce555< >( source_code: &str, mode: Mode, @@ -28107,18 +28199,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OneOrMore = OneOrMore, ",", TypeParam => ActionFn(285); + // OneOrMore = OneOrMore, ",", TypeParam => ActionFn(290); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant97(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant86(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action285::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action290::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant86(__nt), __end)); (3, 211) } - pub(crate) fn __reduce555< + pub(crate) fn __reduce556< >( source_code: &str, mode: Mode, @@ -28135,7 +28227,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (1, 212) } - pub(crate) fn __reduce556< + pub(crate) fn __reduce557< >( source_code: &str, mode: Mode, @@ -28144,15 +28236,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OrPattern = TwoOrMore => ActionFn(1377); + // OrPattern = TwoOrMoreSep => ActionFn(1379); let __sym0 = __pop_Variant53(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1377::<>(source_code, mode, __sym0); + let __nt = super::__action1379::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (1, 212) } - pub(crate) fn __reduce557< + pub(crate) fn __reduce558< >( source_code: &str, mode: Mode, @@ -28161,17 +28253,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OrTest<"all"> = (> "or")+, AndTest<"all"> => ActionFn(1378); + // OrTest<"all"> = (> "or")+, AndTest<"all"> => ActionFn(1380); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1378::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1380::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 213) } - pub(crate) fn __reduce558< + pub(crate) fn __reduce559< >( source_code: &str, mode: Mode, @@ -28180,15 +28272,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OrTest<"all"> = AndTest<"all"> => ActionFn(253); + // OrTest<"all"> = AndTest<"all"> => ActionFn(256); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action253::<>(source_code, mode, __sym0); + let __nt = super::__action256::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 213) } - pub(crate) fn __reduce559< + pub(crate) fn __reduce560< >( source_code: &str, mode: Mode, @@ -28197,17 +28289,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OrTest<"no-withitems"> = (> "or")+, AndTest<"all"> => ActionFn(1379); + // OrTest<"no-withitems"> = (> "or")+, AndTest<"all"> => ActionFn(1381); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant17(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1379::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1381::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 214) } - pub(crate) fn __reduce560< + pub(crate) fn __reduce561< >( source_code: &str, mode: Mode, @@ -28216,15 +28308,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // OrTest<"no-withitems"> = AndTest<"no-withitems"> => ActionFn(501); + // OrTest<"no-withitems"> = AndTest<"no-withitems"> => ActionFn(504); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action501::<>(source_code, mode, __sym0); + let __nt = super::__action504::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 214) } - pub(crate) fn __reduce561< + pub(crate) fn __reduce562< >( source_code: &str, mode: Mode, @@ -28233,15 +28325,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterDef = TypedParameter => ActionFn(494); + // ParameterDef = TypedParameter => ActionFn(497); let __sym0 = __pop_Variant11(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action494::<>(source_code, mode, __sym0); + let __nt = super::__action497::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant11(__nt), __end)); (1, 215) } - pub(crate) fn __reduce562< + pub(crate) fn __reduce563< >( source_code: &str, mode: Mode, @@ -28250,18 +28342,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterDef = TypedParameter, "=", Test<"all"> => ActionFn(1380); + // ParameterDef = TypedParameter, "=", Test<"all"> => ActionFn(1382); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant11(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1380::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1382::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant11(__nt), __end)); (3, 215) } - pub(crate) fn __reduce563< + pub(crate) fn __reduce564< >( source_code: &str, mode: Mode, @@ -28270,15 +28362,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterDef = UntypedParameter => ActionFn(483); + // ParameterDef = UntypedParameter => ActionFn(486); let __sym0 = __pop_Variant11(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action483::<>(source_code, mode, __sym0); + let __nt = super::__action486::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant11(__nt), __end)); (1, 216) } - pub(crate) fn __reduce564< + pub(crate) fn __reduce565< >( source_code: &str, mode: Mode, @@ -28287,18 +28379,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterDef = UntypedParameter, "=", Test<"all"> => ActionFn(1381); + // ParameterDef = UntypedParameter, "=", Test<"all"> => ActionFn(1383); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant11(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1381::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1383::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant11(__nt), __end)); (3, 216) } - pub(crate) fn __reduce565< + pub(crate) fn __reduce566< >( source_code: &str, mode: Mode, @@ -28307,15 +28399,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterDefs = OneOrMore> => ActionFn(443); + // ParameterDefs = OneOrMore> => ActionFn(446); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action443::<>(source_code, mode, __sym0); + let __nt = super::__action446::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant87(__nt), __end)); (1, 217) } - pub(crate) fn __reduce566< + pub(crate) fn __reduce567< >( source_code: &str, mode: Mode, @@ -28324,18 +28416,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterDefs = OneOrMore>, ",", "/" => ActionFn(698); + // ParameterDefs = OneOrMore>, ",", "/" => ActionFn(701); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action698::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action701::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant87(__nt), __end)); (3, 217) } - pub(crate) fn __reduce567< + pub(crate) fn __reduce568< >( source_code: &str, mode: Mode, @@ -28344,7 +28436,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterDefs = OneOrMore>, ",", "/", ("," >)+ => ActionFn(699); + // ParameterDefs = OneOrMore>, ",", "/", ("," >)+ => ActionFn(702); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -28352,11 +28444,11 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action699::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action702::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant87(__nt), __end)); (4, 217) } - pub(crate) fn __reduce568< + pub(crate) fn __reduce569< >( source_code: &str, mode: Mode, @@ -28365,15 +28457,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterDefs = OneOrMore> => ActionFn(451); + // ParameterDefs = OneOrMore> => ActionFn(454); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action451::<>(source_code, mode, __sym0); + let __nt = super::__action454::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant87(__nt), __end)); (1, 218) } - pub(crate) fn __reduce569< + pub(crate) fn __reduce570< >( source_code: &str, mode: Mode, @@ -28382,18 +28474,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterDefs = OneOrMore>, ",", "/" => ActionFn(706); + // ParameterDefs = OneOrMore>, ",", "/" => ActionFn(709); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action706::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action709::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant87(__nt), __end)); (3, 218) } - pub(crate) fn __reduce570< + pub(crate) fn __reduce571< >( source_code: &str, mode: Mode, @@ -28402,7 +28494,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterDefs = OneOrMore>, ",", "/", ("," >)+ => ActionFn(707); + // ParameterDefs = OneOrMore>, ",", "/", ("," >)+ => ActionFn(710); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -28410,11 +28502,11 @@ mod __parse__Top { let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action707::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action710::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant87(__nt), __end)); (4, 218) } - pub(crate) fn __reduce647< + pub(crate) fn __reduce648< >( source_code: &str, mode: Mode, @@ -28423,17 +28515,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterList = KwargParameter, "," => ActionFn(1418); + // ParameterList = KwargParameter, "," => ActionFn(1420); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant9(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1418::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1420::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (2, 219) } - pub(crate) fn __reduce648< + pub(crate) fn __reduce649< >( source_code: &str, mode: Mode, @@ -28442,15 +28534,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterList = KwargParameter => ActionFn(1419); + // ParameterList = KwargParameter => ActionFn(1421); let __sym0 = __pop_Variant9(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1419::<>(source_code, mode, __sym0); + let __nt = super::__action1421::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (1, 219) } - pub(crate) fn __reduce725< + pub(crate) fn __reduce726< >( source_code: &str, mode: Mode, @@ -28459,17 +28551,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterList = KwargParameter, "," => ActionFn(1456); + // ParameterList = KwargParameter, "," => ActionFn(1458); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant9(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1456::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1458::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (2, 220) } - pub(crate) fn __reduce726< + pub(crate) fn __reduce727< >( source_code: &str, mode: Mode, @@ -28478,15 +28570,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterList = KwargParameter => ActionFn(1457); + // ParameterList = KwargParameter => ActionFn(1459); let __sym0 = __pop_Variant9(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1457::<>(source_code, mode, __sym0); + let __nt = super::__action1459::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant46(__nt), __end)); (1, 220) } - pub(crate) fn __reduce727< + pub(crate) fn __reduce728< >( source_code: &str, mode: Mode, @@ -28495,15 +28587,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterList? = ParameterList => ActionFn(278); + // ParameterList? = ParameterList => ActionFn(283); let __sym0 = __pop_Variant46(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action278::<>(source_code, mode, __sym0); + let __nt = super::__action283::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant47(__nt), __end)); (1, 221) } - pub(crate) fn __reduce728< + pub(crate) fn __reduce729< >( source_code: &str, mode: Mode, @@ -28512,14 +28604,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ParameterList? = => ActionFn(279); + // ParameterList? = => ActionFn(284); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action279::<>(source_code, mode, &__start, &__end); + let __nt = super::__action284::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant47(__nt), __end)); (0, 221) } - pub(crate) fn __reduce747< + pub(crate) fn __reduce748< >( source_code: &str, mode: Mode, @@ -28528,15 +28620,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // PassStatement = "pass" => ActionFn(1460); + // PassStatement = "pass" => ActionFn(1462); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1460::<>(source_code, mode, __sym0); + let __nt = super::__action1462::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 225) } - pub(crate) fn __reduce748< + pub(crate) fn __reduce749< >( source_code: &str, mode: Mode, @@ -28553,7 +28645,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (1, 226) } - pub(crate) fn __reduce749< + pub(crate) fn __reduce750< >( source_code: &str, mode: Mode, @@ -28570,7 +28662,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (1, 226) } - pub(crate) fn __reduce750< + pub(crate) fn __reduce751< >( source_code: &str, mode: Mode, @@ -28579,15 +28671,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Pattern? = Pattern => ActionFn(426); + // Pattern? = Pattern => ActionFn(429); let __sym0 = __pop_Variant35(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action426::<>(source_code, mode, __sym0); + let __nt = super::__action429::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant88(__nt), __end)); (1, 227) } - pub(crate) fn __reduce751< + pub(crate) fn __reduce752< >( source_code: &str, mode: Mode, @@ -28596,14 +28688,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Pattern? = => ActionFn(427); + // Pattern? = => ActionFn(430); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action427::<>(source_code, mode, &__start, &__end); + let __nt = super::__action430::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant88(__nt), __end)); (0, 227) } - pub(crate) fn __reduce752< + pub(crate) fn __reduce753< >( source_code: &str, mode: Mode, @@ -28612,7 +28704,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // PatternArguments = "(", OneOrMore, ",", OneOrMore, ",", ")" => ActionFn(1461); + // PatternArguments = "(", OneOrMore, ",", OneOrMore, ",", ")" => ActionFn(1463); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -28622,11 +28714,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = super::__action1461::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); + let __nt = super::__action1463::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant89(__nt), __end)); (6, 228) } - pub(crate) fn __reduce753< + pub(crate) fn __reduce754< >( source_code: &str, mode: Mode, @@ -28635,7 +28727,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // PatternArguments = "(", OneOrMore, ",", OneOrMore, ")" => ActionFn(1462); + // PatternArguments = "(", OneOrMore, ",", OneOrMore, ")" => ActionFn(1464); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant83(__symbols); @@ -28644,11 +28736,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1462::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1464::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant89(__nt), __end)); (5, 228) } - pub(crate) fn __reduce754< + pub(crate) fn __reduce755< >( source_code: &str, mode: Mode, @@ -28657,7 +28749,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // PatternArguments = "(", OneOrMore, ",", ")" => ActionFn(1463); + // PatternArguments = "(", OneOrMore, ",", ")" => ActionFn(1465); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -28665,11 +28757,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1463::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1465::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant89(__nt), __end)); (4, 228) } - pub(crate) fn __reduce755< + pub(crate) fn __reduce756< >( source_code: &str, mode: Mode, @@ -28678,18 +28770,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // PatternArguments = "(", OneOrMore, ")" => ActionFn(1464); + // PatternArguments = "(", OneOrMore, ")" => ActionFn(1466); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant53(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1464::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1466::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant89(__nt), __end)); (3, 228) } - pub(crate) fn __reduce756< + pub(crate) fn __reduce757< >( source_code: &str, mode: Mode, @@ -28698,7 +28790,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // PatternArguments = "(", OneOrMore, ",", ")" => ActionFn(1465); + // PatternArguments = "(", OneOrMore, ",", ")" => ActionFn(1467); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -28706,11 +28798,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1465::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1467::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant89(__nt), __end)); (4, 228) } - pub(crate) fn __reduce757< + pub(crate) fn __reduce758< >( source_code: &str, mode: Mode, @@ -28719,18 +28811,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // PatternArguments = "(", OneOrMore, ")" => ActionFn(1466); + // PatternArguments = "(", OneOrMore, ")" => ActionFn(1468); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant83(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1466::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1468::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant89(__nt), __end)); (3, 228) } - pub(crate) fn __reduce758< + pub(crate) fn __reduce759< >( source_code: &str, mode: Mode, @@ -28739,17 +28831,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // PatternArguments = "(", ")" => ActionFn(1467); + // PatternArguments = "(", ")" => ActionFn(1469); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1467::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1469::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant89(__nt), __end)); (2, 228) } - pub(crate) fn __reduce759< + pub(crate) fn __reduce760< >( source_code: &str, mode: Mode, @@ -28758,17 +28850,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Patterns = Pattern, "," => ActionFn(1468); + // Patterns = Pattern, "," => ActionFn(1470); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant35(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1468::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1470::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (2, 229) } - pub(crate) fn __reduce760< + pub(crate) fn __reduce761< >( source_code: &str, mode: Mode, @@ -28777,17 +28869,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Patterns = TwoOrMore, "," => ActionFn(1469); + // Patterns = TwoOrMoreSep, "," => ActionFn(1471); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant53(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1469::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1471::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (2, 229) } - pub(crate) fn __reduce761< + pub(crate) fn __reduce762< >( source_code: &str, mode: Mode, @@ -28796,15 +28888,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Patterns = TwoOrMore => ActionFn(1470); + // Patterns = TwoOrMoreSep => ActionFn(1472); let __sym0 = __pop_Variant53(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1470::<>(source_code, mode, __sym0); + let __nt = super::__action1472::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (1, 229) } - pub(crate) fn __reduce762< + pub(crate) fn __reduce763< >( source_code: &str, mode: Mode, @@ -28821,7 +28913,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (1, 229) } - pub(crate) fn __reduce763< + pub(crate) fn __reduce764< >( source_code: &str, mode: Mode, @@ -28830,18 +28922,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Power<"all"> = AtomExpr<"all">, "**", Factor<"all"> => ActionFn(1471); + // Power<"all"> = AtomExpr<"all">, "**", Factor<"all"> => ActionFn(1473); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1471::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1473::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 230) } - pub(crate) fn __reduce764< + pub(crate) fn __reduce765< >( source_code: &str, mode: Mode, @@ -28850,15 +28942,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Power<"all"> = AtomExpr<"all"> => ActionFn(530); + // Power<"all"> = AtomExpr<"all"> => ActionFn(533); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action530::<>(source_code, mode, __sym0); + let __nt = super::__action533::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 230) } - pub(crate) fn __reduce765< + pub(crate) fn __reduce766< >( source_code: &str, mode: Mode, @@ -28867,18 +28959,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Power<"no-withitems"> = AtomExpr<"all">, "**", Factor<"all"> => ActionFn(1472); + // Power<"no-withitems"> = AtomExpr<"all">, "**", Factor<"all"> => ActionFn(1474); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1472::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1474::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 231) } - pub(crate) fn __reduce766< + pub(crate) fn __reduce767< >( source_code: &str, mode: Mode, @@ -28887,15 +28979,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Power<"no-withitems"> = AtomExpr<"no-withitems"> => ActionFn(581); + // Power<"no-withitems"> = AtomExpr<"no-withitems"> => ActionFn(584); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action581::<>(source_code, mode, __sym0); + let __nt = super::__action584::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 231) } - pub(crate) fn __reduce767< + pub(crate) fn __reduce768< >( source_code: &str, mode: Mode, @@ -28911,7 +29003,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant25(__nt), __end)); (0, 232) } - pub(crate) fn __reduce768< + pub(crate) fn __reduce769< >( source_code: &str, mode: Mode, @@ -28930,7 +29022,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant25(__nt), __end)); (2, 232) } - pub(crate) fn __reduce769< + pub(crate) fn __reduce770< >( source_code: &str, mode: Mode, @@ -28939,7 +29031,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Program = Program, SmallStatement, ";", "\n" => ActionFn(1187); + // Program = Program, SmallStatement, ";", "\n" => ActionFn(1190); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -28947,11 +29039,11 @@ mod __parse__Top { let __sym0 = __pop_Variant25(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1187::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1190::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant25(__nt), __end)); (4, 232) } - pub(crate) fn __reduce770< + pub(crate) fn __reduce771< >( source_code: &str, mode: Mode, @@ -28960,7 +29052,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Program = Program, ( ";")+, SmallStatement, ";", "\n" => ActionFn(1188); + // Program = Program, ( ";")+, SmallStatement, ";", "\n" => ActionFn(1191); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -28969,11 +29061,11 @@ mod __parse__Top { let __sym0 = __pop_Variant25(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1188::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1191::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant25(__nt), __end)); (5, 232) } - pub(crate) fn __reduce771< + pub(crate) fn __reduce772< >( source_code: &str, mode: Mode, @@ -28982,18 +29074,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Program = Program, SmallStatement, "\n" => ActionFn(1189); + // Program = Program, SmallStatement, "\n" => ActionFn(1192); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant37(__symbols); let __sym0 = __pop_Variant25(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1189::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1192::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant25(__nt), __end)); (3, 232) } - pub(crate) fn __reduce772< + pub(crate) fn __reduce773< >( source_code: &str, mode: Mode, @@ -29002,7 +29094,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Program = Program, ( ";")+, SmallStatement, "\n" => ActionFn(1190); + // Program = Program, ( ";")+, SmallStatement, "\n" => ActionFn(1193); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant37(__symbols); @@ -29010,11 +29102,11 @@ mod __parse__Top { let __sym0 = __pop_Variant25(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1190::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1193::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant25(__nt), __end)); (4, 232) } - pub(crate) fn __reduce773< + pub(crate) fn __reduce774< >( source_code: &str, mode: Mode, @@ -29033,7 +29125,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant25(__nt), __end)); (2, 232) } - pub(crate) fn __reduce774< + pub(crate) fn __reduce775< >( source_code: &str, mode: Mode, @@ -29042,15 +29134,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // RaiseStatement = "raise" => ActionFn(1473); + // RaiseStatement = "raise" => ActionFn(1475); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1473::<>(source_code, mode, __sym0); + let __nt = super::__action1475::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 233) } - pub(crate) fn __reduce775< + pub(crate) fn __reduce776< >( source_code: &str, mode: Mode, @@ -29059,7 +29151,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // RaiseStatement = "raise", Test<"all">, "from", Test<"all"> => ActionFn(1474); + // RaiseStatement = "raise", Test<"all">, "from", Test<"all"> => ActionFn(1476); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant15(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -29067,11 +29159,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1474::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1476::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (4, 233) } - pub(crate) fn __reduce776< + pub(crate) fn __reduce777< >( source_code: &str, mode: Mode, @@ -29080,17 +29172,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // RaiseStatement = "raise", Test<"all"> => ActionFn(1475); + // RaiseStatement = "raise", Test<"all"> => ActionFn(1477); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1475::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1477::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (2, 233) } - pub(crate) fn __reduce777< + pub(crate) fn __reduce778< >( source_code: &str, mode: Mode, @@ -29099,18 +29191,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SequencePattern = "(", Pattern, ")" => ActionFn(1476); + // SequencePattern = "(", Pattern, ")" => ActionFn(1478); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant35(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1476::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1478::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (3, 234) } - pub(crate) fn __reduce778< + pub(crate) fn __reduce779< >( source_code: &str, mode: Mode, @@ -29119,17 +29211,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SequencePattern = "(", ")" => ActionFn(1477); + // SequencePattern = "(", ")" => ActionFn(1479); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1477::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1479::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (2, 234) } - pub(crate) fn __reduce779< + pub(crate) fn __reduce780< >( source_code: &str, mode: Mode, @@ -29138,7 +29230,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SequencePattern = "(", Pattern, ",", ")" => ActionFn(1478); + // SequencePattern = "(", Pattern, ",", ")" => ActionFn(1480); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -29146,11 +29238,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1478::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1480::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (4, 234) } - pub(crate) fn __reduce780< + pub(crate) fn __reduce781< >( source_code: &str, mode: Mode, @@ -29159,7 +29251,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SequencePattern = "(", ( ",")+, Pattern, ",", ")" => ActionFn(1479); + // SequencePattern = "(", ( ",")+, Pattern, ",", ")" => ActionFn(1481); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -29168,11 +29260,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1479::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1481::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (5, 234) } - pub(crate) fn __reduce781< + pub(crate) fn __reduce782< >( source_code: &str, mode: Mode, @@ -29181,7 +29273,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SequencePattern = "(", ( ",")+, Pattern, ")" => ActionFn(1480); + // SequencePattern = "(", ( ",")+, Pattern, ")" => ActionFn(1482); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant35(__symbols); @@ -29189,11 +29281,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1480::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1482::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (4, 234) } - pub(crate) fn __reduce782< + pub(crate) fn __reduce783< >( source_code: &str, mode: Mode, @@ -29202,18 +29294,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SequencePattern = "[", Pattern, "]" => ActionFn(1545); + // SequencePattern = "[", Pattern, "]" => ActionFn(1549); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant35(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1545::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1549::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (3, 234) } - pub(crate) fn __reduce783< + pub(crate) fn __reduce784< >( source_code: &str, mode: Mode, @@ -29222,17 +29314,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SequencePattern = "[", "]" => ActionFn(1546); + // SequencePattern = "[", "]" => ActionFn(1550); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1546::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1550::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (2, 234) } - pub(crate) fn __reduce784< + pub(crate) fn __reduce785< >( source_code: &str, mode: Mode, @@ -29241,7 +29333,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SequencePattern = "[", ( ",")+, Pattern, "]" => ActionFn(1547); + // SequencePattern = "[", ( ",")+, Pattern, "]" => ActionFn(1551); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant35(__symbols); @@ -29249,11 +29341,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1547::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1551::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (4, 234) } - pub(crate) fn __reduce785< + pub(crate) fn __reduce786< >( source_code: &str, mode: Mode, @@ -29262,18 +29354,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SequencePattern = "[", ( ",")+, "]" => ActionFn(1548); + // SequencePattern = "[", ( ",")+, "]" => ActionFn(1552); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant36(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1548::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1552::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (3, 234) } - pub(crate) fn __reduce786< + pub(crate) fn __reduce787< >( source_code: &str, mode: Mode, @@ -29282,17 +29374,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SetLiteralValues = OneOrMore, "," => ActionFn(658); + // SetLiteralValues = OneOrMore, "," => ActionFn(661); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action658::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action661::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (2, 235) } - pub(crate) fn __reduce787< + pub(crate) fn __reduce788< >( source_code: &str, mode: Mode, @@ -29301,15 +29393,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SetLiteralValues = OneOrMore => ActionFn(659); + // SetLiteralValues = OneOrMore => ActionFn(662); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action659::<>(source_code, mode, __sym0); + let __nt = super::__action662::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); (1, 235) } - pub(crate) fn __reduce788< + pub(crate) fn __reduce789< >( source_code: &str, mode: Mode, @@ -29318,18 +29410,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ShiftExpression<"all"> = ShiftExpression<"all">, ShiftOp, ArithmeticExpression<"all"> => ActionFn(1482); + // ShiftExpression<"all"> = ShiftExpression<"all">, ShiftOp, ArithmeticExpression<"all"> => ActionFn(1484); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant49(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1482::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1484::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 236) } - pub(crate) fn __reduce789< + pub(crate) fn __reduce790< >( source_code: &str, mode: Mode, @@ -29338,15 +29430,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ShiftExpression<"all"> = ArithmeticExpression<"all"> => ActionFn(505); + // ShiftExpression<"all"> = ArithmeticExpression<"all"> => ActionFn(508); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action505::<>(source_code, mode, __sym0); + let __nt = super::__action508::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 236) } - pub(crate) fn __reduce790< + pub(crate) fn __reduce791< >( source_code: &str, mode: Mode, @@ -29355,18 +29447,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ShiftExpression<"no-withitems"> = ShiftExpression<"all">, ShiftOp, ArithmeticExpression<"all"> => ActionFn(1483); + // ShiftExpression<"no-withitems"> = ShiftExpression<"all">, ShiftOp, ArithmeticExpression<"all"> => ActionFn(1485); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant49(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1483::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1485::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (3, 237) } - pub(crate) fn __reduce791< + pub(crate) fn __reduce792< >( source_code: &str, mode: Mode, @@ -29375,15 +29467,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ShiftExpression<"no-withitems"> = ArithmeticExpression<"no-withitems"> => ActionFn(542); + // ShiftExpression<"no-withitems"> = ArithmeticExpression<"no-withitems"> => ActionFn(545); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action542::<>(source_code, mode, __sym0); + let __nt = super::__action545::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (1, 237) } - pub(crate) fn __reduce792< + pub(crate) fn __reduce793< >( source_code: &str, mode: Mode, @@ -29392,15 +29484,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ShiftOp = "<<" => ActionFn(194); + // ShiftOp = "<<" => ActionFn(195); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action194::<>(source_code, mode, __sym0); + let __nt = super::__action195::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant49(__nt), __end)); (1, 238) } - pub(crate) fn __reduce793< + pub(crate) fn __reduce794< >( source_code: &str, mode: Mode, @@ -29409,15 +29501,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ShiftOp = ">>" => ActionFn(195); + // ShiftOp = ">>" => ActionFn(196); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action195::<>(source_code, mode, __sym0); + let __nt = super::__action196::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant49(__nt), __end)); (1, 238) } - pub(crate) fn __reduce794< + pub(crate) fn __reduce795< >( source_code: &str, mode: Mode, @@ -29426,7 +29518,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SingleForComprehension = "async", "for", ExpressionList, "in", OrTest<"all"> => ActionFn(1551); + // SingleForComprehension = "async", "for", ExpressionList, "in", OrTest<"all"> => ActionFn(1555); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant15(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -29435,11 +29527,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1551::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1555::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant90(__nt), __end)); (5, 239) } - pub(crate) fn __reduce795< + pub(crate) fn __reduce796< >( source_code: &str, mode: Mode, @@ -29448,7 +29540,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SingleForComprehension = "async", "for", ExpressionList, "in", OrTest<"all">, ComprehensionIf+ => ActionFn(1552); + // SingleForComprehension = "async", "for", ExpressionList, "in", OrTest<"all">, ComprehensionIf+ => ActionFn(1556); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant17(__symbols); let __sym4 = __pop_Variant15(__symbols); @@ -29458,11 +29550,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = super::__action1552::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); + let __nt = super::__action1556::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant90(__nt), __end)); (6, 239) } - pub(crate) fn __reduce796< + pub(crate) fn __reduce797< >( source_code: &str, mode: Mode, @@ -29471,7 +29563,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SingleForComprehension = "for", ExpressionList, "in", OrTest<"all"> => ActionFn(1553); + // SingleForComprehension = "for", ExpressionList, "in", OrTest<"all"> => ActionFn(1557); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant15(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -29479,11 +29571,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1553::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1557::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant90(__nt), __end)); (4, 239) } - pub(crate) fn __reduce797< + pub(crate) fn __reduce798< >( source_code: &str, mode: Mode, @@ -29492,7 +29584,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SingleForComprehension = "for", ExpressionList, "in", OrTest<"all">, ComprehensionIf+ => ActionFn(1554); + // SingleForComprehension = "for", ExpressionList, "in", OrTest<"all">, ComprehensionIf+ => ActionFn(1558); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant17(__symbols); let __sym3 = __pop_Variant15(__symbols); @@ -29501,11 +29593,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1554::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1558::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant90(__nt), __end)); (5, 239) } - pub(crate) fn __reduce798< + pub(crate) fn __reduce799< >( source_code: &str, mode: Mode, @@ -29514,15 +29606,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SingleForComprehension+ = SingleForComprehension => ActionFn(254); + // SingleForComprehension+ = SingleForComprehension => ActionFn(257); let __sym0 = __pop_Variant90(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action254::<>(source_code, mode, __sym0); + let __nt = super::__action257::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant91(__nt), __end)); (1, 240) } - pub(crate) fn __reduce799< + pub(crate) fn __reduce800< >( source_code: &str, mode: Mode, @@ -29531,17 +29623,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SingleForComprehension+ = SingleForComprehension+, SingleForComprehension => ActionFn(255); + // SingleForComprehension+ = SingleForComprehension+, SingleForComprehension => ActionFn(258); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant90(__symbols); let __sym0 = __pop_Variant91(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action255::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action258::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant91(__nt), __end)); (2, 240) } - pub(crate) fn __reduce800< + pub(crate) fn __reduce801< >( source_code: &str, mode: Mode, @@ -29550,17 +29642,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SliceOp = ":", Test<"all"> => ActionFn(1729); + // SliceOp = ":", Test<"all"> => ActionFn(1733); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1729::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1733::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant92(__nt), __end)); (2, 241) } - pub(crate) fn __reduce801< + pub(crate) fn __reduce802< >( source_code: &str, mode: Mode, @@ -29569,15 +29661,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SliceOp = ":" => ActionFn(1730); + // SliceOp = ":" => ActionFn(1734); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1730::<>(source_code, mode, __sym0); + let __nt = super::__action1734::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant92(__nt), __end)); (1, 241) } - pub(crate) fn __reduce802< + pub(crate) fn __reduce803< >( source_code: &str, mode: Mode, @@ -29586,15 +29678,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SliceOp? = SliceOp => ActionFn(272); + // SliceOp? = SliceOp => ActionFn(277); let __sym0 = __pop_Variant92(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action272::<>(source_code, mode, __sym0); + let __nt = super::__action277::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant93(__nt), __end)); (1, 242) } - pub(crate) fn __reduce803< + pub(crate) fn __reduce804< >( source_code: &str, mode: Mode, @@ -29603,14 +29695,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SliceOp? = => ActionFn(273); + // SliceOp? = => ActionFn(278); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action273::<>(source_code, mode, &__start, &__end); + let __nt = super::__action278::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant93(__nt), __end)); (0, 242) } - pub(crate) fn __reduce804< + pub(crate) fn __reduce805< >( source_code: &str, mode: Mode, @@ -29627,7 +29719,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 243) } - pub(crate) fn __reduce805< + pub(crate) fn __reduce806< >( source_code: &str, mode: Mode, @@ -29644,7 +29736,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 243) } - pub(crate) fn __reduce806< + pub(crate) fn __reduce807< >( source_code: &str, mode: Mode, @@ -29661,7 +29753,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 243) } - pub(crate) fn __reduce807< + pub(crate) fn __reduce808< >( source_code: &str, mode: Mode, @@ -29678,7 +29770,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 243) } - pub(crate) fn __reduce808< + pub(crate) fn __reduce809< >( source_code: &str, mode: Mode, @@ -29695,7 +29787,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 243) } - pub(crate) fn __reduce809< + pub(crate) fn __reduce810< >( source_code: &str, mode: Mode, @@ -29712,7 +29804,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 243) } - pub(crate) fn __reduce810< + pub(crate) fn __reduce811< >( source_code: &str, mode: Mode, @@ -29729,7 +29821,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 243) } - pub(crate) fn __reduce811< + pub(crate) fn __reduce812< >( source_code: &str, mode: Mode, @@ -29746,7 +29838,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 243) } - pub(crate) fn __reduce812< + pub(crate) fn __reduce813< >( source_code: &str, mode: Mode, @@ -29763,7 +29855,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 243) } - pub(crate) fn __reduce813< + pub(crate) fn __reduce814< >( source_code: &str, mode: Mode, @@ -29780,7 +29872,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 243) } - pub(crate) fn __reduce814< + pub(crate) fn __reduce815< >( source_code: &str, mode: Mode, @@ -29797,7 +29889,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant37(__nt), __end)); (1, 243) } - pub(crate) fn __reduce815< + pub(crate) fn __reduce816< >( source_code: &str, mode: Mode, @@ -29806,17 +29898,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // StarExpr = "*", Expression<"all"> => ActionFn(1486); + // StarExpr = "*", Expression<"all"> => ActionFn(1488); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1486::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1488::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); (2, 244) } - pub(crate) fn __reduce816< + pub(crate) fn __reduce817< >( source_code: &str, mode: Mode, @@ -29825,17 +29917,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // StarPattern = "*", Identifier => ActionFn(1487); + // StarPattern = "*", Identifier => ActionFn(1489); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant23(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1487::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1489::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); (2, 245) } - pub(crate) fn __reduce817< + pub(crate) fn __reduce818< >( source_code: &str, mode: Mode, @@ -29844,18 +29936,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // StarTypedParameter = Identifier, ":", TestOrStarExpr => ActionFn(1488); + // StarTypedParameter = Identifier, ":", TestOrStarExpr => ActionFn(1490); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1488::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1490::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant63(__nt), __end)); (3, 246) } - pub(crate) fn __reduce818< + pub(crate) fn __reduce819< >( source_code: &str, mode: Mode, @@ -29864,15 +29956,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // StarTypedParameter = Identifier => ActionFn(1489); + // StarTypedParameter = Identifier => ActionFn(1491); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1489::<>(source_code, mode, __sym0); + let __nt = super::__action1491::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant63(__nt), __end)); (1, 246) } - pub(crate) fn __reduce819< + pub(crate) fn __reduce820< >( source_code: &str, mode: Mode, @@ -29881,15 +29973,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // StarTypedParameter? = StarTypedParameter => ActionFn(496); + // StarTypedParameter? = StarTypedParameter => ActionFn(499); let __sym0 = __pop_Variant63(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action496::<>(source_code, mode, __sym0); + let __nt = super::__action499::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant64(__nt), __end)); (1, 247) } - pub(crate) fn __reduce820< + pub(crate) fn __reduce821< >( source_code: &str, mode: Mode, @@ -29898,14 +29990,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // StarTypedParameter? = => ActionFn(497); + // StarTypedParameter? = => ActionFn(500); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action497::<>(source_code, mode, &__start, &__end); + let __nt = super::__action500::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant64(__nt), __end)); (0, 247) } - pub(crate) fn __reduce821< + pub(crate) fn __reduce822< >( source_code: &str, mode: Mode, @@ -29914,15 +30006,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // StarUntypedParameter = Identifier => ActionFn(1490); + // StarUntypedParameter = Identifier => ActionFn(1492); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1490::<>(source_code, mode, __sym0); + let __nt = super::__action1492::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant63(__nt), __end)); (1, 248) } - pub(crate) fn __reduce822< + pub(crate) fn __reduce823< >( source_code: &str, mode: Mode, @@ -29931,15 +30023,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // StarUntypedParameter? = StarUntypedParameter => ActionFn(485); + // StarUntypedParameter? = StarUntypedParameter => ActionFn(488); let __sym0 = __pop_Variant63(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action485::<>(source_code, mode, __sym0); + let __nt = super::__action488::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant64(__nt), __end)); (1, 249) } - pub(crate) fn __reduce823< + pub(crate) fn __reduce824< >( source_code: &str, mode: Mode, @@ -29948,14 +30040,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // StarUntypedParameter? = => ActionFn(486); + // StarUntypedParameter? = => ActionFn(489); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action486::<>(source_code, mode, &__start, &__end); + let __nt = super::__action489::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant64(__nt), __end)); (0, 249) } - pub(crate) fn __reduce824< + pub(crate) fn __reduce825< >( source_code: &str, mode: Mode, @@ -29964,18 +30056,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Statements = SmallStatement, ";", "\n" => ActionFn(1191); + // Statements = SmallStatement, ";", "\n" => ActionFn(1194); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant37(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1191::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1194::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant94(__nt), __end)); (3, 250) } - pub(crate) fn __reduce825< + pub(crate) fn __reduce826< >( source_code: &str, mode: Mode, @@ -29984,7 +30076,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Statements = ( ";")+, SmallStatement, ";", "\n" => ActionFn(1192); + // Statements = ( ";")+, SmallStatement, ";", "\n" => ActionFn(1195); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -29992,11 +30084,11 @@ mod __parse__Top { let __sym0 = __pop_Variant38(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1192::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1195::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant94(__nt), __end)); (4, 250) } - pub(crate) fn __reduce826< + pub(crate) fn __reduce827< >( source_code: &str, mode: Mode, @@ -30005,17 +30097,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Statements = SmallStatement, "\n" => ActionFn(1193); + // Statements = SmallStatement, "\n" => ActionFn(1196); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant37(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1193::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1196::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant94(__nt), __end)); (2, 250) } - pub(crate) fn __reduce827< + pub(crate) fn __reduce828< >( source_code: &str, mode: Mode, @@ -30024,18 +30116,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Statements = ( ";")+, SmallStatement, "\n" => ActionFn(1194); + // Statements = ( ";")+, SmallStatement, "\n" => ActionFn(1197); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant37(__symbols); let __sym0 = __pop_Variant38(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1194::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1197::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant94(__nt), __end)); (3, 250) } - pub(crate) fn __reduce828< + pub(crate) fn __reduce829< >( source_code: &str, mode: Mode, @@ -30052,7 +30144,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant94(__nt), __end)); (1, 250) } - pub(crate) fn __reduce829< + pub(crate) fn __reduce830< >( source_code: &str, mode: Mode, @@ -30071,7 +30163,7 @@ mod __parse__Top { __symbols.push((__start, __Symbol::Variant94(__nt), __end)); (2, 250) } - pub(crate) fn __reduce830< + pub(crate) fn __reduce831< >( source_code: &str, mode: Mode, @@ -30080,7 +30172,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Statements = Statements, SmallStatement, ";", "\n" => ActionFn(1195); + // Statements = Statements, SmallStatement, ";", "\n" => ActionFn(1198); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -30088,11 +30180,11 @@ mod __parse__Top { let __sym0 = __pop_Variant94(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1195::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1198::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant94(__nt), __end)); (4, 250) } - pub(crate) fn __reduce831< + pub(crate) fn __reduce832< >( source_code: &str, mode: Mode, @@ -30101,7 +30193,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Statements = Statements, ( ";")+, SmallStatement, ";", "\n" => ActionFn(1196); + // Statements = Statements, ( ";")+, SmallStatement, ";", "\n" => ActionFn(1199); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -30110,11 +30202,11 @@ mod __parse__Top { let __sym0 = __pop_Variant94(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1196::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1199::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant94(__nt), __end)); (5, 250) } - pub(crate) fn __reduce832< + pub(crate) fn __reduce833< >( source_code: &str, mode: Mode, @@ -30123,18 +30215,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Statements = Statements, SmallStatement, "\n" => ActionFn(1197); + // Statements = Statements, SmallStatement, "\n" => ActionFn(1200); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant37(__symbols); let __sym0 = __pop_Variant94(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1197::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1200::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant94(__nt), __end)); (3, 250) } - pub(crate) fn __reduce833< + pub(crate) fn __reduce834< >( source_code: &str, mode: Mode, @@ -30143,7 +30235,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Statements = Statements, ( ";")+, SmallStatement, "\n" => ActionFn(1198); + // Statements = Statements, ( ";")+, SmallStatement, "\n" => ActionFn(1201); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant37(__symbols); @@ -30151,7 +30243,7 @@ mod __parse__Top { let __sym0 = __pop_Variant94(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1198::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1201::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant94(__nt), __end)); (4, 250) } @@ -30164,49 +30256,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // StringLiteral+ = StringLiteral => ActionFn(351); - let __sym0 = __pop_Variant69(__symbols); - let __start = __sym0.0; - let __end = __sym0.2; - let __nt = super::__action351::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant95(__nt), __end)); - (1, 252) - } - pub(crate) fn __reduce836< - >( - source_code: &str, - mode: Mode, - __lookahead_start: Option<&TextSize>, - __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)>, - _: core::marker::PhantomData<()>, - ) -> (usize, usize) - { - // StringLiteral+ = StringLiteral+, StringLiteral => ActionFn(352); - assert!(__symbols.len() >= 2); - let __sym1 = __pop_Variant69(__symbols); - let __sym0 = __pop_Variant95(__symbols); - let __start = __sym0.0; - let __end = __sym1.2; - let __nt = super::__action352::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant95(__nt), __end)); - (2, 252) - } - pub(crate) fn __reduce837< - >( - source_code: &str, - mode: Mode, - __lookahead_start: Option<&TextSize>, - __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)>, - _: core::marker::PhantomData<()>, - ) -> (usize, usize) - { - // StringLiteralOrFString = StringLiteral => ActionFn(212); + // String = StringLiteralOrFString => ActionFn(935); let __sym0 = __pop_Variant69(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action212::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant69(__nt), __end)); - (1, 253) + let __nt = super::__action935::<>(source_code, mode, __sym0); + __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + (1, 251) } pub(crate) fn __reduce838< >( @@ -30217,11 +30273,11 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // StringLiteralOrFString = FStringExpr => ActionFn(213); + // StringLiteralOrFString = StringLiteral => ActionFn(215); let __sym0 = __pop_Variant69(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action213::<>(source_code, mode, __sym0); + let __nt = super::__action215::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant69(__nt), __end)); (1, 253) } @@ -30234,13 +30290,13 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // StringLiteralOrFString+ = StringLiteralOrFString => ActionFn(349); + // StringLiteralOrFString = FStringExpr => ActionFn(216); let __sym0 = __pop_Variant69(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action349::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant95(__nt), __end)); - (1, 254) + let __nt = super::__action216::<>(source_code, mode, __sym0); + __symbols.push((__start, __Symbol::Variant69(__nt), __end)); + (1, 253) } pub(crate) fn __reduce840< >( @@ -30251,34 +30307,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // StringLiteralOrFString+ = StringLiteralOrFString+, StringLiteralOrFString => ActionFn(350); - assert!(__symbols.len() >= 2); - let __sym1 = __pop_Variant69(__symbols); - let __sym0 = __pop_Variant95(__symbols); - let __start = __sym0.0; - let __end = __sym1.2; - let __nt = super::__action350::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant95(__nt), __end)); - (2, 254) - } - pub(crate) fn __reduce841< - >( - source_code: &str, - mode: Mode, - __lookahead_start: Option<&TextSize>, - __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)>, - _: core::marker::PhantomData<()>, - ) -> (usize, usize) - { - // Subscript = TestOrStarNamedExpr => ActionFn(209); + // Subscript = TestOrStarNamedExpr => ActionFn(210); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action209::<>(source_code, mode, __sym0); + let __nt = super::__action210::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 255) + (1, 254) } - pub(crate) fn __reduce842< + pub(crate) fn __reduce841< >( source_code: &str, mode: Mode, @@ -30287,7 +30324,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Subscript = Test<"all">, ":", Test<"all">, SliceOp => ActionFn(1731); + // Subscript = Test<"all">, ":", Test<"all">, SliceOp => ActionFn(1735); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant92(__symbols); let __sym2 = __pop_Variant15(__symbols); @@ -30295,11 +30332,11 @@ mod __parse__Top { let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1731::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1735::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (4, 255) + (4, 254) } - pub(crate) fn __reduce843< + pub(crate) fn __reduce842< >( source_code: &str, mode: Mode, @@ -30308,18 +30345,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Subscript = Test<"all">, ":", SliceOp => ActionFn(1732); + // Subscript = Test<"all">, ":", SliceOp => ActionFn(1736); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant92(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1732::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1736::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (3, 255) + (3, 254) } - pub(crate) fn __reduce844< + pub(crate) fn __reduce843< >( source_code: &str, mode: Mode, @@ -30328,18 +30365,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Subscript = ":", Test<"all">, SliceOp => ActionFn(1733); + // Subscript = ":", Test<"all">, SliceOp => ActionFn(1737); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant92(__symbols); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1733::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1737::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (3, 255) + (3, 254) } - pub(crate) fn __reduce845< + pub(crate) fn __reduce844< >( source_code: &str, mode: Mode, @@ -30348,17 +30385,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Subscript = ":", SliceOp => ActionFn(1734); + // Subscript = ":", SliceOp => ActionFn(1738); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant92(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1734::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1738::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (2, 255) + (2, 254) } - pub(crate) fn __reduce846< + pub(crate) fn __reduce845< >( source_code: &str, mode: Mode, @@ -30367,18 +30404,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Subscript = Test<"all">, ":", Test<"all"> => ActionFn(1735); + // Subscript = Test<"all">, ":", Test<"all"> => ActionFn(1739); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1735::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1739::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (3, 255) + (3, 254) } - pub(crate) fn __reduce847< + pub(crate) fn __reduce846< >( source_code: &str, mode: Mode, @@ -30387,17 +30424,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Subscript = Test<"all">, ":" => ActionFn(1736); + // Subscript = Test<"all">, ":" => ActionFn(1740); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1736::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1740::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (2, 255) + (2, 254) } - pub(crate) fn __reduce848< + pub(crate) fn __reduce847< >( source_code: &str, mode: Mode, @@ -30406,17 +30443,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Subscript = ":", Test<"all"> => ActionFn(1737); + // Subscript = ":", Test<"all"> => ActionFn(1741); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1737::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1741::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (2, 255) + (2, 254) } - pub(crate) fn __reduce849< + pub(crate) fn __reduce848< >( source_code: &str, mode: Mode, @@ -30425,15 +30462,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Subscript = ":" => ActionFn(1738); + // Subscript = ":" => ActionFn(1742); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1738::<>(source_code, mode, __sym0); + let __nt = super::__action1742::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 255) + (1, 254) } - pub(crate) fn __reduce850< + pub(crate) fn __reduce849< >( source_code: &str, mode: Mode, @@ -30442,15 +30479,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SubscriptList = Subscript => ActionFn(206); + // SubscriptList = Subscript => ActionFn(207); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action206::<>(source_code, mode, __sym0); + let __nt = super::__action207::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 256) + (1, 255) } - pub(crate) fn __reduce851< + pub(crate) fn __reduce850< >( source_code: &str, mode: Mode, @@ -30459,17 +30496,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SubscriptList = Subscript, "," => ActionFn(1492); + // SubscriptList = Subscript, "," => ActionFn(1496); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1492::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1496::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (2, 256) + (2, 255) } - pub(crate) fn __reduce852< + pub(crate) fn __reduce851< >( source_code: &str, mode: Mode, @@ -30478,17 +30515,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SubscriptList = TwoOrMore, "," => ActionFn(1493); + // SubscriptList = TwoOrMoreSep, "," => ActionFn(1497); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1493::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1497::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (2, 256) + (2, 255) } - pub(crate) fn __reduce853< + pub(crate) fn __reduce852< >( source_code: &str, mode: Mode, @@ -30497,15 +30534,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // SubscriptList = TwoOrMore => ActionFn(1494); + // SubscriptList = TwoOrMoreSep => ActionFn(1498); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1494::<>(source_code, mode, __sym0); + let __nt = super::__action1498::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 256) + (1, 255) } - pub(crate) fn __reduce854< + pub(crate) fn __reduce853< >( source_code: &str, mode: Mode, @@ -30514,18 +30551,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Suite = SmallStatement, ";", "\n" => ActionFn(1199); + // Suite = SmallStatement, ";", "\n" => ActionFn(1202); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant37(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1199::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1202::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant25(__nt), __end)); - (3, 257) + (3, 256) } - pub(crate) fn __reduce855< + pub(crate) fn __reduce854< >( source_code: &str, mode: Mode, @@ -30534,7 +30571,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Suite = ( ";")+, SmallStatement, ";", "\n" => ActionFn(1200); + // Suite = ( ";")+, SmallStatement, ";", "\n" => ActionFn(1203); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -30542,11 +30579,11 @@ mod __parse__Top { let __sym0 = __pop_Variant38(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1200::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1203::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant25(__nt), __end)); - (4, 257) + (4, 256) } - pub(crate) fn __reduce856< + pub(crate) fn __reduce855< >( source_code: &str, mode: Mode, @@ -30555,17 +30592,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Suite = SmallStatement, "\n" => ActionFn(1201); + // Suite = SmallStatement, "\n" => ActionFn(1204); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant37(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1201::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1204::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant25(__nt), __end)); - (2, 257) + (2, 256) } - pub(crate) fn __reduce857< + pub(crate) fn __reduce856< >( source_code: &str, mode: Mode, @@ -30574,18 +30611,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Suite = ( ";")+, SmallStatement, "\n" => ActionFn(1202); + // Suite = ( ";")+, SmallStatement, "\n" => ActionFn(1205); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant37(__symbols); let __sym0 = __pop_Variant38(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1202::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1205::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant25(__nt), __end)); - (3, 257) + (3, 256) } - pub(crate) fn __reduce858< + pub(crate) fn __reduce857< >( source_code: &str, mode: Mode, @@ -30604,9 +30641,9 @@ mod __parse__Top { let __end = __sym3.2; let __nt = super::__action8::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant25(__nt), __end)); - (4, 257) + (4, 256) } - pub(crate) fn __reduce859< + pub(crate) fn __reduce858< >( source_code: &str, mode: Mode, @@ -30615,18 +30652,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Term<"all"> = Term<"all">, MulOp, Factor<"all"> => ActionFn(1495); + // Term<"all"> = Term<"all">, MulOp, Factor<"all"> => ActionFn(1499); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant49(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1495::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1499::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (3, 258) + (3, 257) } - pub(crate) fn __reduce860< + pub(crate) fn __reduce859< >( source_code: &str, mode: Mode, @@ -30635,15 +30672,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Term<"all"> = Factor<"all"> => ActionFn(522); + // Term<"all"> = Factor<"all"> => ActionFn(525); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action522::<>(source_code, mode, __sym0); + let __nt = super::__action525::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 258) + (1, 257) } - pub(crate) fn __reduce861< + pub(crate) fn __reduce860< >( source_code: &str, mode: Mode, @@ -30652,18 +30689,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Term<"no-withitems"> = Term<"all">, MulOp, Factor<"all"> => ActionFn(1496); + // Term<"no-withitems"> = Term<"all">, MulOp, Factor<"all"> => ActionFn(1500); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant49(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1496::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1500::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (3, 259) + (3, 258) } - pub(crate) fn __reduce862< + pub(crate) fn __reduce861< >( source_code: &str, mode: Mode, @@ -30672,15 +30709,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Term<"no-withitems"> = Factor<"no-withitems"> => ActionFn(575); + // Term<"no-withitems"> = Factor<"no-withitems"> => ActionFn(578); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action575::<>(source_code, mode, __sym0); + let __nt = super::__action578::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 259) + (1, 258) } - pub(crate) fn __reduce863< + pub(crate) fn __reduce862< >( source_code: &str, mode: Mode, @@ -30689,7 +30726,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Test<"all"> = OrTest<"all">, "if", OrTest<"all">, "else", Test<"all"> => ActionFn(1497); + // Test<"all"> = OrTest<"all">, "if", OrTest<"all">, "else", Test<"all"> => ActionFn(1501); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant15(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -30698,11 +30735,11 @@ mod __parse__Top { let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1497::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1501::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (5, 260) + (5, 259) } - pub(crate) fn __reduce864< + pub(crate) fn __reduce863< >( source_code: &str, mode: Mode, @@ -30711,15 +30748,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Test<"all"> = OrTest<"all"> => ActionFn(401); + // Test<"all"> = OrTest<"all"> => ActionFn(404); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action401::<>(source_code, mode, __sym0); + let __nt = super::__action404::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 260) + (1, 259) } - pub(crate) fn __reduce865< + pub(crate) fn __reduce864< >( source_code: &str, mode: Mode, @@ -30728,15 +30765,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Test<"all"> = LambdaDef => ActionFn(402); + // Test<"all"> = LambdaDef => ActionFn(405); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action402::<>(source_code, mode, __sym0); + let __nt = super::__action405::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 260) + (1, 259) } - pub(crate) fn __reduce866< + pub(crate) fn __reduce865< >( source_code: &str, mode: Mode, @@ -30745,15 +30782,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Test<"all">? = Test<"all"> => ActionFn(322); + // Test<"all">? = Test<"all"> => ActionFn(327); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action322::<>(source_code, mode, __sym0); + let __nt = super::__action327::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); - (1, 261) + (1, 260) } - pub(crate) fn __reduce867< + pub(crate) fn __reduce866< >( source_code: &str, mode: Mode, @@ -30762,14 +30799,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Test<"all">? = => ActionFn(323); + // Test<"all">? = => ActionFn(328); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action323::<>(source_code, mode, &__start, &__end); + let __nt = super::__action328::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); - (0, 261) + (0, 260) } - pub(crate) fn __reduce868< + pub(crate) fn __reduce867< >( source_code: &str, mode: Mode, @@ -30778,7 +30815,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Test<"no-withitems"> = OrTest<"all">, "if", OrTest<"all">, "else", Test<"all"> => ActionFn(1498); + // Test<"no-withitems"> = OrTest<"all">, "if", OrTest<"all">, "else", Test<"all"> => ActionFn(1502); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant15(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -30787,11 +30824,11 @@ mod __parse__Top { let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1498::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1502::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (5, 262) + (5, 261) } - pub(crate) fn __reduce869< + pub(crate) fn __reduce868< >( source_code: &str, mode: Mode, @@ -30800,15 +30837,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Test<"no-withitems"> = OrTest<"no-withitems"> => ActionFn(433); + // Test<"no-withitems"> = OrTest<"no-withitems"> => ActionFn(436); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action433::<>(source_code, mode, __sym0); + let __nt = super::__action436::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 262) + (1, 261) } - pub(crate) fn __reduce870< + pub(crate) fn __reduce869< >( source_code: &str, mode: Mode, @@ -30817,15 +30854,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Test<"no-withitems"> = LambdaDef => ActionFn(434); + // Test<"no-withitems"> = LambdaDef => ActionFn(437); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action434::<>(source_code, mode, __sym0); + let __nt = super::__action437::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 262) + (1, 261) } - pub(crate) fn __reduce871< + pub(crate) fn __reduce870< >( source_code: &str, mode: Mode, @@ -30834,15 +30871,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TestList = GenericList => ActionFn(232); + // TestList = GenericList => ActionFn(235); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action232::<>(source_code, mode, __sym0); + let __nt = super::__action235::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 263) + (1, 262) } - pub(crate) fn __reduce872< + pub(crate) fn __reduce871< >( source_code: &str, mode: Mode, @@ -30851,15 +30888,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TestList? = GenericList => ActionFn(1743); + // TestList? = GenericList => ActionFn(1747); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1743::<>(source_code, mode, __sym0); + let __nt = super::__action1747::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); - (1, 264) + (1, 263) } - pub(crate) fn __reduce873< + pub(crate) fn __reduce872< >( source_code: &str, mode: Mode, @@ -30868,14 +30905,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TestList? = => ActionFn(397); + // TestList? = => ActionFn(400); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action397::<>(source_code, mode, &__start, &__end); + let __nt = super::__action400::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant16(__nt), __end)); - (0, 264) + (0, 263) } - pub(crate) fn __reduce874< + pub(crate) fn __reduce873< >( source_code: &str, mode: Mode, @@ -30884,15 +30921,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TestListOrYieldExpr = GenericList => ActionFn(1744); + // TestListOrYieldExpr = GenericList => ActionFn(1748); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1744::<>(source_code, mode, __sym0); + let __nt = super::__action1748::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 265) + (1, 264) } - pub(crate) fn __reduce875< + pub(crate) fn __reduce874< >( source_code: &str, mode: Mode, @@ -30907,9 +30944,9 @@ mod __parse__Top { let __end = __sym0.2; let __nt = super::__action32::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 265) + (1, 264) } - pub(crate) fn __reduce876< + pub(crate) fn __reduce875< >( source_code: &str, mode: Mode, @@ -30924,9 +30961,9 @@ mod __parse__Top { let __end = __sym0.2; let __nt = super::__action34::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 266) + (1, 265) } - pub(crate) fn __reduce877< + pub(crate) fn __reduce876< >( source_code: &str, mode: Mode, @@ -30941,9 +30978,9 @@ mod __parse__Top { let __end = __sym0.2; let __nt = super::__action35::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 266) + (1, 265) } - pub(crate) fn __reduce878< + pub(crate) fn __reduce877< >( source_code: &str, mode: Mode, @@ -30952,15 +30989,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TestOrStarExprList = GenericList => ActionFn(1745); + // TestOrStarExprList = GenericList => ActionFn(1749); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1745::<>(source_code, mode, __sym0); + let __nt = super::__action1749::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 267) + (1, 266) } - pub(crate) fn __reduce879< + pub(crate) fn __reduce878< >( source_code: &str, mode: Mode, @@ -30975,9 +31012,9 @@ mod __parse__Top { let __end = __sym0.2; let __nt = super::__action38::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 268) + (1, 267) } - pub(crate) fn __reduce880< + pub(crate) fn __reduce879< >( source_code: &str, mode: Mode, @@ -30992,9 +31029,9 @@ mod __parse__Top { let __end = __sym0.2; let __nt = super::__action39::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 268) + (1, 267) } - pub(crate) fn __reduce881< + pub(crate) fn __reduce880< >( source_code: &str, mode: Mode, @@ -31003,17 +31040,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Top = StartModule, Program => ActionFn(1499); + // Top = StartModule, Program => ActionFn(1503); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant25(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1499::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant96(__nt), __end)); - (2, 269) + let __nt = super::__action1503::<>(source_code, mode, __sym0, __sym1); + __symbols.push((__start, __Symbol::Variant95(__nt), __end)); + (2, 268) } - pub(crate) fn __reduce882< + pub(crate) fn __reduce881< >( source_code: &str, mode: Mode, @@ -31022,17 +31059,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Top = StartExpression, GenericList => ActionFn(1746); + // Top = StartExpression, GenericList => ActionFn(1750); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1746::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant96(__nt), __end)); - (2, 269) + let __nt = super::__action1750::<>(source_code, mode, __sym0, __sym1); + __symbols.push((__start, __Symbol::Variant95(__nt), __end)); + (2, 268) } - pub(crate) fn __reduce883< + pub(crate) fn __reduce882< >( source_code: &str, mode: Mode, @@ -31041,18 +31078,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // Top = StartExpression, GenericList, ("\n")+ => ActionFn(1747); + // Top = StartExpression, GenericList, ("\n")+ => ActionFn(1751); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant22(__symbols); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1747::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant96(__nt), __end)); - (3, 269) + let __nt = super::__action1751::<>(source_code, mode, __sym0, __sym1, __sym2); + __symbols.push((__start, __Symbol::Variant95(__nt), __end)); + (3, 268) } - pub(crate) fn __reduce884< + pub(crate) fn __reduce883< >( source_code: &str, mode: Mode, @@ -31061,7 +31098,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TryStatement = "try", ":", Suite, ExceptClause+, "else", ":", Suite, "finally", ":", Suite => ActionFn(1502); + // TryStatement = "try", ":", Suite, ExceptClause+, "else", ":", Suite, "finally", ":", Suite => ActionFn(1506); assert!(__symbols.len() >= 10); let __sym9 = __pop_Variant25(__symbols); let __sym8 = __pop_Variant0(__symbols); @@ -31075,11 +31112,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym9.2; - let __nt = super::__action1502::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9); + let __nt = super::__action1506::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); - (10, 270) + (10, 269) } - pub(crate) fn __reduce885< + pub(crate) fn __reduce884< >( source_code: &str, mode: Mode, @@ -31088,7 +31125,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TryStatement = "try", ":", Suite, ExceptClause+, "else", ":", Suite => ActionFn(1503); + // TryStatement = "try", ":", Suite, ExceptClause+, "else", ":", Suite => ActionFn(1507); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -31099,11 +31136,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1503::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1507::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); - (7, 270) + (7, 269) } - pub(crate) fn __reduce886< + pub(crate) fn __reduce885< >( source_code: &str, mode: Mode, @@ -31112,7 +31149,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TryStatement = "try", ":", Suite, ExceptClause+, "finally", ":", Suite => ActionFn(1504); + // TryStatement = "try", ":", Suite, ExceptClause+, "finally", ":", Suite => ActionFn(1508); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -31123,11 +31160,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1504::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1508::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); - (7, 270) + (7, 269) } - pub(crate) fn __reduce887< + pub(crate) fn __reduce886< >( source_code: &str, mode: Mode, @@ -31136,7 +31173,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TryStatement = "try", ":", Suite, ExceptClause+ => ActionFn(1505); + // TryStatement = "try", ":", Suite, ExceptClause+ => ActionFn(1509); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant66(__symbols); let __sym2 = __pop_Variant25(__symbols); @@ -31144,11 +31181,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1505::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1509::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); - (4, 270) + (4, 269) } - pub(crate) fn __reduce888< + pub(crate) fn __reduce887< >( source_code: &str, mode: Mode, @@ -31157,7 +31194,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TryStatement = "try", ":", Suite, ExceptStarClause+, "else", ":", Suite, "finally", ":", Suite => ActionFn(1506); + // TryStatement = "try", ":", Suite, ExceptStarClause+, "else", ":", Suite, "finally", ":", Suite => ActionFn(1510); assert!(__symbols.len() >= 10); let __sym9 = __pop_Variant25(__symbols); let __sym8 = __pop_Variant0(__symbols); @@ -31171,11 +31208,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym9.2; - let __nt = super::__action1506::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9); + let __nt = super::__action1510::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); - (10, 270) + (10, 269) } - pub(crate) fn __reduce889< + pub(crate) fn __reduce888< >( source_code: &str, mode: Mode, @@ -31184,7 +31221,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TryStatement = "try", ":", Suite, ExceptStarClause+, "else", ":", Suite => ActionFn(1507); + // TryStatement = "try", ":", Suite, ExceptStarClause+, "else", ":", Suite => ActionFn(1511); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -31195,11 +31232,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1507::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1511::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); - (7, 270) + (7, 269) } - pub(crate) fn __reduce890< + pub(crate) fn __reduce889< >( source_code: &str, mode: Mode, @@ -31208,7 +31245,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TryStatement = "try", ":", Suite, ExceptStarClause+, "finally", ":", Suite => ActionFn(1508); + // TryStatement = "try", ":", Suite, ExceptStarClause+, "finally", ":", Suite => ActionFn(1512); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -31219,11 +31256,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1508::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1512::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); - (7, 270) + (7, 269) } - pub(crate) fn __reduce891< + pub(crate) fn __reduce890< >( source_code: &str, mode: Mode, @@ -31232,7 +31269,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TryStatement = "try", ":", Suite, ExceptStarClause+ => ActionFn(1509); + // TryStatement = "try", ":", Suite, ExceptStarClause+ => ActionFn(1513); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant66(__symbols); let __sym2 = __pop_Variant25(__symbols); @@ -31240,11 +31277,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1509::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1513::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); - (4, 270) + (4, 269) } - pub(crate) fn __reduce892< + pub(crate) fn __reduce891< >( source_code: &str, mode: Mode, @@ -31253,7 +31290,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TryStatement = "try", ":", Suite, "finally", ":", Suite => ActionFn(1135); + // TryStatement = "try", ":", Suite, "finally", ":", Suite => ActionFn(1138); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant25(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -31263,9 +31300,28 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = super::__action1135::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); + let __nt = super::__action1138::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); - (6, 270) + (6, 269) + } + pub(crate) fn __reduce892< + >( + source_code: &str, + mode: Mode, + __lookahead_start: Option<&TextSize>, + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)>, + _: core::marker::PhantomData<()>, + ) -> (usize, usize) + { + // TwoOrMore = StringLiteral, StringLiteral => ActionFn(354); + assert!(__symbols.len() >= 2); + let __sym1 = __pop_Variant69(__symbols); + let __sym0 = __pop_Variant69(__symbols); + let __start = __sym0.0; + let __end = __sym1.2; + let __nt = super::__action354::<>(source_code, mode, __sym0, __sym1); + __symbols.push((__start, __Symbol::Variant96(__nt), __end)); + (2, 270) } pub(crate) fn __reduce893< >( @@ -31276,18 +31332,75 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TwoOrMore = ClosedPattern, "|", ClosedPattern => ActionFn(357); + // TwoOrMore = TwoOrMore, StringLiteral => ActionFn(355); + assert!(__symbols.len() >= 2); + let __sym1 = __pop_Variant69(__symbols); + let __sym0 = __pop_Variant96(__symbols); + let __start = __sym0.0; + let __end = __sym1.2; + let __nt = super::__action355::<>(source_code, mode, __sym0, __sym1); + __symbols.push((__start, __Symbol::Variant96(__nt), __end)); + (2, 270) + } + pub(crate) fn __reduce894< + >( + source_code: &str, + mode: Mode, + __lookahead_start: Option<&TextSize>, + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)>, + _: core::marker::PhantomData<()>, + ) -> (usize, usize) + { + // TwoOrMore = StringLiteralOrFString, StringLiteralOrFString => ActionFn(275); + assert!(__symbols.len() >= 2); + let __sym1 = __pop_Variant69(__symbols); + let __sym0 = __pop_Variant69(__symbols); + let __start = __sym0.0; + let __end = __sym1.2; + let __nt = super::__action275::<>(source_code, mode, __sym0, __sym1); + __symbols.push((__start, __Symbol::Variant96(__nt), __end)); + (2, 271) + } + pub(crate) fn __reduce895< + >( + source_code: &str, + mode: Mode, + __lookahead_start: Option<&TextSize>, + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)>, + _: core::marker::PhantomData<()>, + ) -> (usize, usize) + { + // TwoOrMore = TwoOrMore, StringLiteralOrFString => ActionFn(276); + assert!(__symbols.len() >= 2); + let __sym1 = __pop_Variant69(__symbols); + let __sym0 = __pop_Variant96(__symbols); + let __start = __sym0.0; + let __end = __sym1.2; + let __nt = super::__action276::<>(source_code, mode, __sym0, __sym1); + __symbols.push((__start, __Symbol::Variant96(__nt), __end)); + (2, 271) + } + pub(crate) fn __reduce896< + >( + source_code: &str, + mode: Mode, + __lookahead_start: Option<&TextSize>, + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)>, + _: core::marker::PhantomData<()>, + ) -> (usize, usize) + { + // TwoOrMoreSep = ClosedPattern, "|", ClosedPattern => ActionFn(360); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant35(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant35(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action357::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action360::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); - (3, 271) + (3, 272) } - pub(crate) fn __reduce894< + pub(crate) fn __reduce897< >( source_code: &str, mode: Mode, @@ -31296,18 +31409,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TwoOrMore = TwoOrMore, "|", ClosedPattern => ActionFn(358); + // TwoOrMoreSep = TwoOrMoreSep, "|", ClosedPattern => ActionFn(361); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant35(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant53(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action358::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action361::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); - (3, 271) + (3, 272) } - pub(crate) fn __reduce895< + pub(crate) fn __reduce898< >( source_code: &str, mode: Mode, @@ -31316,18 +31429,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TwoOrMore = Pattern, ",", Pattern => ActionFn(359); + // TwoOrMoreSep = Pattern, ",", Pattern => ActionFn(362); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant35(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant35(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action359::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action362::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); - (3, 272) + (3, 273) } - pub(crate) fn __reduce896< + pub(crate) fn __reduce899< >( source_code: &str, mode: Mode, @@ -31336,18 +31449,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TwoOrMore = TwoOrMore, ",", Pattern => ActionFn(360); + // TwoOrMoreSep = TwoOrMoreSep, ",", Pattern => ActionFn(363); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant35(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant53(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action360::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action363::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant53(__nt), __end)); - (3, 272) + (3, 273) } - pub(crate) fn __reduce897< + pub(crate) fn __reduce900< >( source_code: &str, mode: Mode, @@ -31356,18 +31469,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TwoOrMore = Subscript, ",", Subscript => ActionFn(274); + // TwoOrMoreSep = Subscript, ",", Subscript => ActionFn(279); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action274::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action279::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); - (3, 273) + (3, 274) } - pub(crate) fn __reduce898< + pub(crate) fn __reduce901< >( source_code: &str, mode: Mode, @@ -31376,18 +31489,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TwoOrMore = TwoOrMore, ",", Subscript => ActionFn(275); + // TwoOrMoreSep = TwoOrMoreSep, ",", Subscript => ActionFn(280); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action275::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action280::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); - (3, 273) + (3, 274) } - pub(crate) fn __reduce899< + pub(crate) fn __reduce902< >( source_code: &str, mode: Mode, @@ -31396,18 +31509,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TwoOrMore = TestOrStarNamedExpr, ",", TestOrStarNamedExpr => ActionFn(364); + // TwoOrMoreSep = TestOrStarNamedExpr, ",", TestOrStarNamedExpr => ActionFn(367); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action364::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action367::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); - (3, 274) + (3, 275) } - pub(crate) fn __reduce900< + pub(crate) fn __reduce903< >( source_code: &str, mode: Mode, @@ -31416,18 +31529,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TwoOrMore = TwoOrMore, ",", TestOrStarNamedExpr => ActionFn(365); + // TwoOrMoreSep = TwoOrMoreSep, ",", TestOrStarNamedExpr => ActionFn(368); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action365::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action368::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant33(__nt), __end)); - (3, 274) + (3, 275) } - pub(crate) fn __reduce901< + pub(crate) fn __reduce904< >( source_code: &str, mode: Mode, @@ -31436,15 +31549,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TypeAliasName = Identifier => ActionFn(1510); + // TypeAliasName = Identifier => ActionFn(1514); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1510::<>(source_code, mode, __sym0); + let __nt = super::__action1514::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant44(__nt), __end)); - (1, 275) + (1, 276) } - pub(crate) fn __reduce902< + pub(crate) fn __reduce905< >( source_code: &str, mode: Mode, @@ -31453,7 +31566,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TypeAliasStatement = "type", TypeAliasName, TypeParams, "=", Test<"all"> => ActionFn(1779); + // TypeAliasStatement = "type", TypeAliasName, TypeParams, "=", Test<"all"> => ActionFn(1783); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant15(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -31462,11 +31575,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1779::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1783::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); - (5, 276) + (5, 277) } - pub(crate) fn __reduce903< + pub(crate) fn __reduce906< >( source_code: &str, mode: Mode, @@ -31475,7 +31588,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TypeAliasStatement = "type", TypeAliasName, "=", Test<"all"> => ActionFn(1780); + // TypeAliasStatement = "type", TypeAliasName, "=", Test<"all"> => ActionFn(1784); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant15(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -31483,11 +31596,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1780::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1784::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); - (4, 276) + (4, 277) } - pub(crate) fn __reduce904< + pub(crate) fn __reduce907< >( source_code: &str, mode: Mode, @@ -31496,18 +31609,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TypeParam = Identifier, ":", Test<"all"> => ActionFn(1512); + // TypeParam = Identifier, ":", Test<"all"> => ActionFn(1516); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1512::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1516::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant97(__nt), __end)); - (3, 277) + (3, 278) } - pub(crate) fn __reduce905< + pub(crate) fn __reduce908< >( source_code: &str, mode: Mode, @@ -31516,15 +31629,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TypeParam = Identifier => ActionFn(1513); + // TypeParam = Identifier => ActionFn(1517); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1513::<>(source_code, mode, __sym0); + let __nt = super::__action1517::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant97(__nt), __end)); - (1, 277) + (1, 278) } - pub(crate) fn __reduce906< + pub(crate) fn __reduce909< >( source_code: &str, mode: Mode, @@ -31533,17 +31646,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TypeParam = "*", Identifier => ActionFn(1514); + // TypeParam = "*", Identifier => ActionFn(1518); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant23(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1514::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1518::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant97(__nt), __end)); - (2, 277) + (2, 278) } - pub(crate) fn __reduce907< + pub(crate) fn __reduce910< >( source_code: &str, mode: Mode, @@ -31552,17 +31665,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TypeParam = "**", Identifier => ActionFn(1515); + // TypeParam = "**", Identifier => ActionFn(1519); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant23(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1515::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1519::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant97(__nt), __end)); - (2, 277) + (2, 278) } - pub(crate) fn __reduce908< + pub(crate) fn __reduce911< >( source_code: &str, mode: Mode, @@ -31571,7 +31684,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TypeParams = "[", OneOrMore, ",", "]" => ActionFn(1516); + // TypeParams = "[", OneOrMore, ",", "]" => ActionFn(1520); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -31579,11 +31692,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1516::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1520::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant98(__nt), __end)); - (4, 278) + (4, 279) } - pub(crate) fn __reduce909< + pub(crate) fn __reduce912< >( source_code: &str, mode: Mode, @@ -31592,18 +31705,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TypeParams = "[", OneOrMore, "]" => ActionFn(1517); + // TypeParams = "[", OneOrMore, "]" => ActionFn(1521); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant86(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1517::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1521::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant98(__nt), __end)); - (3, 278) + (3, 279) } - pub(crate) fn __reduce910< + pub(crate) fn __reduce913< >( source_code: &str, mode: Mode, @@ -31612,15 +31725,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TypeParams? = TypeParams => ActionFn(304); + // TypeParams? = TypeParams => ActionFn(309); let __sym0 = __pop_Variant98(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action304::<>(source_code, mode, __sym0); + let __nt = super::__action309::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant99(__nt), __end)); - (1, 279) + (1, 280) } - pub(crate) fn __reduce911< + pub(crate) fn __reduce914< >( source_code: &str, mode: Mode, @@ -31629,14 +31742,14 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TypeParams? = => ActionFn(305); + // TypeParams? = => ActionFn(310); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action305::<>(source_code, mode, &__start, &__end); + let __nt = super::__action310::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant99(__nt), __end)); - (0, 279) + (0, 280) } - pub(crate) fn __reduce912< + pub(crate) fn __reduce915< >( source_code: &str, mode: Mode, @@ -31645,18 +31758,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TypedParameter = Identifier, ":", Test<"all"> => ActionFn(1518); + // TypedParameter = Identifier, ":", Test<"all"> => ActionFn(1522); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1518::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1522::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant11(__nt), __end)); - (3, 280) + (3, 281) } - pub(crate) fn __reduce913< + pub(crate) fn __reduce916< >( source_code: &str, mode: Mode, @@ -31665,15 +31778,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // TypedParameter = Identifier => ActionFn(1519); + // TypedParameter = Identifier => ActionFn(1523); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1519::<>(source_code, mode, __sym0); + let __nt = super::__action1523::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant11(__nt), __end)); - (1, 280) + (1, 281) } - pub(crate) fn __reduce914< + pub(crate) fn __reduce917< >( source_code: &str, mode: Mode, @@ -31682,15 +31795,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // UnaryOp = "+" => ActionFn(203); + // UnaryOp = "+" => ActionFn(204); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action203::<>(source_code, mode, __sym0); + let __nt = super::__action204::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant100(__nt), __end)); - (1, 281) + (1, 282) } - pub(crate) fn __reduce915< + pub(crate) fn __reduce918< >( source_code: &str, mode: Mode, @@ -31699,15 +31812,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // UnaryOp = "-" => ActionFn(204); + // UnaryOp = "-" => ActionFn(205); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action204::<>(source_code, mode, __sym0); + let __nt = super::__action205::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant100(__nt), __end)); - (1, 281) + (1, 282) } - pub(crate) fn __reduce916< + pub(crate) fn __reduce919< >( source_code: &str, mode: Mode, @@ -31716,15 +31829,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // UnaryOp = "~" => ActionFn(205); + // UnaryOp = "~" => ActionFn(206); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action205::<>(source_code, mode, __sym0); + let __nt = super::__action206::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant100(__nt), __end)); - (1, 281) + (1, 282) } - pub(crate) fn __reduce917< + pub(crate) fn __reduce920< >( source_code: &str, mode: Mode, @@ -31733,15 +31846,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // UntypedParameter = Identifier => ActionFn(1520); + // UntypedParameter = Identifier => ActionFn(1524); let __sym0 = __pop_Variant23(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1520::<>(source_code, mode, __sym0); + let __nt = super::__action1524::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant11(__nt), __end)); - (1, 282) + (1, 283) } - pub(crate) fn __reduce918< + pub(crate) fn __reduce921< >( source_code: &str, mode: Mode, @@ -31750,15 +31863,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // ValuePattern = MatchNameOrAttr => ActionFn(1521); + // ValuePattern = MatchNameOrAttr => ActionFn(1525); let __sym0 = __pop_Variant44(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1521::<>(source_code, mode, __sym0); + let __nt = super::__action1525::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant35(__nt), __end)); - (1, 283) + (1, 284) } - pub(crate) fn __reduce919< + pub(crate) fn __reduce922< >( source_code: &str, mode: Mode, @@ -31767,7 +31880,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WhileStatement = "while", NamedExpressionTest, ":", Suite, "else", ":", Suite => ActionFn(1132); + // WhileStatement = "while", NamedExpressionTest, ":", Suite, "else", ":", Suite => ActionFn(1135); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -31778,11 +31891,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1132::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1135::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); - (7, 284) + (7, 285) } - pub(crate) fn __reduce920< + pub(crate) fn __reduce923< >( source_code: &str, mode: Mode, @@ -31791,7 +31904,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WhileStatement = "while", NamedExpressionTest, ":", Suite => ActionFn(1133); + // WhileStatement = "while", NamedExpressionTest, ":", Suite => ActionFn(1136); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant25(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -31799,11 +31912,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1133::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1136::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); - (4, 284) + (4, 285) } - pub(crate) fn __reduce921< + pub(crate) fn __reduce924< >( source_code: &str, mode: Mode, @@ -31812,15 +31925,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItem<"all"> = Test<"all"> => ActionFn(317); + // WithItem<"all"> = Test<"all"> => ActionFn(322); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action317::<>(source_code, mode, __sym0); + let __nt = super::__action322::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant18(__nt), __end)); - (1, 285) + (1, 286) } - pub(crate) fn __reduce922< + pub(crate) fn __reduce925< >( source_code: &str, mode: Mode, @@ -31829,15 +31942,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItem<"all"> = WithItemAs => ActionFn(318); + // WithItem<"all"> = WithItemAs => ActionFn(323); let __sym0 = __pop_Variant18(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action318::<>(source_code, mode, __sym0); + let __nt = super::__action323::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant18(__nt), __end)); - (1, 285) + (1, 286) } - pub(crate) fn __reduce923< + pub(crate) fn __reduce926< >( source_code: &str, mode: Mode, @@ -31846,15 +31959,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItem<"no-withitems"> = Test<"no-withitems"> => ActionFn(312); + // WithItem<"no-withitems"> = Test<"no-withitems"> => ActionFn(317); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action312::<>(source_code, mode, __sym0); + let __nt = super::__action317::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant18(__nt), __end)); - (1, 286) + (1, 287) } - pub(crate) fn __reduce924< + pub(crate) fn __reduce927< >( source_code: &str, mode: Mode, @@ -31863,15 +31976,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItem<"no-withitems"> = WithItemAs => ActionFn(313); + // WithItem<"no-withitems"> = WithItemAs => ActionFn(318); let __sym0 = __pop_Variant18(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action313::<>(source_code, mode, __sym0); + let __nt = super::__action318::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant18(__nt), __end)); - (1, 286) + (1, 287) } - pub(crate) fn __reduce925< + pub(crate) fn __reduce928< >( source_code: &str, mode: Mode, @@ -31880,18 +31993,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItemAs = Test<"all">, "as", Expression<"all"> => ActionFn(1522); + // WithItemAs = Test<"all">, "as", Expression<"all"> => ActionFn(1526); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1522::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1526::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant18(__nt), __end)); - (3, 287) + (3, 288) } - pub(crate) fn __reduce926< + pub(crate) fn __reduce929< >( source_code: &str, mode: Mode, @@ -31900,7 +32013,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItems = "(", OneOrMore>, ",", ")" => ActionFn(1206); + // WithItems = "(", OneOrMore>, ",", ")" => ActionFn(1209); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -31908,11 +32021,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1206::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1209::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); - (4, 288) + (4, 289) } - pub(crate) fn __reduce927< + pub(crate) fn __reduce930< >( source_code: &str, mode: Mode, @@ -31921,18 +32034,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItems = "(", OneOrMore>, ")" => ActionFn(1207); + // WithItems = "(", OneOrMore>, ")" => ActionFn(1210); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant33(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1207::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1210::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); - (3, 288) + (3, 289) } - pub(crate) fn __reduce928< + pub(crate) fn __reduce931< >( source_code: &str, mode: Mode, @@ -31941,7 +32054,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItems = "(", OneOrMore>, ",", WithItemAs, ",", ")" => ActionFn(1209); + // WithItems = "(", OneOrMore>, ",", WithItemAs, ",", ")" => ActionFn(1212); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant0(__symbols); @@ -31951,11 +32064,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = super::__action1209::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); + let __nt = super::__action1212::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); - (6, 288) + (6, 289) } - pub(crate) fn __reduce929< + pub(crate) fn __reduce932< >( source_code: &str, mode: Mode, @@ -31964,7 +32077,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItems = "(", WithItemAs, ",", ")" => ActionFn(1210); + // WithItems = "(", WithItemAs, ",", ")" => ActionFn(1213); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -31972,11 +32085,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1210::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1213::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); - (4, 288) + (4, 289) } - pub(crate) fn __reduce930< + pub(crate) fn __reduce933< >( source_code: &str, mode: Mode, @@ -31985,7 +32098,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItems = "(", OneOrMore>, ",", WithItemAs, ("," >)+, ",", ")" => ActionFn(1211); + // WithItems = "(", OneOrMore>, ",", WithItemAs, ("," >)+, ",", ")" => ActionFn(1214); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant0(__symbols); @@ -31996,11 +32109,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; - let __nt = super::__action1211::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); + let __nt = super::__action1214::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); - (7, 288) + (7, 289) } - pub(crate) fn __reduce931< + pub(crate) fn __reduce934< >( source_code: &str, mode: Mode, @@ -32009,7 +32122,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItems = "(", WithItemAs, ("," >)+, ",", ")" => ActionFn(1212); + // WithItems = "(", WithItemAs, ("," >)+, ",", ")" => ActionFn(1215); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -32018,11 +32131,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1212::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1215::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); - (5, 288) + (5, 289) } - pub(crate) fn __reduce932< + pub(crate) fn __reduce935< >( source_code: &str, mode: Mode, @@ -32031,7 +32144,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItems = "(", OneOrMore>, ",", WithItemAs, ")" => ActionFn(1213); + // WithItems = "(", OneOrMore>, ",", WithItemAs, ")" => ActionFn(1216); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant18(__symbols); @@ -32040,11 +32153,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action1213::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action1216::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); - (5, 288) + (5, 289) } - pub(crate) fn __reduce933< + pub(crate) fn __reduce936< >( source_code: &str, mode: Mode, @@ -32053,18 +32166,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItems = "(", WithItemAs, ")" => ActionFn(1214); + // WithItems = "(", WithItemAs, ")" => ActionFn(1217); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant18(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1214::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1217::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); - (3, 288) + (3, 289) } - pub(crate) fn __reduce934< + pub(crate) fn __reduce937< >( source_code: &str, mode: Mode, @@ -32073,7 +32186,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItems = "(", OneOrMore>, ",", WithItemAs, ("," >)+, ")" => ActionFn(1215); + // WithItems = "(", OneOrMore>, ",", WithItemAs, ("," >)+, ")" => ActionFn(1218); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant19(__symbols); @@ -32083,11 +32196,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; - let __nt = super::__action1215::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); + let __nt = super::__action1218::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); - (6, 288) + (6, 289) } - pub(crate) fn __reduce935< + pub(crate) fn __reduce938< >( source_code: &str, mode: Mode, @@ -32096,7 +32209,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItems = "(", WithItemAs, ("," >)+, ")" => ActionFn(1216); + // WithItems = "(", WithItemAs, ("," >)+, ")" => ActionFn(1219); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant19(__symbols); @@ -32104,11 +32217,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action1216::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action1219::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); - (4, 288) + (4, 289) } - pub(crate) fn __reduce936< + pub(crate) fn __reduce939< >( source_code: &str, mode: Mode, @@ -32117,15 +32230,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItems = WithItem<"no-withitems"> => ActionFn(158); + // WithItems = WithItem<"no-withitems"> => ActionFn(159); let __sym0 = __pop_Variant18(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action158::<>(source_code, mode, __sym0); + let __nt = super::__action159::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); - (1, 288) + (1, 289) } - pub(crate) fn __reduce937< + pub(crate) fn __reduce940< >( source_code: &str, mode: Mode, @@ -32134,17 +32247,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItems = WithItem<"all">, ("," >)+ => ActionFn(159); + // WithItems = WithItem<"all">, ("," >)+ => ActionFn(160); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant19(__symbols); let __sym0 = __pop_Variant18(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action159::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action160::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); - (2, 288) + (2, 289) } - pub(crate) fn __reduce938< + pub(crate) fn __reduce941< >( source_code: &str, mode: Mode, @@ -32153,15 +32266,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithItemsNoAs = OneOrMore> => ActionFn(160); + // WithItemsNoAs = OneOrMore> => ActionFn(161); let __sym0 = __pop_Variant33(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action160::<>(source_code, mode, __sym0); + let __nt = super::__action161::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant40(__nt), __end)); - (1, 289) + (1, 290) } - pub(crate) fn __reduce939< + pub(crate) fn __reduce942< >( source_code: &str, mode: Mode, @@ -32170,7 +32283,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithStatement = "async", "with", WithItems, ":", Suite => ActionFn(960); + // WithStatement = "async", "with", WithItems, ":", Suite => ActionFn(963); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant25(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -32179,11 +32292,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; - let __nt = super::__action960::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); + let __nt = super::__action963::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); - (5, 290) + (5, 291) } - pub(crate) fn __reduce940< + pub(crate) fn __reduce943< >( source_code: &str, mode: Mode, @@ -32192,7 +32305,7 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // WithStatement = "with", WithItems, ":", Suite => ActionFn(961); + // WithStatement = "with", WithItems, ":", Suite => ActionFn(964); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant25(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -32200,11 +32313,11 @@ mod __parse__Top { let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; - let __nt = super::__action961::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); + let __nt = super::__action964::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); __symbols.push((__start, __Symbol::Variant37(__nt), __end)); - (4, 290) + (4, 291) } - pub(crate) fn __reduce941< + pub(crate) fn __reduce944< >( source_code: &str, mode: Mode, @@ -32213,18 +32326,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // XorExpression<"all"> = XorExpression<"all">, "^", AndExpression<"all"> => ActionFn(1523); + // XorExpression<"all"> = XorExpression<"all">, "^", AndExpression<"all"> => ActionFn(1527); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1523::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1527::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (3, 291) + (3, 292) } - pub(crate) fn __reduce942< + pub(crate) fn __reduce945< >( source_code: &str, mode: Mode, @@ -32233,15 +32346,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // XorExpression<"all"> = AndExpression<"all"> => ActionFn(425); + // XorExpression<"all"> = AndExpression<"all"> => ActionFn(428); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action425::<>(source_code, mode, __sym0); + let __nt = super::__action428::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 291) + (1, 292) } - pub(crate) fn __reduce943< + pub(crate) fn __reduce946< >( source_code: &str, mode: Mode, @@ -32250,18 +32363,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // XorExpression<"no-withitems"> = XorExpression<"all">, "^", AndExpression<"all"> => ActionFn(1524); + // XorExpression<"no-withitems"> = XorExpression<"all">, "^", AndExpression<"all"> => ActionFn(1528); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1524::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1528::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (3, 292) + (3, 293) } - pub(crate) fn __reduce944< + pub(crate) fn __reduce947< >( source_code: &str, mode: Mode, @@ -32270,15 +32383,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // XorExpression<"no-withitems"> = AndExpression<"no-withitems"> => ActionFn(532); + // XorExpression<"no-withitems"> = AndExpression<"no-withitems"> => ActionFn(535); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action532::<>(source_code, mode, __sym0); + let __nt = super::__action535::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 292) + (1, 293) } - pub(crate) fn __reduce945< + pub(crate) fn __reduce948< >( source_code: &str, mode: Mode, @@ -32287,17 +32400,17 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // YieldExpr = "yield", GenericList => ActionFn(1750); + // YieldExpr = "yield", GenericList => ActionFn(1754); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; - let __nt = super::__action1750::<>(source_code, mode, __sym0, __sym1); + let __nt = super::__action1754::<>(source_code, mode, __sym0, __sym1); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (2, 293) + (2, 294) } - pub(crate) fn __reduce946< + pub(crate) fn __reduce949< >( source_code: &str, mode: Mode, @@ -32306,15 +32419,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // YieldExpr = "yield" => ActionFn(1751); + // YieldExpr = "yield" => ActionFn(1755); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action1751::<>(source_code, mode, __sym0); + let __nt = super::__action1755::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (1, 293) + (1, 294) } - pub(crate) fn __reduce947< + pub(crate) fn __reduce950< >( source_code: &str, mode: Mode, @@ -32323,18 +32436,18 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // YieldExpr = "yield", "from", Test<"all"> => ActionFn(1526); + // YieldExpr = "yield", "from", Test<"all"> => ActionFn(1530); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; - let __nt = super::__action1526::<>(source_code, mode, __sym0, __sym1, __sym2); + let __nt = super::__action1530::<>(source_code, mode, __sym0, __sym1, __sym2); __symbols.push((__start, __Symbol::Variant15(__nt), __end)); - (3, 293) + (3, 294) } - pub(crate) fn __reduce949< + pub(crate) fn __reduce952< >( source_code: &str, mode: Mode, @@ -32343,15 +32456,15 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // fstring_middle? = fstring_middle => ActionFn(276); + // fstring_middle? = fstring_middle => ActionFn(281); let __sym0 = __pop_Variant3(__symbols); let __start = __sym0.0; let __end = __sym0.2; - let __nt = super::__action276::<>(source_code, mode, __sym0); + let __nt = super::__action281::<>(source_code, mode, __sym0); __symbols.push((__start, __Symbol::Variant101(__nt), __end)); - (1, 295) + (1, 296) } - pub(crate) fn __reduce950< + pub(crate) fn __reduce953< >( source_code: &str, mode: Mode, @@ -32360,12 +32473,12 @@ mod __parse__Top { _: core::marker::PhantomData<()>, ) -> (usize, usize) { - // fstring_middle? = => ActionFn(277); + // fstring_middle? = => ActionFn(282); let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); - let __nt = super::__action277::<>(source_code, mode, &__start, &__end); + let __nt = super::__action282::<>(source_code, mode, &__start, &__end); __symbols.push((__start, __Symbol::Variant101(__nt), __end)); - (0, 295) + (0, 296) } } pub(crate) use self::__parse__Top::TopParser; @@ -34390,19 +34503,36 @@ fn __action120< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, strings, _): (TextSize, alloc::vec::Vec, TextSize), + (_, string, _): (TextSize, StringType, TextSize), + (_, end_location, _): (TextSize, TextSize, TextSize), +) -> ast::Pattern +{ + ast::PatternMatchValue { + value: Box::new(string.into()), + range: (location..end_location).into() + }.into() +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action121< +>( + source_code: &str, + mode: Mode, + (_, location, _): (TextSize, TextSize, TextSize), + (_, strings, _): (TextSize, Vec, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> Result> { Ok(ast::PatternMatchValue { - value: Box::new(concatenate_strings(strings, (location..end_location).into())?), + value: Box::new(concatenated_strings(strings, (location..end_location).into())?), range: (location..end_location).into() }.into()) } #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action121< +fn __action122< >( source_code: &str, mode: Mode, @@ -34420,7 +34550,7 @@ fn __action121< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action122< +fn __action123< >( source_code: &str, mode: Mode, @@ -34436,7 +34566,7 @@ fn __action122< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action123< +fn __action124< >( source_code: &str, mode: Mode, @@ -34457,7 +34587,7 @@ fn __action123< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action124< +fn __action125< >( source_code: &str, mode: Mode, @@ -34478,7 +34608,7 @@ fn __action124< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action125< +fn __action126< >( source_code: &str, mode: Mode, @@ -34495,7 +34625,7 @@ fn __action125< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action126< +fn __action127< >( source_code: &str, mode: Mode, @@ -34507,7 +34637,19 @@ fn __action126< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action127< +fn __action128< +>( + source_code: &str, + mode: Mode, + (_, __0, _): (TextSize, ast::Expr, TextSize), +) -> ast::Expr +{ + __0 +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action129< >( source_code: &str, mode: Mode, @@ -34519,7 +34661,7 @@ fn __action127< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action128< +fn __action130< >( source_code: &str, mode: Mode, @@ -34531,7 +34673,7 @@ fn __action128< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action129< +fn __action131< >( source_code: &str, mode: Mode, @@ -34547,7 +34689,7 @@ fn __action129< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action130< +fn __action132< >( source_code: &str, mode: Mode, @@ -34564,7 +34706,7 @@ fn __action130< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action131< +fn __action133< >( source_code: &str, mode: Mode, @@ -34581,21 +34723,7 @@ fn __action131< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action132< ->( - source_code: &str, - mode: Mode, - (_, location, _): (TextSize, TextSize, TextSize), - (_, strings, _): (TextSize, alloc::vec::Vec, TextSize), - (_, end_location, _): (TextSize, TextSize, TextSize), -) -> Result> -{ - Ok(concatenate_strings(strings, (location..end_location).into())?) -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action133< +fn __action134< >( source_code: &str, mode: Mode, @@ -34609,7 +34737,7 @@ fn __action133< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action134< +fn __action135< >( source_code: &str, mode: Mode, @@ -34631,7 +34759,7 @@ fn __action134< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action135< +fn __action136< >( source_code: &str, mode: Mode, @@ -34658,7 +34786,7 @@ fn __action135< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action136< +fn __action137< >( source_code: &str, mode: Mode, @@ -34683,7 +34811,7 @@ fn __action136< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action137< +fn __action138< >( source_code: &str, mode: Mode, @@ -34713,7 +34841,7 @@ fn __action137< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action138< +fn __action139< >( source_code: &str, mode: Mode, @@ -34733,7 +34861,7 @@ fn __action138< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action139< +fn __action140< >( source_code: &str, mode: Mode, @@ -34754,7 +34882,7 @@ fn __action139< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action140< +fn __action141< >( source_code: &str, mode: Mode, @@ -34775,7 +34903,7 @@ fn __action140< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action141< +fn __action142< >( source_code: &str, mode: Mode, @@ -34800,7 +34928,7 @@ fn __action141< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action142< +fn __action143< >( source_code: &str, mode: Mode, @@ -34823,7 +34951,7 @@ fn __action142< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action143< +fn __action144< >( source_code: &str, mode: Mode, @@ -34846,7 +34974,7 @@ fn __action143< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action144< +fn __action145< >( source_code: &str, mode: Mode, @@ -34867,7 +34995,7 @@ fn __action144< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action145< +fn __action146< >( source_code: &str, mode: Mode, @@ -34903,7 +35031,7 @@ fn __action145< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action146< +fn __action147< >( source_code: &str, mode: Mode, @@ -34935,7 +35063,7 @@ fn __action146< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action147< +fn __action148< >( source_code: &str, mode: Mode, @@ -34965,7 +35093,7 @@ fn __action147< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action148< +fn __action149< >( source_code: &str, mode: Mode, @@ -35003,7 +35131,7 @@ fn __action148< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action149< +fn __action150< >( source_code: &str, mode: Mode, @@ -35041,7 +35169,7 @@ fn __action149< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action150< +fn __action151< >( source_code: &str, mode: Mode, @@ -35071,7 +35199,7 @@ fn __action150< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action151< +fn __action152< >( source_code: &str, mode: Mode, @@ -35098,7 +35226,7 @@ fn __action151< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action152< +fn __action153< >( source_code: &str, mode: Mode, @@ -35125,7 +35253,7 @@ fn __action152< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action153< +fn __action154< >( source_code: &str, mode: Mode, @@ -35151,7 +35279,7 @@ fn __action153< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action154< +fn __action155< >( source_code: &str, mode: Mode, @@ -35177,7 +35305,7 @@ fn __action154< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action155< +fn __action156< >( source_code: &str, mode: Mode, @@ -35197,7 +35325,7 @@ fn __action155< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action156< +fn __action157< >( source_code: &str, mode: Mode, @@ -35212,7 +35340,7 @@ fn __action156< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action157< +fn __action158< >( source_code: &str, mode: Mode, @@ -35231,7 +35359,7 @@ fn __action157< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action158< +fn __action159< >( source_code: &str, mode: Mode, @@ -35261,7 +35389,7 @@ fn __action158< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action159< +fn __action160< >( source_code: &str, mode: Mode, @@ -35276,7 +35404,7 @@ fn __action159< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action160< +fn __action161< >( source_code: &str, mode: Mode, @@ -35294,7 +35422,7 @@ fn __action160< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action161< +fn __action162< >( source_code: &str, mode: Mode, @@ -35317,7 +35445,7 @@ fn __action161< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action162< +fn __action163< >( source_code: &str, mode: Mode, @@ -35352,7 +35480,7 @@ fn __action162< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action163< +fn __action164< >( source_code: &str, mode: Mode, @@ -35370,7 +35498,7 @@ fn __action163< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action164< +fn __action165< >( source_code: &str, mode: Mode, @@ -35397,7 +35525,7 @@ fn __action164< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action165< +fn __action166< >( source_code: &str, mode: Mode, @@ -35424,7 +35552,7 @@ fn __action165< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action166< +fn __action167< >( source_code: &str, mode: Mode, @@ -35441,7 +35569,7 @@ fn __action166< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action167< +fn __action168< >( source_code: &str, mode: Mode, @@ -35455,7 +35583,7 @@ fn __action167< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action168< +fn __action169< >( source_code: &str, mode: Mode, @@ -35474,7 +35602,7 @@ fn __action168< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action169< +fn __action170< >( source_code: &str, mode: Mode, @@ -35492,7 +35620,7 @@ fn __action169< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action170< +fn __action171< >( source_code: &str, mode: Mode, @@ -35510,7 +35638,7 @@ fn __action170< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action171< +fn __action172< >( source_code: &str, mode: Mode, @@ -35541,7 +35669,7 @@ fn __action171< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action172< +fn __action173< >( source_code: &str, mode: Mode, @@ -35563,7 +35691,7 @@ fn __action172< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action173< +fn __action174< >( source_code: &str, mode: Mode, @@ -35582,7 +35710,7 @@ fn __action173< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action174< +fn __action175< >( source_code: &str, mode: Mode, @@ -35601,7 +35729,7 @@ fn __action174< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action175< +fn __action176< >( source_code: &str, mode: Mode, @@ -35620,7 +35748,7 @@ fn __action175< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action176< +fn __action177< >( source_code: &str, mode: Mode, @@ -35638,7 +35766,7 @@ fn __action176< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action177< +fn __action178< >( source_code: &str, mode: Mode, @@ -35656,7 +35784,7 @@ fn __action177< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action178< +fn __action179< >( source_code: &str, mode: Mode, @@ -35675,7 +35803,7 @@ fn __action178< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action179< +fn __action180< >( source_code: &str, mode: Mode, @@ -35687,7 +35815,7 @@ fn __action179< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action180< +fn __action181< >( source_code: &str, mode: Mode, @@ -35699,7 +35827,7 @@ fn __action180< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action181< +fn __action182< >( source_code: &str, mode: Mode, @@ -35717,7 +35845,7 @@ fn __action181< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action182< +fn __action183< >( source_code: &str, mode: Mode, @@ -35739,7 +35867,7 @@ fn __action182< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action183< +fn __action184< >( source_code: &str, mode: Mode, @@ -35773,7 +35901,7 @@ fn __action183< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action184< +fn __action185< >( source_code: &str, mode: Mode, @@ -35785,7 +35913,7 @@ fn __action184< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action185< +fn __action186< >( source_code: &str, mode: Mode, @@ -35797,7 +35925,7 @@ fn __action185< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action186< +fn __action187< >( source_code: &str, mode: Mode, @@ -35809,7 +35937,7 @@ fn __action186< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action187< +fn __action188< >( source_code: &str, mode: Mode, @@ -35821,7 +35949,7 @@ fn __action187< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action188< +fn __action189< >( source_code: &str, mode: Mode, @@ -35833,7 +35961,7 @@ fn __action188< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action189< +fn __action190< >( source_code: &str, mode: Mode, @@ -35845,7 +35973,7 @@ fn __action189< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action190< +fn __action191< >( source_code: &str, mode: Mode, @@ -35857,7 +35985,7 @@ fn __action190< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action191< +fn __action192< >( source_code: &str, mode: Mode, @@ -35870,7 +35998,7 @@ fn __action191< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action192< +fn __action193< >( source_code: &str, mode: Mode, @@ -35882,7 +36010,7 @@ fn __action192< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action193< +fn __action194< >( source_code: &str, mode: Mode, @@ -35895,7 +36023,7 @@ fn __action193< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action194< +fn __action195< >( source_code: &str, mode: Mode, @@ -35907,7 +36035,7 @@ fn __action194< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action195< +fn __action196< >( source_code: &str, mode: Mode, @@ -35919,7 +36047,7 @@ fn __action195< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action196< +fn __action197< >( source_code: &str, mode: Mode, @@ -35931,7 +36059,7 @@ fn __action196< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action197< +fn __action198< >( source_code: &str, mode: Mode, @@ -35943,7 +36071,7 @@ fn __action197< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action198< +fn __action199< >( source_code: &str, mode: Mode, @@ -35955,7 +36083,7 @@ fn __action198< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action199< +fn __action200< >( source_code: &str, mode: Mode, @@ -35967,7 +36095,7 @@ fn __action199< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action200< +fn __action201< >( source_code: &str, mode: Mode, @@ -35979,7 +36107,7 @@ fn __action200< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action201< +fn __action202< >( source_code: &str, mode: Mode, @@ -35991,7 +36119,7 @@ fn __action201< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action202< +fn __action203< >( source_code: &str, mode: Mode, @@ -36003,7 +36131,7 @@ fn __action202< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action203< +fn __action204< >( source_code: &str, mode: Mode, @@ -36015,7 +36143,7 @@ fn __action203< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action204< +fn __action205< >( source_code: &str, mode: Mode, @@ -36027,7 +36155,7 @@ fn __action204< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action205< +fn __action206< >( source_code: &str, mode: Mode, @@ -36039,7 +36167,7 @@ fn __action205< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action206< +fn __action207< >( source_code: &str, mode: Mode, @@ -36051,7 +36179,7 @@ fn __action206< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action207< +fn __action208< >( source_code: &str, mode: Mode, @@ -36072,7 +36200,7 @@ fn __action207< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action208< +fn __action209< >( source_code: &str, mode: Mode, @@ -36094,7 +36222,7 @@ fn __action208< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action209< +fn __action210< >( source_code: &str, mode: Mode, @@ -36106,7 +36234,7 @@ fn __action209< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action210< +fn __action211< >( source_code: &str, mode: Mode, @@ -36130,7 +36258,7 @@ fn __action210< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action211< +fn __action212< >( source_code: &str, mode: Mode, @@ -36144,7 +36272,36 @@ fn __action211< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action212< +fn __action213< +>( + source_code: &str, + mode: Mode, + (_, location, _): (TextSize, TextSize, TextSize), + (_, string, _): (TextSize, StringType, TextSize), +) -> ast::Expr +{ + string.into() +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action214< +>( + source_code: &str, + mode: Mode, + (_, location, _): (TextSize, TextSize, TextSize), + (_, strings, _): (TextSize, Vec, TextSize), + (_, end_location, _): (TextSize, TextSize, TextSize), +) -> Result> +{ + { + Ok(concatenated_strings(strings, (location..end_location).into())?) + } +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action215< >( source_code: &str, mode: Mode, @@ -36156,7 +36313,7 @@ fn __action212< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action213< +fn __action216< >( source_code: &str, mode: Mode, @@ -36168,23 +36325,24 @@ fn __action213< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action214< +fn __action217< >( source_code: &str, mode: Mode, - (_, start_location, _): (TextSize, TextSize, TextSize), + (_, location, _): (TextSize, TextSize, TextSize), (_, string, _): (TextSize, (String, StringKind, bool), TextSize), + (_, end_location, _): (TextSize, TextSize, TextSize), ) -> Result> { { let (source, kind, triple_quoted) = string; - Ok(parse_string_literal(&source, kind, triple_quoted, start_location)?) + Ok(parse_string_literal(&source, kind, triple_quoted, (location..end_location).into())?) } } #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action215< +fn __action218< >( source_code: &str, mode: Mode, @@ -36196,9 +36354,8 @@ fn __action215< ) -> StringType { { - StringType::FString(ast::ExprFString { + StringType::FString(ast::FString { values, - implicit_concatenated: false, range: (location..end_location).into() }) } @@ -36206,7 +36363,7 @@ fn __action215< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action216< +fn __action219< >( source_code: &str, mode: Mode, @@ -36218,23 +36375,24 @@ fn __action216< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action217< +fn __action220< >( source_code: &str, mode: Mode, - (_, start_location, _): (TextSize, TextSize, TextSize), + (_, location, _): (TextSize, TextSize, TextSize), (_, fstring_middle, _): (TextSize, (String, bool), TextSize), + (_, end_location, _): (TextSize, TextSize, TextSize), ) -> Result> { { let (source, is_raw) = fstring_middle; - Ok(parse_fstring_middle(&source, is_raw, start_location)?) + Ok(parse_fstring_middle(&source, is_raw, (location..end_location).into())?) } } #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action218< +fn __action221< >( source_code: &str, mode: Mode, @@ -36287,7 +36445,7 @@ fn __action218< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action219< +fn __action222< >( source_code: &str, mode: Mode, @@ -36300,7 +36458,7 @@ fn __action219< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action220< +fn __action223< >( source_code: &str, mode: Mode, @@ -36310,9 +36468,8 @@ fn __action220< ) -> ast::Expr { { - ast::ExprFString { + ast::FString { values, - implicit_concatenated: false, range: (location..end_location).into() }.into() } @@ -36320,7 +36477,7 @@ fn __action220< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action221< +fn __action224< >( source_code: &str, mode: Mode, @@ -36346,7 +36503,7 @@ fn __action221< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action222< +fn __action225< >( source_code: &str, mode: Mode, @@ -36359,7 +36516,7 @@ fn __action222< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action223< +fn __action226< >( source_code: &str, mode: Mode, @@ -36372,7 +36529,7 @@ fn __action223< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action224< +fn __action227< >( source_code: &str, mode: Mode, @@ -36386,7 +36543,7 @@ fn __action224< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action225< +fn __action228< >( source_code: &str, mode: Mode, @@ -36398,7 +36555,7 @@ fn __action225< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action226< +fn __action229< >( source_code: &str, mode: Mode, @@ -36411,7 +36568,7 @@ fn __action226< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action227< +fn __action230< >( source_code: &str, mode: Mode, @@ -36424,7 +36581,7 @@ fn __action227< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action228< +fn __action231< >( source_code: &str, mode: Mode, @@ -36436,7 +36593,7 @@ fn __action228< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action229< +fn __action232< >( source_code: &str, mode: Mode, @@ -36448,7 +36605,7 @@ fn __action229< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action230< +fn __action233< >( source_code: &str, mode: Mode, @@ -36460,7 +36617,7 @@ fn __action230< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action231< +fn __action234< >( source_code: &str, mode: Mode, @@ -36473,7 +36630,7 @@ fn __action231< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action232< +fn __action235< >( source_code: &str, mode: Mode, @@ -36485,7 +36642,7 @@ fn __action232< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action233< +fn __action236< >( source_code: &str, mode: Mode, @@ -36504,7 +36661,7 @@ fn __action233< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action234< +fn __action237< >( source_code: &str, mode: Mode, @@ -36516,7 +36673,7 @@ fn __action234< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action235< +fn __action238< >( source_code: &str, mode: Mode, @@ -36545,7 +36702,7 @@ fn __action235< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action236< +fn __action239< >( source_code: &str, mode: Mode, @@ -36557,7 +36714,7 @@ fn __action236< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action237< +fn __action240< >( source_code: &str, mode: Mode, @@ -36570,7 +36727,7 @@ fn __action237< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action238< +fn __action241< >( source_code: &str, mode: Mode, @@ -36593,7 +36750,7 @@ fn __action238< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action239< +fn __action242< >( source_code: &str, mode: Mode, @@ -36620,7 +36777,7 @@ fn __action239< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action240< +fn __action243< >( source_code: &str, mode: Mode, @@ -36636,7 +36793,7 @@ fn __action240< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action241< +fn __action244< >( source_code: &str, mode: Mode, @@ -36656,7 +36813,7 @@ fn __action241< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action242< +fn __action245< >( source_code: &str, mode: Mode, @@ -36671,7 +36828,7 @@ fn __action242< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action243< +fn __action246< >( source_code: &str, mode: Mode, @@ -36683,7 +36840,7 @@ fn __action243< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action244< +fn __action247< >( source_code: &str, mode: Mode, @@ -36695,7 +36852,7 @@ fn __action244< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action245< +fn __action248< >( source_code: &str, mode: Mode, @@ -36707,7 +36864,7 @@ fn __action245< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action246< +fn __action249< >( source_code: &str, mode: Mode, @@ -36721,7 +36878,7 @@ fn __action246< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action247< +fn __action250< >( source_code: &str, mode: Mode, @@ -36733,7 +36890,7 @@ fn __action247< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action248< +fn __action251< >( source_code: &str, mode: Mode, @@ -36746,7 +36903,7 @@ fn __action248< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action249< +fn __action252< >( source_code: &str, mode: Mode, @@ -36764,7 +36921,7 @@ fn __action249< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action250< +fn __action253< >( source_code: &str, mode: Mode, @@ -36777,7 +36934,7 @@ fn __action250< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action251< +fn __action254< >( source_code: &str, mode: Mode, @@ -36789,7 +36946,7 @@ fn __action251< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action252< +fn __action255< >( source_code: &str, mode: Mode, @@ -36807,7 +36964,7 @@ fn __action252< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action253< +fn __action256< >( source_code: &str, mode: Mode, @@ -36819,7 +36976,7 @@ fn __action253< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action254< +fn __action257< >( source_code: &str, mode: Mode, @@ -36831,7 +36988,7 @@ fn __action254< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action255< +fn __action258< >( source_code: &str, mode: Mode, @@ -36844,7 +37001,7 @@ fn __action255< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action256< +fn __action259< >( source_code: &str, mode: Mode, @@ -36869,7 +37026,7 @@ fn __action256< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action257< +fn __action260< >( source_code: &str, mode: Mode, @@ -36881,7 +37038,7 @@ fn __action257< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action258< +fn __action261< >( source_code: &str, mode: Mode, @@ -36898,7 +37055,7 @@ fn __action258< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action259< +fn __action262< >( source_code: &str, mode: Mode, @@ -36923,7 +37080,7 @@ fn __action259< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action260< +fn __action263< >( source_code: &str, mode: Mode, @@ -36935,7 +37092,7 @@ fn __action260< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action261< +fn __action264< >( source_code: &str, mode: Mode, @@ -36952,7 +37109,7 @@ fn __action261< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action262< +fn __action265< >( source_code: &str, mode: Mode, @@ -36964,7 +37121,7 @@ fn __action262< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action263< +fn __action266< >( source_code: &str, mode: Mode, @@ -36981,7 +37138,7 @@ fn __action263< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action264< +fn __action267< >( source_code: &str, mode: Mode, @@ -36993,7 +37150,7 @@ fn __action264< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action265< +fn __action268< >( source_code: &str, mode: Mode, @@ -37006,7 +37163,7 @@ fn __action265< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action266< +fn __action269< >( source_code: &str, mode: Mode, @@ -37018,7 +37175,7 @@ fn __action266< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action267< +fn __action270< >( source_code: &str, mode: Mode, @@ -37031,7 +37188,7 @@ fn __action267< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action268< +fn __action271< >( source_code: &str, mode: Mode, @@ -37043,7 +37200,7 @@ fn __action268< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action269< +fn __action272< >( source_code: &str, mode: Mode, @@ -37056,7 +37213,7 @@ fn __action269< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action270< +fn __action273< >( source_code: &str, mode: Mode, @@ -37069,7 +37226,7 @@ fn __action270< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action271< +fn __action274< >( source_code: &str, mode: Mode, @@ -37081,7 +37238,36 @@ fn __action271< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action272< +fn __action275< +>( + source_code: &str, + mode: Mode, + (_, e1, _): (TextSize, StringType, TextSize), + (_, e2, _): (TextSize, StringType, TextSize), +) -> Vec +{ + vec![e1, e2] +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action276< +>( + source_code: &str, + mode: Mode, + (_, mut v, _): (TextSize, Vec, TextSize), + (_, e, _): (TextSize, StringType, TextSize), +) -> Vec +{ + { + v.push(e); + v + } +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action277< >( source_code: &str, mode: Mode, @@ -37093,7 +37279,7 @@ fn __action272< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action273< +fn __action278< >( source_code: &str, mode: Mode, @@ -37106,7 +37292,7 @@ fn __action273< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action274< +fn __action279< >( source_code: &str, mode: Mode, @@ -37120,7 +37306,7 @@ fn __action274< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action275< +fn __action280< >( source_code: &str, mode: Mode, @@ -37137,7 +37323,7 @@ fn __action275< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action276< +fn __action281< >( source_code: &str, mode: Mode, @@ -37149,7 +37335,7 @@ fn __action276< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action277< +fn __action282< >( source_code: &str, mode: Mode, @@ -37162,7 +37348,7 @@ fn __action277< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action278< +fn __action283< >( source_code: &str, mode: Mode, @@ -37174,7 +37360,7 @@ fn __action278< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action279< +fn __action284< >( source_code: &str, mode: Mode, @@ -37187,7 +37373,7 @@ fn __action279< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action280< +fn __action285< >( source_code: &str, mode: Mode, @@ -37218,7 +37404,7 @@ fn __action280< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action281< +fn __action286< >( source_code: &str, mode: Mode, @@ -37251,7 +37437,7 @@ fn __action281< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action282< +fn __action287< >( source_code: &str, mode: Mode, @@ -37276,7 +37462,7 @@ fn __action282< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action283< +fn __action288< >( source_code: &str, mode: Mode, @@ -37300,7 +37486,7 @@ fn __action283< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action284< +fn __action289< >( source_code: &str, mode: Mode, @@ -37312,7 +37498,7 @@ fn __action284< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action285< +fn __action290< >( source_code: &str, mode: Mode, @@ -37329,7 +37515,7 @@ fn __action285< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action286< +fn __action291< >( source_code: &str, mode: Mode, @@ -37341,7 +37527,7 @@ fn __action286< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action287< +fn __action292< >( source_code: &str, mode: Mode, @@ -37354,7 +37540,7 @@ fn __action287< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action288< +fn __action293< >( source_code: &str, mode: Mode, @@ -37366,7 +37552,7 @@ fn __action288< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action289< +fn __action294< >( source_code: &str, mode: Mode, @@ -37379,7 +37565,7 @@ fn __action289< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action290< +fn __action295< >( source_code: &str, mode: Mode, @@ -37392,7 +37578,7 @@ fn __action290< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action291< +fn __action296< >( source_code: &str, mode: Mode, @@ -37404,7 +37590,7 @@ fn __action291< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action292< +fn __action297< >( source_code: &str, mode: Mode, @@ -37417,7 +37603,7 @@ fn __action292< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action293< +fn __action298< >( source_code: &str, mode: Mode, @@ -37430,7 +37616,7 @@ fn __action293< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action294< +fn __action299< >( source_code: &str, mode: Mode, @@ -37442,7 +37628,7 @@ fn __action294< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action295< +fn __action300< >( source_code: &str, mode: Mode, @@ -37455,7 +37641,7 @@ fn __action295< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action296< +fn __action301< >( source_code: &str, mode: Mode, @@ -37467,7 +37653,7 @@ fn __action296< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action297< +fn __action302< >( source_code: &str, mode: Mode, @@ -37498,7 +37684,7 @@ fn __action297< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action298< +fn __action303< >( source_code: &str, mode: Mode, @@ -37531,7 +37717,7 @@ fn __action298< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action299< +fn __action304< >( source_code: &str, mode: Mode, @@ -37556,7 +37742,7 @@ fn __action299< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action300< +fn __action305< >( source_code: &str, mode: Mode, @@ -37580,7 +37766,7 @@ fn __action300< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action301< +fn __action306< >( source_code: &str, mode: Mode, @@ -37592,7 +37778,7 @@ fn __action301< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action302< +fn __action307< >( source_code: &str, mode: Mode, @@ -37605,7 +37791,7 @@ fn __action302< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action303< +fn __action308< >( source_code: &str, mode: Mode, @@ -37618,7 +37804,7 @@ fn __action303< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action304< +fn __action309< >( source_code: &str, mode: Mode, @@ -37630,7 +37816,7 @@ fn __action304< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action305< +fn __action310< >( source_code: &str, mode: Mode, @@ -37643,7 +37829,7 @@ fn __action305< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action306< +fn __action311< >( source_code: &str, mode: Mode, @@ -37656,7 +37842,7 @@ fn __action306< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action307< +fn __action312< >( source_code: &str, mode: Mode, @@ -37668,7 +37854,7 @@ fn __action307< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action308< +fn __action313< >( source_code: &str, mode: Mode, @@ -37680,7 +37866,7 @@ fn __action308< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action309< +fn __action314< >( source_code: &str, mode: Mode, @@ -37697,7 +37883,7 @@ fn __action309< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action310< +fn __action315< >( source_code: &str, mode: Mode, @@ -37709,7 +37895,7 @@ fn __action310< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action311< +fn __action316< >( source_code: &str, mode: Mode, @@ -37722,7 +37908,7 @@ fn __action311< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action312< +fn __action317< >( source_code: &str, mode: Mode, @@ -37740,7 +37926,7 @@ fn __action312< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action313< +fn __action318< >( source_code: &str, mode: Mode, @@ -37752,7 +37938,7 @@ fn __action313< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action314< +fn __action319< >( source_code: &str, mode: Mode, @@ -37765,7 +37951,7 @@ fn __action314< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action315< +fn __action320< >( source_code: &str, mode: Mode, @@ -37777,7 +37963,7 @@ fn __action315< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action316< +fn __action321< >( source_code: &str, mode: Mode, @@ -37790,7 +37976,7 @@ fn __action316< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action317< +fn __action322< >( source_code: &str, mode: Mode, @@ -37808,7 +37994,7 @@ fn __action317< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action318< +fn __action323< >( source_code: &str, mode: Mode, @@ -37820,7 +38006,7 @@ fn __action318< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action319< +fn __action324< >( source_code: &str, mode: Mode, @@ -37832,7 +38018,7 @@ fn __action319< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action320< +fn __action325< >( source_code: &str, mode: Mode, @@ -37845,7 +38031,7 @@ fn __action320< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action321< +fn __action326< >( source_code: &str, mode: Mode, @@ -37858,7 +38044,7 @@ fn __action321< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action322< +fn __action327< >( source_code: &str, mode: Mode, @@ -37870,7 +38056,7 @@ fn __action322< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action323< +fn __action328< >( source_code: &str, mode: Mode, @@ -37883,7 +38069,7 @@ fn __action323< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action324< +fn __action329< >( source_code: &str, mode: Mode, @@ -37897,7 +38083,7 @@ fn __action324< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action325< +fn __action330< >( source_code: &str, mode: Mode, @@ -37909,7 +38095,7 @@ fn __action325< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action326< +fn __action331< >( source_code: &str, mode: Mode, @@ -37922,7 +38108,7 @@ fn __action326< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action327< +fn __action332< >( source_code: &str, mode: Mode, @@ -37934,7 +38120,7 @@ fn __action327< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action328< +fn __action333< >( source_code: &str, mode: Mode, @@ -37947,7 +38133,7 @@ fn __action328< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action329< +fn __action334< >( source_code: &str, mode: Mode, @@ -37961,7 +38147,7 @@ fn __action329< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action330< +fn __action335< >( source_code: &str, mode: Mode, @@ -37973,7 +38159,7 @@ fn __action330< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action331< +fn __action336< >( source_code: &str, mode: Mode, @@ -37986,7 +38172,7 @@ fn __action331< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action332< +fn __action337< >( source_code: &str, mode: Mode, @@ -37998,7 +38184,7 @@ fn __action332< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action333< +fn __action338< >( source_code: &str, mode: Mode, @@ -38011,7 +38197,7 @@ fn __action333< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action334< +fn __action339< >( source_code: &str, mode: Mode, @@ -38023,7 +38209,7 @@ fn __action334< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action335< +fn __action340< >( source_code: &str, mode: Mode, @@ -38036,7 +38222,7 @@ fn __action335< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action336< +fn __action341< >( source_code: &str, mode: Mode, @@ -38050,7 +38236,7 @@ fn __action336< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action337< +fn __action342< >( source_code: &str, mode: Mode, @@ -38062,7 +38248,7 @@ fn __action337< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action338< +fn __action343< >( source_code: &str, mode: Mode, @@ -38075,7 +38261,7 @@ fn __action338< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action339< +fn __action344< >( source_code: &str, mode: Mode, @@ -38090,7 +38276,7 @@ fn __action339< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action340< +fn __action345< >( source_code: &str, mode: Mode, @@ -38103,7 +38289,7 @@ fn __action340< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action341< +fn __action346< >( source_code: &str, mode: Mode, @@ -38115,7 +38301,7 @@ fn __action341< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action342< +fn __action347< >( source_code: &str, mode: Mode, @@ -38131,7 +38317,7 @@ fn __action342< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action343< +fn __action348< >( source_code: &str, mode: Mode, @@ -38143,7 +38329,7 @@ fn __action343< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action344< +fn __action349< >( source_code: &str, mode: Mode, @@ -38160,7 +38346,7 @@ fn __action344< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action345< +fn __action350< >( source_code: &str, mode: Mode, @@ -38172,7 +38358,7 @@ fn __action345< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action346< +fn __action351< >( source_code: &str, mode: Mode, @@ -38189,7 +38375,7 @@ fn __action346< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action347< +fn __action352< >( source_code: &str, mode: Mode, @@ -38201,7 +38387,7 @@ fn __action347< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action348< +fn __action353< >( source_code: &str, mode: Mode, @@ -38218,57 +38404,36 @@ fn __action348< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action349< ->( - source_code: &str, - mode: Mode, - (_, __0, _): (TextSize, StringType, TextSize), -) -> alloc::vec::Vec -{ - alloc::vec![__0] -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action350< ->( - source_code: &str, - mode: Mode, - (_, v, _): (TextSize, alloc::vec::Vec, TextSize), - (_, e, _): (TextSize, StringType, TextSize), -) -> alloc::vec::Vec -{ - { let mut v = v; v.push(e); v } -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action351< +fn __action354< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, StringType, TextSize), -) -> alloc::vec::Vec + (_, e1, _): (TextSize, StringType, TextSize), + (_, e2, _): (TextSize, StringType, TextSize), +) -> Vec { - alloc::vec![__0] + vec![e1, e2] } #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action352< +fn __action355< >( source_code: &str, mode: Mode, - (_, v, _): (TextSize, alloc::vec::Vec, TextSize), + (_, mut v, _): (TextSize, Vec, TextSize), (_, e, _): (TextSize, StringType, TextSize), -) -> alloc::vec::Vec +) -> Vec { - { let mut v = v; v.push(e); v } + { + v.push(e); + v + } } #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action353< +fn __action356< >( source_code: &str, mode: Mode, @@ -38286,7 +38451,7 @@ fn __action353< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action354< +fn __action357< >( source_code: &str, mode: Mode, @@ -38298,7 +38463,7 @@ fn __action354< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action355< +fn __action358< >( source_code: &str, mode: Mode, @@ -38311,7 +38476,7 @@ fn __action355< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action356< +fn __action359< >( source_code: &str, mode: Mode, @@ -38324,7 +38489,7 @@ fn __action356< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action357< +fn __action360< >( source_code: &str, mode: Mode, @@ -38338,7 +38503,7 @@ fn __action357< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action358< +fn __action361< >( source_code: &str, mode: Mode, @@ -38355,7 +38520,7 @@ fn __action358< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action359< +fn __action362< >( source_code: &str, mode: Mode, @@ -38369,7 +38534,7 @@ fn __action359< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action360< +fn __action363< >( source_code: &str, mode: Mode, @@ -38386,7 +38551,7 @@ fn __action360< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action361< +fn __action364< >( source_code: &str, mode: Mode, @@ -38398,7 +38563,7 @@ fn __action361< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action362< +fn __action365< >( source_code: &str, mode: Mode, @@ -38411,7 +38576,7 @@ fn __action362< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action363< +fn __action366< >( source_code: &str, mode: Mode, @@ -38423,7 +38588,7 @@ fn __action363< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action364< +fn __action367< >( source_code: &str, mode: Mode, @@ -38437,7 +38602,7 @@ fn __action364< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action365< +fn __action368< >( source_code: &str, mode: Mode, @@ -38454,7 +38619,7 @@ fn __action365< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action366< +fn __action369< >( source_code: &str, mode: Mode, @@ -38466,7 +38631,7 @@ fn __action366< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action367< +fn __action370< >( source_code: &str, mode: Mode, @@ -38479,7 +38644,7 @@ fn __action367< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action368< +fn __action371< >( source_code: &str, mode: Mode, @@ -38491,7 +38656,7 @@ fn __action368< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action369< +fn __action372< >( source_code: &str, mode: Mode, @@ -38504,7 +38669,7 @@ fn __action369< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action370< +fn __action373< >( source_code: &str, mode: Mode, @@ -38516,7 +38681,7 @@ fn __action370< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action371< +fn __action374< >( source_code: &str, mode: Mode, @@ -38537,7 +38702,7 @@ fn __action371< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action372< +fn __action375< >( source_code: &str, mode: Mode, @@ -38549,7 +38714,7 @@ fn __action372< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action373< +fn __action376< >( source_code: &str, mode: Mode, @@ -38561,7 +38726,7 @@ fn __action373< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action374< +fn __action377< >( source_code: &str, mode: Mode, @@ -38574,7 +38739,7 @@ fn __action374< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action375< +fn __action378< >( source_code: &str, mode: Mode, @@ -38587,7 +38752,7 @@ fn __action375< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action376< +fn __action379< >( source_code: &str, mode: Mode, @@ -38599,7 +38764,7 @@ fn __action376< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action377< +fn __action380< >( source_code: &str, mode: Mode, @@ -38616,7 +38781,7 @@ fn __action377< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action378< +fn __action381< >( source_code: &str, mode: Mode, @@ -38628,7 +38793,7 @@ fn __action378< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action379< +fn __action382< >( source_code: &str, mode: Mode, @@ -38641,7 +38806,7 @@ fn __action379< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action380< +fn __action383< >( source_code: &str, mode: Mode, @@ -38654,7 +38819,7 @@ fn __action380< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action381< +fn __action384< >( source_code: &str, mode: Mode, @@ -38666,7 +38831,7 @@ fn __action381< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action382< +fn __action385< >( source_code: &str, mode: Mode, @@ -38679,7 +38844,7 @@ fn __action382< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action383< +fn __action386< >( source_code: &str, mode: Mode, @@ -38691,7 +38856,7 @@ fn __action383< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action384< +fn __action387< >( source_code: &str, mode: Mode, @@ -38708,7 +38873,7 @@ fn __action384< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action385< +fn __action388< >( source_code: &str, mode: Mode, @@ -38723,7 +38888,7 @@ fn __action385< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action386< +fn __action389< >( source_code: &str, mode: Mode, @@ -38735,7 +38900,7 @@ fn __action386< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action387< +fn __action390< >( source_code: &str, mode: Mode, @@ -38748,7 +38913,7 @@ fn __action387< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action388< +fn __action391< >( source_code: &str, mode: Mode, @@ -38761,7 +38926,7 @@ fn __action388< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action389< +fn __action392< >( source_code: &str, mode: Mode, @@ -38773,7 +38938,7 @@ fn __action389< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action390< +fn __action393< >( source_code: &str, mode: Mode, @@ -38785,7 +38950,7 @@ fn __action390< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action391< +fn __action394< >( source_code: &str, mode: Mode, @@ -38802,7 +38967,7 @@ fn __action391< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action392< +fn __action395< >( source_code: &str, mode: Mode, @@ -38817,7 +38982,7 @@ fn __action392< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action393< +fn __action396< >( source_code: &str, mode: Mode, @@ -38829,7 +38994,7 @@ fn __action393< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action394< +fn __action397< >( source_code: &str, mode: Mode, @@ -38842,7 +39007,7 @@ fn __action394< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action395< +fn __action398< >( source_code: &str, mode: Mode, @@ -38855,7 +39020,7 @@ fn __action395< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action396< +fn __action399< >( source_code: &str, mode: Mode, @@ -38867,7 +39032,7 @@ fn __action396< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action397< +fn __action400< >( source_code: &str, mode: Mode, @@ -38880,7 +39045,7 @@ fn __action397< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action398< +fn __action401< >( source_code: &str, mode: Mode, @@ -38892,7 +39057,7 @@ fn __action398< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action399< +fn __action402< >( source_code: &str, mode: Mode, @@ -38905,7 +39070,7 @@ fn __action399< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action400< +fn __action403< >( source_code: &str, mode: Mode, @@ -38928,7 +39093,7 @@ fn __action400< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action401< +fn __action404< >( source_code: &str, mode: Mode, @@ -38940,7 +39105,7 @@ fn __action401< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action402< +fn __action405< >( source_code: &str, mode: Mode, @@ -38952,7 +39117,7 @@ fn __action402< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action403< +fn __action406< >( source_code: &str, mode: Mode, @@ -38965,7 +39130,7 @@ fn __action403< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action404< +fn __action407< >( source_code: &str, mode: Mode, @@ -38977,7 +39142,7 @@ fn __action404< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action405< +fn __action408< >( source_code: &str, mode: Mode, @@ -38989,7 +39154,7 @@ fn __action405< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action406< +fn __action409< >( source_code: &str, mode: Mode, @@ -39002,7 +39167,7 @@ fn __action406< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action407< +fn __action410< >( source_code: &str, mode: Mode, @@ -39015,7 +39180,7 @@ fn __action407< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action408< +fn __action411< >( source_code: &str, mode: Mode, @@ -39027,7 +39192,7 @@ fn __action408< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action409< +fn __action412< >( source_code: &str, mode: Mode, @@ -39040,7 +39205,7 @@ fn __action409< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action410< +fn __action413< >( source_code: &str, mode: Mode, @@ -39053,7 +39218,7 @@ fn __action410< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action411< +fn __action414< >( source_code: &str, mode: Mode, @@ -39065,7 +39230,7 @@ fn __action411< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action412< +fn __action415< >( source_code: &str, mode: Mode, @@ -39076,7 +39241,7 @@ fn __action412< } #[allow(unused_variables)] -fn __action413< +fn __action416< >( source_code: &str, mode: Mode, @@ -39088,7 +39253,7 @@ fn __action413< } #[allow(unused_variables)] -fn __action414< +fn __action417< >( source_code: &str, mode: Mode, @@ -39101,7 +39266,7 @@ fn __action414< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action415< +fn __action418< >( source_code: &str, mode: Mode, @@ -39113,7 +39278,7 @@ fn __action415< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action416< +fn __action419< >( source_code: &str, mode: Mode, @@ -39126,7 +39291,7 @@ fn __action416< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action417< +fn __action420< >( source_code: &str, mode: Mode, @@ -39138,7 +39303,7 @@ fn __action417< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action418< +fn __action421< >( source_code: &str, mode: Mode, @@ -39151,7 +39316,7 @@ fn __action418< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action419< +fn __action422< >( source_code: &str, mode: Mode, @@ -39163,7 +39328,7 @@ fn __action419< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action420< +fn __action423< >( source_code: &str, mode: Mode, @@ -39176,7 +39341,7 @@ fn __action420< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action421< +fn __action424< >( source_code: &str, mode: Mode, @@ -39188,7 +39353,7 @@ fn __action421< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action422< +fn __action425< >( source_code: &str, mode: Mode, @@ -39201,7 +39366,7 @@ fn __action422< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action423< +fn __action426< >( source_code: &str, mode: Mode, @@ -39214,7 +39379,7 @@ fn __action423< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action424< +fn __action427< >( source_code: &str, mode: Mode, @@ -39235,7 +39400,7 @@ fn __action424< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action425< +fn __action428< >( source_code: &str, mode: Mode, @@ -39247,7 +39412,7 @@ fn __action425< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action426< +fn __action429< >( source_code: &str, mode: Mode, @@ -39259,7 +39424,7 @@ fn __action426< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action427< +fn __action430< >( source_code: &str, mode: Mode, @@ -39272,7 +39437,7 @@ fn __action427< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action428< +fn __action431< >( source_code: &str, mode: Mode, @@ -39285,7 +39450,7 @@ fn __action428< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action429< +fn __action432< >( source_code: &str, mode: Mode, @@ -39297,7 +39462,7 @@ fn __action429< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action430< +fn __action433< >( source_code: &str, mode: Mode, @@ -39309,7 +39474,7 @@ fn __action430< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action431< +fn __action434< >( source_code: &str, mode: Mode, @@ -39322,7 +39487,7 @@ fn __action431< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action432< +fn __action435< >( source_code: &str, mode: Mode, @@ -39345,7 +39510,7 @@ fn __action432< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action433< +fn __action436< >( source_code: &str, mode: Mode, @@ -39357,7 +39522,7 @@ fn __action433< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action434< +fn __action437< >( source_code: &str, mode: Mode, @@ -39369,7 +39534,7 @@ fn __action434< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action435< +fn __action438< >( source_code: &str, mode: Mode, @@ -39381,7 +39546,7 @@ fn __action435< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action436< +fn __action439< >( source_code: &str, mode: Mode, @@ -39394,7 +39559,7 @@ fn __action436< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action437< +fn __action440< >( source_code: &str, mode: Mode, @@ -39407,7 +39572,7 @@ fn __action437< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action438< +fn __action441< >( source_code: &str, mode: Mode, @@ -39422,7 +39587,7 @@ fn __action438< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action439< +fn __action442< >( source_code: &str, mode: Mode, @@ -39434,7 +39599,7 @@ fn __action439< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action440< +fn __action443< >( source_code: &str, mode: Mode, @@ -39447,7 +39612,7 @@ fn __action440< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action441< +fn __action444< >( source_code: &str, mode: Mode, @@ -39460,7 +39625,7 @@ fn __action441< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action442< +fn __action445< >( source_code: &str, mode: Mode, @@ -39488,7 +39653,7 @@ fn __action442< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action443< +fn __action446< >( source_code: &str, mode: Mode, @@ -39502,7 +39667,7 @@ fn __action443< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action444< +fn __action447< >( source_code: &str, mode: Mode, @@ -39519,7 +39684,7 @@ fn __action444< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action445< +fn __action448< >( source_code: &str, mode: Mode, @@ -39532,7 +39697,7 @@ fn __action445< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action446< +fn __action449< >( source_code: &str, mode: Mode, @@ -39547,7 +39712,7 @@ fn __action446< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action447< +fn __action450< >( source_code: &str, mode: Mode, @@ -39559,7 +39724,7 @@ fn __action447< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action448< +fn __action451< >( source_code: &str, mode: Mode, @@ -39572,7 +39737,7 @@ fn __action448< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action449< +fn __action452< >( source_code: &str, mode: Mode, @@ -39585,7 +39750,7 @@ fn __action449< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action450< +fn __action453< >( source_code: &str, mode: Mode, @@ -39613,7 +39778,7 @@ fn __action450< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action451< +fn __action454< >( source_code: &str, mode: Mode, @@ -39627,7 +39792,7 @@ fn __action451< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action452< +fn __action455< >( source_code: &str, mode: Mode, @@ -39644,7 +39809,7 @@ fn __action452< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action453< +fn __action456< >( source_code: &str, mode: Mode, @@ -39656,7 +39821,7 @@ fn __action453< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action454< +fn __action457< >( source_code: &str, mode: Mode, @@ -39669,7 +39834,7 @@ fn __action454< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action455< +fn __action458< >( source_code: &str, mode: Mode, @@ -39681,7 +39846,7 @@ fn __action455< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action456< +fn __action459< >( source_code: &str, mode: Mode, @@ -39698,7 +39863,7 @@ fn __action456< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action457< +fn __action460< >( source_code: &str, mode: Mode, @@ -39710,7 +39875,7 @@ fn __action457< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action458< +fn __action461< >( source_code: &str, mode: Mode, @@ -39723,7 +39888,7 @@ fn __action458< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action459< +fn __action462< >( source_code: &str, mode: Mode, @@ -39736,7 +39901,7 @@ fn __action459< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action460< +fn __action463< >( source_code: &str, mode: Mode, @@ -39754,7 +39919,7 @@ fn __action460< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action461< +fn __action464< >( source_code: &str, mode: Mode, @@ -39766,7 +39931,7 @@ fn __action461< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action462< +fn __action465< >( source_code: &str, mode: Mode, @@ -39778,7 +39943,7 @@ fn __action462< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action463< +fn __action466< >( source_code: &str, mode: Mode, @@ -39791,7 +39956,7 @@ fn __action463< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action464< +fn __action467< >( source_code: &str, mode: Mode, @@ -39803,7 +39968,7 @@ fn __action464< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action465< +fn __action468< >( source_code: &str, mode: Mode, @@ -39816,7 +39981,7 @@ fn __action465< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action466< +fn __action469< >( source_code: &str, mode: Mode, @@ -39829,7 +39994,7 @@ fn __action466< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action467< +fn __action470< >( source_code: &str, mode: Mode, @@ -39841,7 +40006,7 @@ fn __action467< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action468< +fn __action471< >( source_code: &str, mode: Mode, @@ -39854,7 +40019,7 @@ fn __action468< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action469< +fn __action472< >( source_code: &str, mode: Mode, @@ -39866,7 +40031,7 @@ fn __action469< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action470< +fn __action473< >( source_code: &str, mode: Mode, @@ -39879,7 +40044,7 @@ fn __action470< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action471< +fn __action474< >( source_code: &str, mode: Mode, @@ -39891,7 +40056,7 @@ fn __action471< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action472< +fn __action475< >( source_code: &str, mode: Mode, @@ -39904,7 +40069,7 @@ fn __action472< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action473< +fn __action476< >( source_code: &str, mode: Mode, @@ -39917,7 +40082,7 @@ fn __action473< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action474< +fn __action477< >( source_code: &str, mode: Mode, @@ -39936,7 +40101,7 @@ fn __action474< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action475< +fn __action478< >( source_code: &str, mode: Mode, @@ -39948,7 +40113,7 @@ fn __action475< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action476< +fn __action479< >( source_code: &str, mode: Mode, @@ -39960,7 +40125,7 @@ fn __action476< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action477< +fn __action480< >( source_code: &str, mode: Mode, @@ -39977,7 +40142,7 @@ fn __action477< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action478< +fn __action481< >( source_code: &str, mode: Mode, @@ -39989,7 +40154,7 @@ fn __action478< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action479< +fn __action482< >( source_code: &str, mode: Mode, @@ -40002,7 +40167,7 @@ fn __action479< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action480< +fn __action483< >( source_code: &str, mode: Mode, @@ -40015,7 +40180,7 @@ fn __action480< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action481< +fn __action484< >( source_code: &str, mode: Mode, @@ -40027,7 +40192,7 @@ fn __action481< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action482< +fn __action485< >( source_code: &str, mode: Mode, @@ -40040,7 +40205,7 @@ fn __action482< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action483< +fn __action486< >( source_code: &str, mode: Mode, @@ -40052,7 +40217,7 @@ fn __action483< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action484< +fn __action487< >( source_code: &str, mode: Mode, @@ -40071,7 +40236,7 @@ fn __action484< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action485< +fn __action488< >( source_code: &str, mode: Mode, @@ -40083,7 +40248,7 @@ fn __action485< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action486< +fn __action489< >( source_code: &str, mode: Mode, @@ -40096,7 +40261,7 @@ fn __action486< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action487< +fn __action490< >( source_code: &str, mode: Mode, @@ -40108,7 +40273,7 @@ fn __action487< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action488< +fn __action491< >( source_code: &str, mode: Mode, @@ -40125,7 +40290,7 @@ fn __action488< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action489< +fn __action492< >( source_code: &str, mode: Mode, @@ -40137,7 +40302,7 @@ fn __action489< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action490< +fn __action493< >( source_code: &str, mode: Mode, @@ -40150,7 +40315,7 @@ fn __action490< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action491< +fn __action494< >( source_code: &str, mode: Mode, @@ -40163,7 +40328,7 @@ fn __action491< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action492< +fn __action495< >( source_code: &str, mode: Mode, @@ -40175,7 +40340,7 @@ fn __action492< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action493< +fn __action496< >( source_code: &str, mode: Mode, @@ -40188,7 +40353,7 @@ fn __action493< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action494< +fn __action497< >( source_code: &str, mode: Mode, @@ -40200,7 +40365,7 @@ fn __action494< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action495< +fn __action498< >( source_code: &str, mode: Mode, @@ -40219,7 +40384,7 @@ fn __action495< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action496< +fn __action499< >( source_code: &str, mode: Mode, @@ -40231,7 +40396,7 @@ fn __action496< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action497< +fn __action500< >( source_code: &str, mode: Mode, @@ -40244,7 +40409,7 @@ fn __action497< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action498< +fn __action501< >( source_code: &str, mode: Mode, @@ -40256,7 +40421,7 @@ fn __action498< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action499< +fn __action502< >( source_code: &str, mode: Mode, @@ -40269,7 +40434,7 @@ fn __action499< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action500< +fn __action503< >( source_code: &str, mode: Mode, @@ -40287,7 +40452,7 @@ fn __action500< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action501< +fn __action504< >( source_code: &str, mode: Mode, @@ -40299,7 +40464,7 @@ fn __action501< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action502< +fn __action505< >( source_code: &str, mode: Mode, @@ -40320,7 +40485,7 @@ fn __action502< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action503< +fn __action506< >( source_code: &str, mode: Mode, @@ -40332,7 +40497,7 @@ fn __action503< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action504< +fn __action507< >( source_code: &str, mode: Mode, @@ -40353,7 +40518,7 @@ fn __action504< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action505< +fn __action508< >( source_code: &str, mode: Mode, @@ -40365,7 +40530,7 @@ fn __action505< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action506< +fn __action509< >( source_code: &str, mode: Mode, @@ -40383,7 +40548,7 @@ fn __action506< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action507< +fn __action510< >( source_code: &str, mode: Mode, @@ -40395,7 +40560,7 @@ fn __action507< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action508< +fn __action511< >( source_code: &str, mode: Mode, @@ -40407,7 +40572,7 @@ fn __action508< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action509< +fn __action512< >( source_code: &str, mode: Mode, @@ -40420,7 +40585,7 @@ fn __action509< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action510< +fn __action513< >( source_code: &str, mode: Mode, @@ -40432,7 +40597,7 @@ fn __action510< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action511< +fn __action514< >( source_code: &str, mode: Mode, @@ -40445,7 +40610,7 @@ fn __action511< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action512< +fn __action515< >( source_code: &str, mode: Mode, @@ -40463,7 +40628,7 @@ fn __action512< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action513< +fn __action516< >( source_code: &str, mode: Mode, @@ -40475,7 +40640,7 @@ fn __action513< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action514< +fn __action517< >( source_code: &str, mode: Mode, @@ -40487,7 +40652,7 @@ fn __action514< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action515< +fn __action518< >( source_code: &str, mode: Mode, @@ -40500,7 +40665,7 @@ fn __action515< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action516< +fn __action519< >( source_code: &str, mode: Mode, @@ -40513,7 +40678,7 @@ fn __action516< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action517< +fn __action520< >( source_code: &str, mode: Mode, @@ -40532,7 +40697,7 @@ fn __action517< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action518< +fn __action521< >( source_code: &str, mode: Mode, @@ -40544,7 +40709,7 @@ fn __action518< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action519< +fn __action522< >( source_code: &str, mode: Mode, @@ -40565,7 +40730,7 @@ fn __action519< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action520< +fn __action523< >( source_code: &str, mode: Mode, @@ -40577,7 +40742,7 @@ fn __action520< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action521< +fn __action524< >( source_code: &str, mode: Mode, @@ -40598,7 +40763,7 @@ fn __action521< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action522< +fn __action525< >( source_code: &str, mode: Mode, @@ -40610,7 +40775,7 @@ fn __action522< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action523< +fn __action526< >( source_code: &str, mode: Mode, @@ -40628,7 +40793,7 @@ fn __action523< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action524< +fn __action527< >( source_code: &str, mode: Mode, @@ -40640,7 +40805,7 @@ fn __action524< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action525< +fn __action528< >( source_code: &str, mode: Mode, @@ -40661,7 +40826,7 @@ fn __action525< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action526< +fn __action529< >( source_code: &str, mode: Mode, @@ -40673,7 +40838,7 @@ fn __action526< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action527< +fn __action530< >( source_code: &str, mode: Mode, @@ -40692,7 +40857,7 @@ fn __action527< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action528< +fn __action531< >( source_code: &str, mode: Mode, @@ -40704,7 +40869,7 @@ fn __action528< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action529< +fn __action532< >( source_code: &str, mode: Mode, @@ -40725,7 +40890,7 @@ fn __action529< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action530< +fn __action533< >( source_code: &str, mode: Mode, @@ -40737,7 +40902,7 @@ fn __action530< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action531< +fn __action534< >( source_code: &str, mode: Mode, @@ -40758,7 +40923,7 @@ fn __action531< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action532< +fn __action535< >( source_code: &str, mode: Mode, @@ -40770,7 +40935,7 @@ fn __action532< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action533< +fn __action536< >( source_code: &str, mode: Mode, @@ -40791,7 +40956,7 @@ fn __action533< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action534< +fn __action537< >( source_code: &str, mode: Mode, @@ -40803,7 +40968,7 @@ fn __action534< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action535< +fn __action538< >( source_code: &str, mode: Mode, @@ -40820,7 +40985,7 @@ fn __action535< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action536< +fn __action539< >( source_code: &str, mode: Mode, @@ -40832,7 +40997,7 @@ fn __action536< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action537< +fn __action540< >( source_code: &str, mode: Mode, @@ -40844,7 +41009,7 @@ fn __action537< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action538< +fn __action541< >( source_code: &str, mode: Mode, @@ -40863,7 +41028,7 @@ fn __action538< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action539< +fn __action542< >( source_code: &str, mode: Mode, @@ -40885,7 +41050,7 @@ fn __action539< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action540< +fn __action543< >( source_code: &str, mode: Mode, @@ -40906,7 +41071,7 @@ fn __action540< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action541< +fn __action544< >( source_code: &str, mode: Mode, @@ -40927,7 +41092,7 @@ fn __action541< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action542< +fn __action545< >( source_code: &str, mode: Mode, @@ -40939,7 +41104,7 @@ fn __action542< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action543< +fn __action546< >( source_code: &str, mode: Mode, @@ -40960,7 +41125,7 @@ fn __action543< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action544< +fn __action547< >( source_code: &str, mode: Mode, @@ -40972,21 +41137,19 @@ fn __action544< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action545< +fn __action548< >( source_code: &str, mode: Mode, - (_, location, _): (TextSize, TextSize, TextSize), - (_, strings, _): (TextSize, alloc::vec::Vec, TextSize), - (_, end_location, _): (TextSize, TextSize, TextSize), -) -> Result> + (_, expr, _): (TextSize, ast::Expr, TextSize), +) -> ast::ParenthesizedExpr { - Ok(concatenate_strings(strings, (location..end_location).into())?.into()) + expr.into() } #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action546< +fn __action549< >( source_code: &str, mode: Mode, @@ -41003,7 +41166,7 @@ fn __action546< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action547< +fn __action550< >( source_code: &str, mode: Mode, @@ -41021,7 +41184,7 @@ fn __action547< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action548< +fn __action551< >( source_code: &str, mode: Mode, @@ -41040,7 +41203,7 @@ fn __action548< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action549< +fn __action552< >( source_code: &str, mode: Mode, @@ -41059,7 +41222,7 @@ fn __action549< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action550< +fn __action553< >( source_code: &str, mode: Mode, @@ -41086,7 +41249,7 @@ fn __action550< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action551< +fn __action554< >( source_code: &str, mode: Mode, @@ -41121,7 +41284,7 @@ fn __action551< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action552< +fn __action555< >( source_code: &str, mode: Mode, @@ -41140,7 +41303,7 @@ fn __action552< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action553< +fn __action556< >( source_code: &str, mode: Mode, @@ -41159,7 +41322,7 @@ fn __action553< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action554< +fn __action557< >( source_code: &str, mode: Mode, @@ -41180,7 +41343,7 @@ fn __action554< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action555< +fn __action558< >( source_code: &str, mode: Mode, @@ -41202,7 +41365,7 @@ fn __action555< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action556< +fn __action559< >( source_code: &str, mode: Mode, @@ -41225,7 +41388,7 @@ fn __action556< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action557< +fn __action560< >( source_code: &str, mode: Mode, @@ -41249,7 +41412,7 @@ fn __action557< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action558< +fn __action561< >( source_code: &str, mode: Mode, @@ -41271,7 +41434,7 @@ fn __action558< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action559< +fn __action562< >( source_code: &str, mode: Mode, @@ -41292,7 +41455,7 @@ fn __action559< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action560< +fn __action563< >( source_code: &str, mode: Mode, @@ -41306,7 +41469,7 @@ fn __action560< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action561< +fn __action564< >( source_code: &str, mode: Mode, @@ -41320,7 +41483,7 @@ fn __action561< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action562< +fn __action565< >( source_code: &str, mode: Mode, @@ -41334,7 +41497,7 @@ fn __action562< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action563< +fn __action566< >( source_code: &str, mode: Mode, @@ -41348,7 +41511,7 @@ fn __action563< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action564< +fn __action567< >( source_code: &str, mode: Mode, @@ -41360,7 +41523,7 @@ fn __action564< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action565< +fn __action568< >( source_code: &str, mode: Mode, @@ -41373,7 +41536,7 @@ fn __action565< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action566< +fn __action569< >( source_code: &str, mode: Mode, @@ -41386,7 +41549,7 @@ fn __action566< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action567< +fn __action570< >( source_code: &str, mode: Mode, @@ -41398,7 +41561,7 @@ fn __action567< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action568< +fn __action571< >( source_code: &str, mode: Mode, @@ -41411,7 +41574,7 @@ fn __action568< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action569< +fn __action572< >( source_code: &str, mode: Mode, @@ -41423,7 +41586,7 @@ fn __action569< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action570< +fn __action573< >( source_code: &str, mode: Mode, @@ -41436,7 +41599,7 @@ fn __action570< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action571< +fn __action574< >( source_code: &str, mode: Mode, @@ -41449,7 +41612,7 @@ fn __action571< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action572< +fn __action575< >( source_code: &str, mode: Mode, @@ -41461,7 +41624,7 @@ fn __action572< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action573< +fn __action576< >( source_code: &str, mode: Mode, @@ -41474,7 +41637,7 @@ fn __action573< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action574< +fn __action577< >( source_code: &str, mode: Mode, @@ -41495,7 +41658,7 @@ fn __action574< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action575< +fn __action578< >( source_code: &str, mode: Mode, @@ -41507,7 +41670,7 @@ fn __action575< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action576< +fn __action579< >( source_code: &str, mode: Mode, @@ -41526,7 +41689,7 @@ fn __action576< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action577< +fn __action580< >( source_code: &str, mode: Mode, @@ -41538,7 +41701,7 @@ fn __action577< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action578< +fn __action581< >( source_code: &str, mode: Mode, @@ -41550,7 +41713,7 @@ fn __action578< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action579< +fn __action582< >( source_code: &str, mode: Mode, @@ -41563,7 +41726,7 @@ fn __action579< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action580< +fn __action583< >( source_code: &str, mode: Mode, @@ -41584,7 +41747,7 @@ fn __action580< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action581< +fn __action584< >( source_code: &str, mode: Mode, @@ -41596,7 +41759,7 @@ fn __action581< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action582< +fn __action585< >( source_code: &str, mode: Mode, @@ -41613,7 +41776,7 @@ fn __action582< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action583< +fn __action586< >( source_code: &str, mode: Mode, @@ -41625,7 +41788,7 @@ fn __action583< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action584< +fn __action587< >( source_code: &str, mode: Mode, @@ -41637,7 +41800,7 @@ fn __action584< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action585< +fn __action588< >( source_code: &str, mode: Mode, @@ -41656,7 +41819,7 @@ fn __action585< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action586< +fn __action589< >( source_code: &str, mode: Mode, @@ -41678,7 +41841,7 @@ fn __action586< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action587< +fn __action590< >( source_code: &str, mode: Mode, @@ -41699,21 +41862,19 @@ fn __action587< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action588< +fn __action591< >( source_code: &str, mode: Mode, - (_, location, _): (TextSize, TextSize, TextSize), - (_, strings, _): (TextSize, alloc::vec::Vec, TextSize), - (_, end_location, _): (TextSize, TextSize, TextSize), -) -> Result> + (_, expr, _): (TextSize, ast::Expr, TextSize), +) -> ast::ParenthesizedExpr { - Ok(concatenate_strings(strings, (location..end_location).into())?.into()) + expr.into() } #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action589< +fn __action592< >( source_code: &str, mode: Mode, @@ -41730,7 +41891,7 @@ fn __action589< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action590< +fn __action593< >( source_code: &str, mode: Mode, @@ -41748,7 +41909,7 @@ fn __action590< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action591< +fn __action594< >( source_code: &str, mode: Mode, @@ -41767,7 +41928,7 @@ fn __action591< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action592< +fn __action595< >( source_code: &str, mode: Mode, @@ -41786,7 +41947,7 @@ fn __action592< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action593< +fn __action596< >( source_code: &str, mode: Mode, @@ -41821,7 +41982,7 @@ fn __action593< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action594< +fn __action597< >( source_code: &str, mode: Mode, @@ -41840,7 +42001,7 @@ fn __action594< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action595< +fn __action598< >( source_code: &str, mode: Mode, @@ -41859,7 +42020,7 @@ fn __action595< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action596< +fn __action599< >( source_code: &str, mode: Mode, @@ -41880,7 +42041,7 @@ fn __action596< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action597< +fn __action600< >( source_code: &str, mode: Mode, @@ -41902,7 +42063,7 @@ fn __action597< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action598< +fn __action601< >( source_code: &str, mode: Mode, @@ -41925,7 +42086,7 @@ fn __action598< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action599< +fn __action602< >( source_code: &str, mode: Mode, @@ -41949,7 +42110,7 @@ fn __action599< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action600< +fn __action603< >( source_code: &str, mode: Mode, @@ -41971,7 +42132,7 @@ fn __action600< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action601< +fn __action604< >( source_code: &str, mode: Mode, @@ -41992,7 +42153,7 @@ fn __action601< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action602< +fn __action605< >( source_code: &str, mode: Mode, @@ -42006,7 +42167,7 @@ fn __action602< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action603< +fn __action606< >( source_code: &str, mode: Mode, @@ -42020,7 +42181,7 @@ fn __action603< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action604< +fn __action607< >( source_code: &str, mode: Mode, @@ -42034,7 +42195,7 @@ fn __action604< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action605< +fn __action608< >( source_code: &str, mode: Mode, @@ -42048,7 +42209,7 @@ fn __action605< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action606< +fn __action609< >( source_code: &str, mode: Mode, @@ -42062,13 +42223,13 @@ fn __action606< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action550( + __action553( source_code, mode, __0, @@ -42082,7 +42243,7 @@ fn __action606< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action607< +fn __action610< >( source_code: &str, mode: Mode, @@ -42095,14 +42256,14 @@ fn __action607< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action550( + __action553( source_code, mode, __0, @@ -42116,7 +42277,7 @@ fn __action607< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action608< +fn __action611< >( source_code: &str, mode: Mode, @@ -42132,13 +42293,13 @@ fn __action608< { let __start0 = __5.0; let __end0 = __5.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __5, ); let __temp0 = (__start0, __temp0, __end0); - __action551( + __action554( source_code, mode, __0, @@ -42154,7 +42315,7 @@ fn __action608< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action609< +fn __action612< >( source_code: &str, mode: Mode, @@ -42169,14 +42330,14 @@ fn __action609< { let __start0 = __4.2; let __end0 = __5.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action551( + __action554( source_code, mode, __0, @@ -42192,7 +42353,7 @@ fn __action609< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action610< +fn __action613< >( source_code: &str, mode: Mode, @@ -42208,13 +42369,13 @@ fn __action610< { let __start0 = __5.0; let __end0 = __5.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __5, ); let __temp0 = (__start0, __temp0, __end0); - __action593( + __action596( source_code, mode, __0, @@ -42230,7 +42391,7 @@ fn __action610< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action611< +fn __action614< >( source_code: &str, mode: Mode, @@ -42245,14 +42406,14 @@ fn __action611< { let __start0 = __4.2; let __end0 = __5.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action593( + __action596( source_code, mode, __0, @@ -42268,7 +42429,7 @@ fn __action611< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action612< +fn __action615< >( source_code: &str, mode: Mode, @@ -42278,13 +42439,13 @@ fn __action612< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action223( + __action226( source_code, mode, __0, @@ -42294,7 +42455,7 @@ fn __action612< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action613< +fn __action616< >( source_code: &str, mode: Mode, @@ -42303,14 +42464,14 @@ fn __action613< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action223( + __action226( source_code, mode, __0, @@ -42320,7 +42481,7 @@ fn __action613< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action614< +fn __action617< >( source_code: &str, mode: Mode, @@ -42330,13 +42491,13 @@ fn __action614< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action231( + __action234( source_code, mode, __0, @@ -42346,7 +42507,7 @@ fn __action614< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action615< +fn __action618< >( source_code: &str, mode: Mode, @@ -42355,14 +42516,14 @@ fn __action615< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action231( + __action234( source_code, mode, __0, @@ -42372,7 +42533,7 @@ fn __action615< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action616< +fn __action619< >( source_code: &str, mode: Mode, @@ -42384,13 +42545,13 @@ fn __action616< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action259( + __action262( source_code, mode, __0, @@ -42402,7 +42563,7 @@ fn __action616< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action617< +fn __action620< >( source_code: &str, mode: Mode, @@ -42413,14 +42574,14 @@ fn __action617< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action259( + __action262( source_code, mode, __0, @@ -42432,7 +42593,7 @@ fn __action617< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action618< +fn __action621< >( source_code: &str, mode: Mode, @@ -42444,13 +42605,13 @@ fn __action618< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action256( + __action259( source_code, mode, __0, @@ -42462,7 +42623,7 @@ fn __action618< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action619< +fn __action622< >( source_code: &str, mode: Mode, @@ -42473,14 +42634,14 @@ fn __action619< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action256( + __action259( source_code, mode, __0, @@ -42492,7 +42653,7 @@ fn __action619< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action620< +fn __action623< >( source_code: &str, mode: Mode, @@ -42506,7 +42667,7 @@ fn __action620< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __3, @@ -42526,7 +42687,7 @@ fn __action620< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action621< +fn __action624< >( source_code: &str, mode: Mode, @@ -42539,7 +42700,7 @@ fn __action621< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, @@ -42560,7 +42721,7 @@ fn __action621< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action622< +fn __action625< >( source_code: &str, mode: Mode, @@ -42570,13 +42731,13 @@ fn __action622< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action222( + __action225( source_code, mode, __0, @@ -42586,7 +42747,7 @@ fn __action622< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action623< +fn __action626< >( source_code: &str, mode: Mode, @@ -42595,14 +42756,14 @@ fn __action623< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action222( + __action225( source_code, mode, __0, @@ -42612,7 +42773,7 @@ fn __action623< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action624< +fn __action627< >( source_code: &str, mode: Mode, @@ -42626,13 +42787,13 @@ fn __action624< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action135( + __action136( source_code, mode, __0, @@ -42646,7 +42807,7 @@ fn __action624< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action625< +fn __action628< >( source_code: &str, mode: Mode, @@ -42659,14 +42820,14 @@ fn __action625< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action135( + __action136( source_code, mode, __0, @@ -42680,7 +42841,7 @@ fn __action625< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action626< +fn __action629< >( source_code: &str, mode: Mode, @@ -42695,13 +42856,13 @@ fn __action626< { let __start0 = __4.0; let __end0 = __4.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __4, ); let __temp0 = (__start0, __temp0, __end0); - __action136( + __action137( source_code, mode, __0, @@ -42716,7 +42877,7 @@ fn __action626< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action627< +fn __action630< >( source_code: &str, mode: Mode, @@ -42730,14 +42891,14 @@ fn __action627< { let __start0 = __3.2; let __end0 = __4.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action136( + __action137( source_code, mode, __0, @@ -42752,7 +42913,7 @@ fn __action627< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action628< +fn __action631< >( source_code: &str, mode: Mode, @@ -42769,13 +42930,13 @@ fn __action628< { let __start0 = __6.0; let __end0 = __6.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __6, ); let __temp0 = (__start0, __temp0, __end0); - __action137( + __action138( source_code, mode, __0, @@ -42792,7 +42953,7 @@ fn __action628< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action629< +fn __action632< >( source_code: &str, mode: Mode, @@ -42808,14 +42969,14 @@ fn __action629< { let __start0 = __5.2; let __end0 = __6.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action137( + __action138( source_code, mode, __0, @@ -42832,7 +42993,7 @@ fn __action629< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action630< +fn __action633< >( source_code: &str, mode: Mode, @@ -42851,7 +43012,7 @@ fn __action630< { let __start0 = __4.0; let __end0 = __4.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __4, @@ -42876,7 +43037,7 @@ fn __action630< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action631< +fn __action634< >( source_code: &str, mode: Mode, @@ -42894,7 +43055,7 @@ fn __action631< { let __start0 = __3.2; let __end0 = __4.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, @@ -42920,7 +43081,7 @@ fn __action631< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action632< +fn __action635< >( source_code: &str, mode: Mode, @@ -42933,13 +43094,13 @@ fn __action632< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action297( + __action302( source_code, mode, __0, @@ -42952,7 +43113,7 @@ fn __action632< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action633< +fn __action636< >( source_code: &str, mode: Mode, @@ -42964,14 +43125,14 @@ fn __action633< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action297( + __action302( source_code, mode, __0, @@ -42984,7 +43145,7 @@ fn __action633< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action634< +fn __action637< >( source_code: &str, mode: Mode, @@ -42997,13 +43158,13 @@ fn __action634< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action298( + __action303( source_code, mode, __0, @@ -43016,7 +43177,7 @@ fn __action634< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action635< +fn __action638< >( source_code: &str, mode: Mode, @@ -43028,14 +43189,14 @@ fn __action635< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action298( + __action303( source_code, mode, __0, @@ -43048,7 +43209,7 @@ fn __action635< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action636< +fn __action639< >( source_code: &str, mode: Mode, @@ -43060,13 +43221,13 @@ fn __action636< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action299( + __action304( source_code, mode, __0, @@ -43078,7 +43239,7 @@ fn __action636< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action637< +fn __action640< >( source_code: &str, mode: Mode, @@ -43089,14 +43250,14 @@ fn __action637< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action299( + __action304( source_code, mode, __0, @@ -43108,7 +43269,7 @@ fn __action637< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action638< +fn __action641< >( source_code: &str, mode: Mode, @@ -43120,13 +43281,13 @@ fn __action638< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action300( + __action305( source_code, mode, __0, @@ -43138,7 +43299,7 @@ fn __action638< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action639< +fn __action642< >( source_code: &str, mode: Mode, @@ -43149,14 +43310,14 @@ fn __action639< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action300( + __action305( source_code, mode, __0, @@ -43168,7 +43329,7 @@ fn __action639< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action640< +fn __action643< >( source_code: &str, mode: Mode, @@ -43181,13 +43342,13 @@ fn __action640< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action280( + __action285( source_code, mode, __0, @@ -43200,7 +43361,7 @@ fn __action640< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action641< +fn __action644< >( source_code: &str, mode: Mode, @@ -43212,14 +43373,14 @@ fn __action641< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action280( + __action285( source_code, mode, __0, @@ -43232,7 +43393,7 @@ fn __action641< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action642< +fn __action645< >( source_code: &str, mode: Mode, @@ -43245,13 +43406,13 @@ fn __action642< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action281( + __action286( source_code, mode, __0, @@ -43264,7 +43425,7 @@ fn __action642< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action643< +fn __action646< >( source_code: &str, mode: Mode, @@ -43276,14 +43437,14 @@ fn __action643< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action281( + __action286( source_code, mode, __0, @@ -43296,7 +43457,7 @@ fn __action643< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action644< +fn __action647< >( source_code: &str, mode: Mode, @@ -43308,13 +43469,13 @@ fn __action644< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action282( + __action287( source_code, mode, __0, @@ -43326,7 +43487,7 @@ fn __action644< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action645< +fn __action648< >( source_code: &str, mode: Mode, @@ -43337,14 +43498,14 @@ fn __action645< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action282( + __action287( source_code, mode, __0, @@ -43356,7 +43517,7 @@ fn __action645< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action646< +fn __action649< >( source_code: &str, mode: Mode, @@ -43368,13 +43529,13 @@ fn __action646< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action283( + __action288( source_code, mode, __0, @@ -43386,7 +43547,7 @@ fn __action646< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action647< +fn __action650< >( source_code: &str, mode: Mode, @@ -43397,14 +43558,14 @@ fn __action647< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action283( + __action288( source_code, mode, __0, @@ -43416,7 +43577,7 @@ fn __action647< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action648< +fn __action651< >( source_code: &str, mode: Mode, @@ -43432,13 +43593,13 @@ fn __action648< { let __start0 = __5.0; let __end0 = __5.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __5, ); let __temp0 = (__start0, __temp0, __end0); - __action141( + __action142( source_code, mode, __0, @@ -43454,7 +43615,7 @@ fn __action648< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action649< +fn __action652< >( source_code: &str, mode: Mode, @@ -43469,14 +43630,14 @@ fn __action649< { let __start0 = __4.2; let __end0 = __5.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action141( + __action142( source_code, mode, __0, @@ -43492,7 +43653,7 @@ fn __action649< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action650< +fn __action653< >( source_code: &str, mode: Mode, @@ -43506,13 +43667,13 @@ fn __action650< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action142( + __action143( source_code, mode, __0, @@ -43526,7 +43687,7 @@ fn __action650< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action651< +fn __action654< >( source_code: &str, mode: Mode, @@ -43539,14 +43700,14 @@ fn __action651< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action142( + __action143( source_code, mode, __0, @@ -43560,7 +43721,7 @@ fn __action651< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action652< +fn __action655< >( source_code: &str, mode: Mode, @@ -43574,13 +43735,13 @@ fn __action652< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action143( + __action144( source_code, mode, __0, @@ -43594,7 +43755,7 @@ fn __action652< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action653< +fn __action656< >( source_code: &str, mode: Mode, @@ -43607,14 +43768,14 @@ fn __action653< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action143( + __action144( source_code, mode, __0, @@ -43628,7 +43789,7 @@ fn __action653< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action654< +fn __action657< >( source_code: &str, mode: Mode, @@ -43640,7 +43801,7 @@ fn __action654< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __2, @@ -43658,7 +43819,7 @@ fn __action654< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action655< +fn __action658< >( source_code: &str, mode: Mode, @@ -43669,7 +43830,7 @@ fn __action655< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, @@ -43688,7 +43849,7 @@ fn __action655< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action656< +fn __action659< >( source_code: &str, mode: Mode, @@ -43703,7 +43864,7 @@ fn __action656< { let __start0 = __4.0; let __end0 = __4.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __4, @@ -43724,7 +43885,7 @@ fn __action656< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action657< +fn __action660< >( source_code: &str, mode: Mode, @@ -43738,7 +43899,7 @@ fn __action657< { let __start0 = __3.2; let __end0 = __4.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, @@ -43760,7 +43921,7 @@ fn __action657< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action658< +fn __action661< >( source_code: &str, mode: Mode, @@ -43770,13 +43931,13 @@ fn __action658< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action227( + __action230( source_code, mode, __0, @@ -43786,7 +43947,7 @@ fn __action658< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action659< +fn __action662< >( source_code: &str, mode: Mode, @@ -43795,14 +43956,14 @@ fn __action659< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action227( + __action230( source_code, mode, __0, @@ -43812,7 +43973,7 @@ fn __action659< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action660< +fn __action663< >( source_code: &str, mode: Mode, @@ -43824,13 +43985,13 @@ fn __action660< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action208( + __action209( source_code, mode, __0, @@ -43842,7 +44003,7 @@ fn __action660< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action661< +fn __action664< >( source_code: &str, mode: Mode, @@ -43853,14 +44014,14 @@ fn __action661< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action208( + __action209( source_code, mode, __0, @@ -43872,7 +44033,7 @@ fn __action661< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action662< +fn __action665< >( source_code: &str, mode: Mode, @@ -43886,13 +44047,13 @@ fn __action662< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action172( + __action173( source_code, mode, __0, @@ -43906,7 +44067,7 @@ fn __action662< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action663< +fn __action666< >( source_code: &str, mode: Mode, @@ -43919,14 +44080,14 @@ fn __action663< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action172( + __action173( source_code, mode, __0, @@ -43940,7 +44101,7 @@ fn __action663< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action664< +fn __action667< >( source_code: &str, mode: Mode, @@ -43952,13 +44113,13 @@ fn __action664< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action156( + __action157( source_code, mode, __0, @@ -43970,7 +44131,7 @@ fn __action664< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action665< +fn __action668< >( source_code: &str, mode: Mode, @@ -43981,14 +44142,14 @@ fn __action665< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action156( + __action157( source_code, mode, __0, @@ -44000,7 +44161,7 @@ fn __action665< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action666< +fn __action669< >( source_code: &str, mode: Mode, @@ -44014,13 +44175,13 @@ fn __action666< { let __start0 = __4.0; let __end0 = __4.2; - let __temp0 = __action381( + let __temp0 = __action384( source_code, mode, __4, ); let __temp0 = (__start0, __temp0, __end0); - __action157( + __action158( source_code, mode, __0, @@ -44034,7 +44195,7 @@ fn __action666< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action667< +fn __action670< >( source_code: &str, mode: Mode, @@ -44047,14 +44208,14 @@ fn __action667< { let __start0 = __3.2; let __end0 = __4.0; - let __temp0 = __action382( + let __temp0 = __action385( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action157( + __action158( source_code, mode, __0, @@ -44068,7 +44229,7 @@ fn __action667< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action668< +fn __action671< >( source_code: &str, mode: Mode, @@ -44081,7 +44242,7 @@ fn __action668< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action405( + let __temp0 = __action408( source_code, mode, __3, @@ -44100,7 +44261,7 @@ fn __action668< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action669< +fn __action672< >( source_code: &str, mode: Mode, @@ -44112,7 +44273,7 @@ fn __action669< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action406( + let __temp0 = __action409( source_code, mode, &__start0, @@ -44132,7 +44293,7 @@ fn __action669< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action670< +fn __action673< >( source_code: &str, mode: Mode, @@ -44144,7 +44305,7 @@ fn __action670< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action405( + let __temp0 = __action408( source_code, mode, __2, @@ -44162,7 +44323,7 @@ fn __action670< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action671< +fn __action674< >( source_code: &str, mode: Mode, @@ -44173,7 +44334,7 @@ fn __action671< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action406( + let __temp0 = __action409( source_code, mode, &__start0, @@ -44192,7 +44353,7 @@ fn __action671< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action672< +fn __action675< >( source_code: &str, mode: Mode, @@ -44205,7 +44366,7 @@ fn __action672< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action405( + let __temp0 = __action408( source_code, mode, __3, @@ -44224,7 +44385,7 @@ fn __action672< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action673< +fn __action676< >( source_code: &str, mode: Mode, @@ -44236,7 +44397,7 @@ fn __action673< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action406( + let __temp0 = __action409( source_code, mode, &__start0, @@ -44256,7 +44417,7 @@ fn __action673< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action674< +fn __action677< >( source_code: &str, mode: Mode, @@ -44268,7 +44429,7 @@ fn __action674< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action405( + let __temp0 = __action408( source_code, mode, __2, @@ -44286,7 +44447,7 @@ fn __action674< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action675< +fn __action678< >( source_code: &str, mode: Mode, @@ -44297,7 +44458,7 @@ fn __action675< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action406( + let __temp0 = __action409( source_code, mode, &__start0, @@ -44316,7 +44477,7 @@ fn __action675< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action676< +fn __action679< >( source_code: &str, mode: Mode, @@ -44332,13 +44493,13 @@ fn __action676< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action268( + let __temp0 = __action271( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action218( + __action221( source_code, mode, __0, @@ -44354,7 +44515,7 @@ fn __action676< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action677< +fn __action680< >( source_code: &str, mode: Mode, @@ -44369,14 +44530,14 @@ fn __action677< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action269( + let __temp0 = __action272( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action218( + __action221( source_code, mode, __0, @@ -44392,7 +44553,7 @@ fn __action677< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action678< +fn __action681< >( source_code: &str, mode: Mode, @@ -44409,13 +44570,13 @@ fn __action678< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action332( + let __temp0 = __action337( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action147( + __action148( source_code, mode, __0, @@ -44432,7 +44593,7 @@ fn __action678< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action679< +fn __action682< >( source_code: &str, mode: Mode, @@ -44448,14 +44609,14 @@ fn __action679< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action333( + let __temp0 = __action338( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action147( + __action148( source_code, mode, __0, @@ -44472,7 +44633,7 @@ fn __action679< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action680< +fn __action683< >( source_code: &str, mode: Mode, @@ -44490,13 +44651,13 @@ fn __action680< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action332( + let __temp0 = __action337( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action162( + __action163( source_code, mode, __0, @@ -44514,7 +44675,7 @@ fn __action680< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action681< +fn __action684< >( source_code: &str, mode: Mode, @@ -44531,14 +44692,14 @@ fn __action681< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action333( + let __temp0 = __action338( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action162( + __action163( source_code, mode, __0, @@ -44556,7 +44717,7 @@ fn __action681< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action682< +fn __action685< >( source_code: &str, mode: Mode, @@ -44572,13 +44733,13 @@ fn __action682< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action332( + let __temp0 = __action337( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action235( + __action238( source_code, mode, __0, @@ -44594,7 +44755,7 @@ fn __action682< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action683< +fn __action686< >( source_code: &str, mode: Mode, @@ -44609,14 +44770,14 @@ fn __action683< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action333( + let __temp0 = __action338( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action235( + __action238( source_code, mode, __0, @@ -44632,7 +44793,7 @@ fn __action683< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action684< +fn __action687< >( source_code: &str, mode: Mode, @@ -44646,13 +44807,13 @@ fn __action684< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action332( + let __temp0 = __action337( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action155( + __action156( source_code, mode, __0, @@ -44666,7 +44827,7 @@ fn __action684< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action685< +fn __action688< >( source_code: &str, mode: Mode, @@ -44679,14 +44840,14 @@ fn __action685< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action333( + let __temp0 = __action338( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action155( + __action156( source_code, mode, __0, @@ -44700,7 +44861,7 @@ fn __action685< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action686< +fn __action689< >( source_code: &str, mode: Mode, @@ -44710,14 +44871,14 @@ fn __action686< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action437( + let __temp0 = __action440( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action489( + __action492( source_code, mode, __temp0, @@ -44726,7 +44887,7 @@ fn __action686< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action687< +fn __action690< >( source_code: &str, mode: Mode, @@ -44740,14 +44901,14 @@ fn __action687< { let __start0 = __2.0; let __end0 = __3.2; - let __temp0 = __action437( + let __temp0 = __action440( source_code, mode, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action634( + __action637( source_code, mode, __0, @@ -44760,7 +44921,7 @@ fn __action687< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action688< +fn __action691< >( source_code: &str, mode: Mode, @@ -44773,14 +44934,14 @@ fn __action688< { let __start0 = __2.0; let __end0 = __3.2; - let __temp0 = __action437( + let __temp0 = __action440( source_code, mode, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action635( + __action638( source_code, mode, __0, @@ -44792,7 +44953,7 @@ fn __action688< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action689< +fn __action692< >( source_code: &str, mode: Mode, @@ -44806,14 +44967,14 @@ fn __action689< { let __start0 = __4.0; let __end0 = __5.2; - let __temp0 = __action686( + let __temp0 = __action689( source_code, mode, __4, __5, ); let __temp0 = (__start0, __temp0, __end0); - __action442( + __action445( source_code, mode, __0, @@ -44826,7 +44987,7 @@ fn __action689< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action690< +fn __action693< >( source_code: &str, mode: Mode, @@ -44838,14 +44999,14 @@ fn __action690< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action490( + let __temp0 = __action493( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action442( + __action445( source_code, mode, __0, @@ -44858,7 +45019,7 @@ fn __action690< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action691< +fn __action694< >( source_code: &str, mode: Mode, @@ -44868,14 +45029,14 @@ fn __action691< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action445( + let __temp0 = __action448( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action478( + __action481( source_code, mode, __temp0, @@ -44884,7 +45045,7 @@ fn __action691< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action692< +fn __action695< >( source_code: &str, mode: Mode, @@ -44898,14 +45059,14 @@ fn __action692< { let __start0 = __2.0; let __end0 = __3.2; - let __temp0 = __action445( + let __temp0 = __action448( source_code, mode, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action642( + __action645( source_code, mode, __0, @@ -44918,7 +45079,7 @@ fn __action692< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action693< +fn __action696< >( source_code: &str, mode: Mode, @@ -44931,14 +45092,14 @@ fn __action693< { let __start0 = __2.0; let __end0 = __3.2; - let __temp0 = __action445( + let __temp0 = __action448( source_code, mode, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action643( + __action646( source_code, mode, __0, @@ -44950,7 +45111,7 @@ fn __action693< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action694< +fn __action697< >( source_code: &str, mode: Mode, @@ -44964,14 +45125,14 @@ fn __action694< { let __start0 = __4.0; let __end0 = __5.2; - let __temp0 = __action691( + let __temp0 = __action694( source_code, mode, __4, __5, ); let __temp0 = (__start0, __temp0, __end0); - __action450( + __action453( source_code, mode, __0, @@ -44984,7 +45145,7 @@ fn __action694< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action695< +fn __action698< >( source_code: &str, mode: Mode, @@ -44996,14 +45157,14 @@ fn __action695< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action479( + let __temp0 = __action482( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action450( + __action453( source_code, mode, __0, @@ -45016,7 +45177,7 @@ fn __action695< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action696< +fn __action699< >( source_code: &str, mode: Mode, @@ -45026,14 +45187,14 @@ fn __action696< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action493( + let __temp0 = __action496( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action508( + __action511( source_code, mode, __temp0, @@ -45042,7 +45203,7 @@ fn __action696< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action697< +fn __action700< >( source_code: &str, mode: Mode, @@ -45053,14 +45214,14 @@ fn __action697< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action493( + let __temp0 = __action496( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action509( + __action512( source_code, mode, __0, @@ -45070,7 +45231,7 @@ fn __action697< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action698< +fn __action701< >( source_code: &str, mode: Mode, @@ -45081,14 +45242,14 @@ fn __action698< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action491( + let __temp0 = __action494( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action444( + __action447( source_code, mode, __0, @@ -45100,7 +45261,7 @@ fn __action698< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action699< +fn __action702< >( source_code: &str, mode: Mode, @@ -45112,13 +45273,13 @@ fn __action699< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action492( + let __temp0 = __action495( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action444( + __action447( source_code, mode, __0, @@ -45130,7 +45291,7 @@ fn __action699< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action700< +fn __action703< >( source_code: &str, mode: Mode, @@ -45143,14 +45304,14 @@ fn __action700< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action491( + let __temp0 = __action494( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action689( + __action692( source_code, mode, __0, @@ -45164,7 +45325,7 @@ fn __action700< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action701< +fn __action704< >( source_code: &str, mode: Mode, @@ -45178,13 +45339,13 @@ fn __action701< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action492( + let __temp0 = __action495( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action689( + __action692( source_code, mode, __0, @@ -45198,7 +45359,7 @@ fn __action701< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action702< +fn __action705< >( source_code: &str, mode: Mode, @@ -45209,14 +45370,14 @@ fn __action702< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action491( + let __temp0 = __action494( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action690( + __action693( source_code, mode, __0, @@ -45228,7 +45389,7 @@ fn __action702< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action703< +fn __action706< >( source_code: &str, mode: Mode, @@ -45240,13 +45401,13 @@ fn __action703< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action492( + let __temp0 = __action495( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action690( + __action693( source_code, mode, __0, @@ -45258,7 +45419,7 @@ fn __action703< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action704< +fn __action707< >( source_code: &str, mode: Mode, @@ -45268,14 +45429,14 @@ fn __action704< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action482( + let __temp0 = __action485( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action510( + __action513( source_code, mode, __temp0, @@ -45284,7 +45445,7 @@ fn __action704< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action705< +fn __action708< >( source_code: &str, mode: Mode, @@ -45295,14 +45456,14 @@ fn __action705< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action482( + let __temp0 = __action485( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action511( + __action514( source_code, mode, __0, @@ -45312,7 +45473,7 @@ fn __action705< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action706< +fn __action709< >( source_code: &str, mode: Mode, @@ -45323,14 +45484,14 @@ fn __action706< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action480( + let __temp0 = __action483( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action452( + __action455( source_code, mode, __0, @@ -45342,7 +45503,7 @@ fn __action706< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action707< +fn __action710< >( source_code: &str, mode: Mode, @@ -45354,13 +45515,13 @@ fn __action707< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action481( + let __temp0 = __action484( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action452( + __action455( source_code, mode, __0, @@ -45372,7 +45533,7 @@ fn __action707< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action708< +fn __action711< >( source_code: &str, mode: Mode, @@ -45385,14 +45546,14 @@ fn __action708< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action480( + let __temp0 = __action483( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action694( + __action697( source_code, mode, __0, @@ -45406,7 +45567,7 @@ fn __action708< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action709< +fn __action712< >( source_code: &str, mode: Mode, @@ -45420,13 +45581,13 @@ fn __action709< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action481( + let __temp0 = __action484( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action694( + __action697( source_code, mode, __0, @@ -45440,7 +45601,7 @@ fn __action709< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action710< +fn __action713< >( source_code: &str, mode: Mode, @@ -45451,14 +45612,14 @@ fn __action710< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action480( + let __temp0 = __action483( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action695( + __action698( source_code, mode, __0, @@ -45470,7 +45631,7 @@ fn __action710< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action711< +fn __action714< >( source_code: &str, mode: Mode, @@ -45482,13 +45643,13 @@ fn __action711< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action481( + let __temp0 = __action484( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action695( + __action698( source_code, mode, __0, @@ -45500,7 +45661,7 @@ fn __action711< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action712< +fn __action715< >( source_code: &str, mode: Mode, @@ -45513,13 +45674,13 @@ fn __action712< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action496( + let __temp0 = __action499( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action700( + __action703( source_code, mode, __0, @@ -45532,7 +45693,7 @@ fn __action712< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action713< +fn __action716< >( source_code: &str, mode: Mode, @@ -45544,14 +45705,14 @@ fn __action713< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action497( + let __temp0 = __action500( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action700( + __action703( source_code, mode, __0, @@ -45564,7 +45725,7 @@ fn __action713< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action714< +fn __action717< >( source_code: &str, mode: Mode, @@ -45578,13 +45739,13 @@ fn __action714< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action496( + let __temp0 = __action499( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action701( + __action704( source_code, mode, __0, @@ -45598,7 +45759,7 @@ fn __action714< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action715< +fn __action718< >( source_code: &str, mode: Mode, @@ -45611,14 +45772,14 @@ fn __action715< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action497( + let __temp0 = __action500( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action701( + __action704( source_code, mode, __0, @@ -45632,7 +45793,7 @@ fn __action715< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action716< +fn __action719< >( source_code: &str, mode: Mode, @@ -45643,13 +45804,13 @@ fn __action716< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action496( + let __temp0 = __action499( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action702( + __action705( source_code, mode, __0, @@ -45660,7 +45821,7 @@ fn __action716< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action717< +fn __action720< >( source_code: &str, mode: Mode, @@ -45670,14 +45831,14 @@ fn __action717< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action497( + let __temp0 = __action500( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action702( + __action705( source_code, mode, __0, @@ -45688,7 +45849,7 @@ fn __action717< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action718< +fn __action721< >( source_code: &str, mode: Mode, @@ -45700,13 +45861,13 @@ fn __action718< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action496( + let __temp0 = __action499( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action703( + __action706( source_code, mode, __0, @@ -45718,7 +45879,7 @@ fn __action718< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action719< +fn __action722< >( source_code: &str, mode: Mode, @@ -45729,14 +45890,14 @@ fn __action719< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action497( + let __temp0 = __action500( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action703( + __action706( source_code, mode, __0, @@ -45748,7 +45909,7 @@ fn __action719< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action720< +fn __action723< >( source_code: &str, mode: Mode, @@ -45760,14 +45921,14 @@ fn __action720< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action342( + __action347( source_code, mode, __temp0, @@ -45780,7 +45941,7 @@ fn __action720< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action721< +fn __action724< >( source_code: &str, mode: Mode, @@ -45791,14 +45952,14 @@ fn __action721< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action339( + __action344( source_code, mode, __temp0, @@ -45810,7 +45971,7 @@ fn __action721< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action722< +fn __action725< >( source_code: &str, mode: Mode, @@ -45822,7 +45983,7 @@ fn __action722< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -45842,7 +46003,7 @@ fn __action722< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action723< +fn __action726< >( source_code: &str, mode: Mode, @@ -45854,14 +46015,14 @@ fn __action723< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action502( + __action505( source_code, mode, __temp0, @@ -45874,7 +46035,7 @@ fn __action723< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action724< +fn __action727< >( source_code: &str, mode: Mode, @@ -45886,14 +46047,14 @@ fn __action724< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action533( + __action536( source_code, mode, __temp0, @@ -45906,7 +46067,7 @@ fn __action724< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action725< +fn __action728< >( source_code: &str, mode: Mode, @@ -45917,14 +46078,14 @@ fn __action725< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action460( + __action463( source_code, mode, __temp0, @@ -45936,7 +46097,7 @@ fn __action725< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action726< +fn __action729< >( source_code: &str, mode: Mode, @@ -45947,14 +46108,14 @@ fn __action726< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action506( + __action509( source_code, mode, __temp0, @@ -45966,7 +46127,7 @@ fn __action726< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action727< +fn __action730< >( source_code: &str, mode: Mode, @@ -45978,14 +46139,14 @@ fn __action727< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action238( + __action241( source_code, mode, __temp0, @@ -45998,7 +46159,7 @@ fn __action727< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action728< +fn __action731< >( source_code: &str, mode: Mode, @@ -46010,14 +46171,14 @@ fn __action728< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action519( + __action522( source_code, mode, __temp0, @@ -46030,7 +46191,7 @@ fn __action728< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action729< +fn __action732< >( source_code: &str, mode: Mode, @@ -46042,14 +46203,14 @@ fn __action729< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action543( + __action546( source_code, mode, __temp0, @@ -46062,7 +46223,7 @@ fn __action729< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action730< +fn __action733< >( source_code: &str, mode: Mode, @@ -46074,7 +46235,7 @@ fn __action730< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -46094,7 +46255,7 @@ fn __action730< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action731< +fn __action734< >( source_code: &str, mode: Mode, @@ -46106,7 +46267,7 @@ fn __action731< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -46126,35 +46287,7 @@ fn __action731< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action732< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), - __1: (TextSize, TextSize, TextSize), -) -> Result> -{ - let __start0 = __0.0; - let __end0 = __0.0; - let __temp0 = __action414( - source_code, - mode, - &__start0, - &__end0, - ); - let __temp0 = (__start0, __temp0, __end0); - __action545( - source_code, - mode, - __temp0, - __0, - __1, - ) -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action733< +fn __action735< >( source_code: &str, mode: Mode, @@ -46164,14 +46297,14 @@ fn __action733< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action546( + __action549( source_code, mode, __temp0, @@ -46182,7 +46315,7 @@ fn __action733< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action734< +fn __action736< >( source_code: &str, mode: Mode, @@ -46192,14 +46325,14 @@ fn __action734< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action547( + __action550( source_code, mode, __temp0, @@ -46210,7 +46343,7 @@ fn __action734< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action735< +fn __action737< >( source_code: &str, mode: Mode, @@ -46222,14 +46355,14 @@ fn __action735< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action548( + __action551( source_code, mode, __temp0, @@ -46242,7 +46375,7 @@ fn __action735< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action736< +fn __action738< >( source_code: &str, mode: Mode, @@ -46255,14 +46388,14 @@ fn __action736< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action549( + __action552( source_code, mode, __temp0, @@ -46276,7 +46409,7 @@ fn __action736< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action737< +fn __action739< >( source_code: &str, mode: Mode, @@ -46289,14 +46422,14 @@ fn __action737< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action606( + __action609( source_code, mode, __temp0, @@ -46310,7 +46443,7 @@ fn __action737< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action738< +fn __action740< >( source_code: &str, mode: Mode, @@ -46322,14 +46455,14 @@ fn __action738< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action607( + __action610( source_code, mode, __temp0, @@ -46342,7 +46475,7 @@ fn __action738< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action739< +fn __action741< >( source_code: &str, mode: Mode, @@ -46357,14 +46490,14 @@ fn __action739< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action608( + __action611( source_code, mode, __temp0, @@ -46380,7 +46513,7 @@ fn __action739< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action740< +fn __action742< >( source_code: &str, mode: Mode, @@ -46394,14 +46527,14 @@ fn __action740< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action609( + __action612( source_code, mode, __temp0, @@ -46416,7 +46549,7 @@ fn __action740< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action741< +fn __action743< >( source_code: &str, mode: Mode, @@ -46427,14 +46560,14 @@ fn __action741< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action552( + __action555( source_code, mode, __temp0, @@ -46446,7 +46579,7 @@ fn __action741< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action742< +fn __action744< >( source_code: &str, mode: Mode, @@ -46458,14 +46591,14 @@ fn __action742< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action553( + __action556( source_code, mode, __temp0, @@ -46478,7 +46611,7 @@ fn __action742< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action743< +fn __action745< >( source_code: &str, mode: Mode, @@ -46491,14 +46624,14 @@ fn __action743< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action554( + __action557( source_code, mode, __temp0, @@ -46512,7 +46645,7 @@ fn __action743< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action744< +fn __action746< >( source_code: &str, mode: Mode, @@ -46525,14 +46658,14 @@ fn __action744< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action555( + __action558( source_code, mode, __0, @@ -46546,7 +46679,7 @@ fn __action744< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action745< +fn __action747< >( source_code: &str, mode: Mode, @@ -46558,14 +46691,14 @@ fn __action745< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action556( + __action559( source_code, mode, __temp0, @@ -46578,7 +46711,7 @@ fn __action745< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action746< +fn __action748< >( source_code: &str, mode: Mode, @@ -46591,14 +46724,14 @@ fn __action746< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action557( + __action560( source_code, mode, __temp0, @@ -46612,7 +46745,7 @@ fn __action746< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action747< +fn __action749< >( source_code: &str, mode: Mode, @@ -46624,14 +46757,14 @@ fn __action747< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action558( + __action561( source_code, mode, __temp0, @@ -46644,7 +46777,7 @@ fn __action747< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action748< +fn __action750< >( source_code: &str, mode: Mode, @@ -46657,14 +46790,14 @@ fn __action748< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action559( + __action562( source_code, mode, __temp0, @@ -46678,7 +46811,7 @@ fn __action748< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action749< +fn __action751< >( source_code: &str, mode: Mode, @@ -46688,14 +46821,14 @@ fn __action749< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action560( + __action563( source_code, mode, __temp0, @@ -46706,7 +46839,7 @@ fn __action749< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action750< +fn __action752< >( source_code: &str, mode: Mode, @@ -46716,14 +46849,14 @@ fn __action750< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action561( + __action564( source_code, mode, __temp0, @@ -46734,7 +46867,7 @@ fn __action750< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action751< +fn __action753< >( source_code: &str, mode: Mode, @@ -46744,14 +46877,14 @@ fn __action751< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action562( + __action565( source_code, mode, __temp0, @@ -46762,7 +46895,7 @@ fn __action751< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action752< +fn __action754< >( source_code: &str, mode: Mode, @@ -46772,14 +46905,14 @@ fn __action752< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action563( + __action566( source_code, mode, __temp0, @@ -46790,35 +46923,7 @@ fn __action752< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action753< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), - __1: (TextSize, TextSize, TextSize), -) -> Result> -{ - let __start0 = __0.0; - let __end0 = __0.0; - let __temp0 = __action414( - source_code, - mode, - &__start0, - &__end0, - ); - let __temp0 = (__start0, __temp0, __end0); - __action588( - source_code, - mode, - __temp0, - __0, - __1, - ) -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action754< +fn __action755< >( source_code: &str, mode: Mode, @@ -46828,14 +46933,14 @@ fn __action754< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action589( + __action592( source_code, mode, __temp0, @@ -46846,7 +46951,7 @@ fn __action754< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action755< +fn __action756< >( source_code: &str, mode: Mode, @@ -46856,14 +46961,14 @@ fn __action755< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action590( + __action593( source_code, mode, __temp0, @@ -46874,7 +46979,7 @@ fn __action755< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action756< +fn __action757< >( source_code: &str, mode: Mode, @@ -46886,14 +46991,14 @@ fn __action756< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action591( + __action594( source_code, mode, __temp0, @@ -46906,7 +47011,7 @@ fn __action756< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action757< +fn __action758< >( source_code: &str, mode: Mode, @@ -46919,14 +47024,14 @@ fn __action757< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action592( + __action595( source_code, mode, __temp0, @@ -46940,7 +47045,7 @@ fn __action757< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action758< +fn __action759< >( source_code: &str, mode: Mode, @@ -46955,14 +47060,14 @@ fn __action758< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action610( + __action613( source_code, mode, __temp0, @@ -46978,7 +47083,7 @@ fn __action758< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action759< +fn __action760< >( source_code: &str, mode: Mode, @@ -46992,14 +47097,14 @@ fn __action759< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action611( + __action614( source_code, mode, __temp0, @@ -47014,7 +47119,7 @@ fn __action759< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action760< +fn __action761< >( source_code: &str, mode: Mode, @@ -47025,14 +47130,14 @@ fn __action760< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action594( + __action597( source_code, mode, __temp0, @@ -47044,7 +47149,7 @@ fn __action760< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action761< +fn __action762< >( source_code: &str, mode: Mode, @@ -47056,14 +47161,14 @@ fn __action761< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action595( + __action598( source_code, mode, __temp0, @@ -47076,7 +47181,7 @@ fn __action761< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action762< +fn __action763< >( source_code: &str, mode: Mode, @@ -47089,14 +47194,14 @@ fn __action762< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action596( + __action599( source_code, mode, __temp0, @@ -47110,7 +47215,7 @@ fn __action762< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action763< +fn __action764< >( source_code: &str, mode: Mode, @@ -47123,14 +47228,14 @@ fn __action763< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action597( + __action600( source_code, mode, __0, @@ -47144,7 +47249,7 @@ fn __action763< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action764< +fn __action765< >( source_code: &str, mode: Mode, @@ -47156,14 +47261,14 @@ fn __action764< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action598( + __action601( source_code, mode, __temp0, @@ -47176,7 +47281,7 @@ fn __action764< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action765< +fn __action766< >( source_code: &str, mode: Mode, @@ -47189,14 +47294,14 @@ fn __action765< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action599( + __action602( source_code, mode, __temp0, @@ -47210,7 +47315,7 @@ fn __action765< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action766< +fn __action767< >( source_code: &str, mode: Mode, @@ -47222,14 +47327,14 @@ fn __action766< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action600( + __action603( source_code, mode, __temp0, @@ -47242,7 +47347,7 @@ fn __action766< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action767< +fn __action768< >( source_code: &str, mode: Mode, @@ -47255,14 +47360,14 @@ fn __action767< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action601( + __action604( source_code, mode, __temp0, @@ -47276,7 +47381,7 @@ fn __action767< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action768< +fn __action769< >( source_code: &str, mode: Mode, @@ -47286,14 +47391,14 @@ fn __action768< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action602( + __action605( source_code, mode, __temp0, @@ -47304,7 +47409,7 @@ fn __action768< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action769< +fn __action770< >( source_code: &str, mode: Mode, @@ -47314,14 +47419,14 @@ fn __action769< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action603( + __action606( source_code, mode, __temp0, @@ -47332,7 +47437,7 @@ fn __action769< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action770< +fn __action771< >( source_code: &str, mode: Mode, @@ -47342,14 +47447,14 @@ fn __action770< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action604( + __action607( source_code, mode, __temp0, @@ -47360,7 +47465,7 @@ fn __action770< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action771< +fn __action772< >( source_code: &str, mode: Mode, @@ -47370,14 +47475,14 @@ fn __action771< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action605( + __action608( source_code, mode, __temp0, @@ -47388,7 +47493,7 @@ fn __action771< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action772< +fn __action773< >( source_code: &str, mode: Mode, @@ -47399,14 +47504,14 @@ fn __action772< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action538( + __action541( source_code, mode, __temp0, @@ -47418,7 +47523,7 @@ fn __action772< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action773< +fn __action774< >( source_code: &str, mode: Mode, @@ -47431,14 +47536,14 @@ fn __action773< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action539( + __action542( source_code, mode, __temp0, @@ -47452,7 +47557,7 @@ fn __action773< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action774< +fn __action775< >( source_code: &str, mode: Mode, @@ -47464,14 +47569,14 @@ fn __action774< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action540( + __action543( source_code, mode, __temp0, @@ -47484,7 +47589,7 @@ fn __action774< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action775< +fn __action776< >( source_code: &str, mode: Mode, @@ -47495,14 +47600,14 @@ fn __action775< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action585( + __action588( source_code, mode, __temp0, @@ -47514,7 +47619,7 @@ fn __action775< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action776< +fn __action777< >( source_code: &str, mode: Mode, @@ -47527,14 +47632,14 @@ fn __action776< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action586( + __action589( source_code, mode, __temp0, @@ -47548,7 +47653,7 @@ fn __action776< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action777< +fn __action778< >( source_code: &str, mode: Mode, @@ -47560,14 +47665,14 @@ fn __action777< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action587( + __action590( source_code, mode, __temp0, @@ -47580,7 +47685,7 @@ fn __action777< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action778< +fn __action779< >( source_code: &str, mode: Mode, @@ -47591,14 +47696,14 @@ fn __action778< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action535( + __action538( source_code, mode, __temp0, @@ -47610,7 +47715,7 @@ fn __action778< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action779< +fn __action780< >( source_code: &str, mode: Mode, @@ -47621,14 +47726,14 @@ fn __action779< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action582( + __action585( source_code, mode, __temp0, @@ -47640,7 +47745,7 @@ fn __action779< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action780< +fn __action781< >( source_code: &str, mode: Mode, @@ -47650,14 +47755,14 @@ fn __action780< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action121( + __action122( source_code, mode, __temp0, @@ -47668,7 +47773,7 @@ fn __action780< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action781< +fn __action782< >( source_code: &str, mode: Mode, @@ -47683,14 +47788,14 @@ fn __action781< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action171( + __action172( source_code, mode, __temp0, @@ -47706,7 +47811,7 @@ fn __action781< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action782< +fn __action783< >( source_code: &str, mode: Mode, @@ -47717,14 +47822,14 @@ fn __action782< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action139( + __action140( source_code, mode, __temp0, @@ -47736,7 +47841,7 @@ fn __action782< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action783< +fn __action784< >( source_code: &str, mode: Mode, @@ -47747,14 +47852,14 @@ fn __action783< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action140( + __action141( source_code, mode, __temp0, @@ -47766,7 +47871,7 @@ fn __action783< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action784< +fn __action785< >( source_code: &str, mode: Mode, @@ -47777,14 +47882,14 @@ fn __action784< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action512( + __action515( source_code, mode, __temp0, @@ -47796,7 +47901,7 @@ fn __action784< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action785< +fn __action786< >( source_code: &str, mode: Mode, @@ -47807,14 +47912,14 @@ fn __action785< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action523( + __action526( source_code, mode, __temp0, @@ -47826,7 +47931,7 @@ fn __action785< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action786< +fn __action787< >( source_code: &str, mode: Mode, @@ -47838,14 +47943,14 @@ fn __action786< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action176( + __action177( source_code, mode, __temp0, @@ -47858,7 +47963,7 @@ fn __action786< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action787< +fn __action788< >( source_code: &str, mode: Mode, @@ -47869,7 +47974,7 @@ fn __action787< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -47888,7 +47993,7 @@ fn __action787< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action788< +fn __action789< >( source_code: &str, mode: Mode, @@ -47898,7 +48003,7 @@ fn __action788< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -47916,7 +48021,7 @@ fn __action788< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action789< +fn __action790< >( source_code: &str, mode: Mode, @@ -47927,7 +48032,7 @@ fn __action789< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -47946,7 +48051,7 @@ fn __action789< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action790< +fn __action791< >( source_code: &str, mode: Mode, @@ -47957,14 +48062,14 @@ fn __action790< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action170( + __action171( source_code, mode, __temp0, @@ -47976,7 +48081,7 @@ fn __action790< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action791< +fn __action792< >( source_code: &str, mode: Mode, @@ -47988,14 +48093,14 @@ fn __action791< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action153( + __action154( source_code, mode, __temp0, @@ -48008,7 +48113,7 @@ fn __action791< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action792< +fn __action793< >( source_code: &str, mode: Mode, @@ -48020,47 +48125,14 @@ fn __action792< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action154( - source_code, - mode, - __temp0, - __0, - __1, - __2, - __3, - ) -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action793< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), - __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::Suite, TextSize), -) -> ast::ExceptHandler -{ - let __start0 = __0.0; - let __end0 = __0.0; - let __temp0 = __action414( - source_code, - mode, - &__start0, - &__end0, - ); - let __temp0 = (__start0, __temp0, __end0); - __action151( + __action155( source_code, mode, __temp0, @@ -48068,7 +48140,6 @@ fn __action793< __1, __2, __3, - __4, ) } @@ -48080,14 +48151,14 @@ fn __action794< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, (ast::ParenthesizedExpr, ast::Identifier), TextSize), + __2: (TextSize, ast::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, ast::Suite, TextSize), ) -> ast::ExceptHandler { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -48109,6 +48180,40 @@ fn __action794< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] fn __action795< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, token::Tok, TextSize), + __1: (TextSize, token::Tok, TextSize), + __2: (TextSize, (ast::ParenthesizedExpr, ast::Identifier), TextSize), + __3: (TextSize, token::Tok, TextSize), + __4: (TextSize, ast::Suite, TextSize), +) -> ast::ExceptHandler +{ + let __start0 = __0.0; + let __end0 = __0.0; + let __temp0 = __action417( + source_code, + mode, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action153( + source_code, + mode, + __temp0, + __0, + __1, + __2, + __3, + __4, + ) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action796< >( source_code: &str, mode: Mode, @@ -48120,14 +48225,14 @@ fn __action795< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action371( + __action374( source_code, mode, __temp0, @@ -48140,7 +48245,7 @@ fn __action795< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action796< +fn __action797< >( source_code: &str, mode: Mode, @@ -48152,14 +48257,14 @@ fn __action796< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action525( + __action528( source_code, mode, __temp0, @@ -48172,7 +48277,7 @@ fn __action796< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action797< +fn __action798< >( source_code: &str, mode: Mode, @@ -48183,7 +48288,7 @@ fn __action797< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -48202,7 +48307,7 @@ fn __action797< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action798< +fn __action799< >( source_code: &str, mode: Mode, @@ -48214,7 +48319,7 @@ fn __action798< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -48234,7 +48339,7 @@ fn __action798< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action799< +fn __action800< >( source_code: &str, mode: Mode, @@ -48247,7 +48352,7 @@ fn __action799< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -48268,7 +48373,7 @@ fn __action799< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action800< +fn __action801< >( source_code: &str, mode: Mode, @@ -48280,21 +48385,21 @@ fn __action800< let __end0 = __0.0; let __start1 = __0.2; let __end1 = __1.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - let __temp1 = __action414( + let __temp1 = __action417( source_code, mode, &__start1, &__end1, ); let __temp1 = (__start1, __temp1, __end1); - __action221( + __action224( source_code, mode, __temp0, @@ -48306,7 +48411,7 @@ fn __action800< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action801< +fn __action802< >( source_code: &str, mode: Mode, @@ -48318,14 +48423,14 @@ fn __action801< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action215( + __action218( source_code, mode, __temp0, @@ -48338,7 +48443,7 @@ fn __action801< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action802< +fn __action803< >( source_code: &str, mode: Mode, @@ -48348,14 +48453,14 @@ fn __action802< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action220( + __action223( source_code, mode, __temp0, @@ -48366,33 +48471,35 @@ fn __action802< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action803< +fn __action804< >( source_code: &str, mode: Mode, __0: (TextSize, (String, bool), TextSize), + __1: (TextSize, TextSize, TextSize), ) -> Result> { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action217( + __action220( source_code, mode, __temp0, __0, + __1, ) } #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action804< +fn __action805< >( source_code: &str, mode: Mode, @@ -48407,14 +48514,14 @@ fn __action804< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action676( + __action679( source_code, mode, __temp0, @@ -48430,7 +48537,7 @@ fn __action804< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action805< +fn __action806< >( source_code: &str, mode: Mode, @@ -48444,14 +48551,14 @@ fn __action805< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action677( + __action680( source_code, mode, __temp0, @@ -48466,7 +48573,7 @@ fn __action805< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action806< +fn __action807< >( source_code: &str, mode: Mode, @@ -48477,14 +48584,14 @@ fn __action806< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action527( + __action530( source_code, mode, __temp0, @@ -48496,7 +48603,7 @@ fn __action806< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action807< +fn __action808< >( source_code: &str, mode: Mode, @@ -48507,14 +48614,14 @@ fn __action807< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action576( + __action579( source_code, mode, __temp0, @@ -48526,7 +48633,7 @@ fn __action807< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action808< +fn __action809< >( source_code: &str, mode: Mode, @@ -48536,7 +48643,7 @@ fn __action808< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -48554,7 +48661,7 @@ fn __action808< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action809< +fn __action810< >( source_code: &str, mode: Mode, @@ -48564,7 +48671,7 @@ fn __action809< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -48582,7 +48689,7 @@ fn __action809< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action810< +fn __action811< >( source_code: &str, mode: Mode, @@ -48593,7 +48700,7 @@ fn __action810< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -48612,7 +48719,7 @@ fn __action810< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action811< +fn __action812< >( source_code: &str, mode: Mode, @@ -48622,7 +48729,7 @@ fn __action811< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -48640,7 +48747,7 @@ fn __action811< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action812< +fn __action813< >( source_code: &str, mode: Mode, @@ -48656,14 +48763,14 @@ fn __action812< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action678( + __action681( source_code, mode, __temp0, @@ -48680,7 +48787,7 @@ fn __action812< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action813< +fn __action814< >( source_code: &str, mode: Mode, @@ -48695,14 +48802,14 @@ fn __action813< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action679( + __action682( source_code, mode, __temp0, @@ -48718,7 +48825,7 @@ fn __action813< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action814< +fn __action815< >( source_code: &str, mode: Mode, @@ -48735,14 +48842,14 @@ fn __action814< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action680( + __action683( source_code, mode, __temp0, @@ -48760,7 +48867,7 @@ fn __action814< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action815< +fn __action816< >( source_code: &str, mode: Mode, @@ -48776,14 +48883,14 @@ fn __action815< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action681( + __action684( source_code, mode, __temp0, @@ -48800,7 +48907,7 @@ fn __action815< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action816< +fn __action817< >( source_code: &str, mode: Mode, @@ -48811,14 +48918,14 @@ fn __action816< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action239( + __action242( source_code, mode, __temp0, @@ -48830,7 +48937,7 @@ fn __action816< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action817< +fn __action818< >( source_code: &str, mode: Mode, @@ -48842,14 +48949,14 @@ fn __action817< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action240( + __action243( source_code, mode, __temp0, @@ -48862,7 +48969,7 @@ fn __action817< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action818< +fn __action819< >( source_code: &str, mode: Mode, @@ -48873,14 +48980,14 @@ fn __action818< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action241( + __action244( source_code, mode, __temp0, @@ -48892,7 +48999,7 @@ fn __action818< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action819< +fn __action820< >( source_code: &str, mode: Mode, @@ -48903,14 +49010,14 @@ fn __action819< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action242( + __action245( source_code, mode, __temp0, @@ -48922,7 +49029,7 @@ fn __action819< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action820< +fn __action821< >( source_code: &str, mode: Mode, @@ -48933,14 +49040,14 @@ fn __action820< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action616( + __action619( source_code, mode, __temp0, @@ -48952,7 +49059,7 @@ fn __action820< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action821< +fn __action822< >( source_code: &str, mode: Mode, @@ -48962,14 +49069,14 @@ fn __action821< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action617( + __action620( source_code, mode, __temp0, @@ -48980,7 +49087,7 @@ fn __action821< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action822< +fn __action823< >( source_code: &str, mode: Mode, @@ -48991,14 +49098,14 @@ fn __action822< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action618( + __action621( source_code, mode, __temp0, @@ -49010,7 +49117,7 @@ fn __action822< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action823< +fn __action824< >( source_code: &str, mode: Mode, @@ -49020,14 +49127,14 @@ fn __action823< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action619( + __action622( source_code, mode, __temp0, @@ -49038,7 +49145,7 @@ fn __action823< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action824< +fn __action825< >( source_code: &str, mode: Mode, @@ -49049,7 +49156,7 @@ fn __action824< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -49068,7 +49175,7 @@ fn __action824< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action825< +fn __action826< >( source_code: &str, mode: Mode, @@ -49078,14 +49185,14 @@ fn __action825< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action246( + __action249( source_code, mode, __temp0, @@ -49096,7 +49203,7 @@ fn __action825< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action826< +fn __action827< >( source_code: &str, mode: Mode, @@ -49110,14 +49217,14 @@ fn __action826< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action145( + __action146( source_code, mode, __temp0, @@ -49132,7 +49239,7 @@ fn __action826< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action827< +fn __action828< >( source_code: &str, mode: Mode, @@ -49143,14 +49250,14 @@ fn __action827< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action392( + __action395( source_code, mode, __temp0, @@ -49162,7 +49269,7 @@ fn __action827< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action828< +fn __action829< >( source_code: &str, mode: Mode, @@ -49173,14 +49280,14 @@ fn __action828< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action385( + __action388( source_code, mode, __temp0, @@ -49192,7 +49299,7 @@ fn __action828< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action829< +fn __action830< >( source_code: &str, mode: Mode, @@ -49202,7 +49309,7 @@ fn __action829< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -49220,7 +49327,7 @@ fn __action829< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action830< +fn __action831< >( source_code: &str, mode: Mode, @@ -49233,14 +49340,14 @@ fn __action830< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action620( + __action623( source_code, mode, __temp0, @@ -49254,7 +49361,7 @@ fn __action830< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action831< +fn __action832< >( source_code: &str, mode: Mode, @@ -49266,14 +49373,14 @@ fn __action831< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action621( + __action624( source_code, mode, __temp0, @@ -49286,7 +49393,7 @@ fn __action831< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action832< +fn __action833< >( source_code: &str, mode: Mode, @@ -49296,7 +49403,7 @@ fn __action832< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -49314,7 +49421,7 @@ fn __action832< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action833< +fn __action834< >( source_code: &str, mode: Mode, @@ -49325,7 +49432,7 @@ fn __action833< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -49344,7 +49451,7 @@ fn __action833< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action834< +fn __action835< >( source_code: &str, mode: Mode, @@ -49357,7 +49464,7 @@ fn __action834< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -49378,7 +49485,7 @@ fn __action834< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action835< +fn __action836< >( source_code: &str, mode: Mode, @@ -49388,7 +49495,7 @@ fn __action835< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -49406,7 +49513,7 @@ fn __action835< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action836< +fn __action837< >( source_code: &str, mode: Mode, @@ -49416,7 +49523,7 @@ fn __action836< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -49434,7 +49541,7 @@ fn __action836< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action837< +fn __action838< >( source_code: &str, mode: Mode, @@ -49445,7 +49552,7 @@ fn __action837< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -49464,7 +49571,7 @@ fn __action837< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action838< +fn __action839< >( source_code: &str, mode: Mode, @@ -49481,21 +49588,21 @@ fn __action838< let __end0 = __0.0; let __start1 = __0.2; let __end1 = __1.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - let __temp1 = __action414( + let __temp1 = __action417( source_code, mode, &__start1, &__end1, ); let __temp1 = (__start1, __temp1, __end1); - __action183( + __action184( source_code, mode, __temp0, @@ -49512,7 +49619,7 @@ fn __action838< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action839< +fn __action840< >( source_code: &str, mode: Mode, @@ -49522,7 +49629,7 @@ fn __action839< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -49540,7 +49647,7 @@ fn __action839< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action840< +fn __action841< >( source_code: &str, mode: Mode, @@ -49550,7 +49657,7 @@ fn __action840< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -49568,7 +49675,7 @@ fn __action840< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action841< +fn __action842< >( source_code: &str, mode: Mode, @@ -49578,7 +49685,7 @@ fn __action841< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -49596,7 +49703,7 @@ fn __action841< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action842< +fn __action843< >( source_code: &str, mode: Mode, @@ -49606,7 +49713,7 @@ fn __action842< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -49624,7 +49731,7 @@ fn __action842< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action843< +fn __action844< >( source_code: &str, mode: Mode, @@ -49634,7 +49741,7 @@ fn __action843< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -49652,17 +49759,17 @@ fn __action843< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action844< +fn __action845< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), + __0: (TextSize, StringType, TextSize), __1: (TextSize, TextSize, TextSize), -) -> Result> +) -> ast::Pattern { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -49680,24 +49787,24 @@ fn __action844< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action845< +fn __action846< >( source_code: &str, mode: Mode, - __0: (TextSize, token::Tok, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::Expr +) -> Result> { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action129( + __action121( source_code, mode, __temp0, @@ -49708,7 +49815,7 @@ fn __action845< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action846< +fn __action847< >( source_code: &str, mode: Mode, @@ -49718,14 +49825,14 @@ fn __action846< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action130( + __action131( source_code, mode, __temp0, @@ -49736,7 +49843,7 @@ fn __action846< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action847< +fn __action848< >( source_code: &str, mode: Mode, @@ -49746,14 +49853,14 @@ fn __action847< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action131( + __action132( source_code, mode, __temp0, @@ -49764,24 +49871,24 @@ fn __action847< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action848< +fn __action849< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), + __0: (TextSize, token::Tok, TextSize), __1: (TextSize, TextSize, TextSize), -) -> Result> +) -> ast::Expr { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action132( + __action133( source_code, mode, __temp0, @@ -49792,7 +49899,7 @@ fn __action848< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action849< +fn __action850< >( source_code: &str, mode: Mode, @@ -49803,14 +49910,14 @@ fn __action849< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action134( + __action135( source_code, mode, __temp0, @@ -49822,7 +49929,7 @@ fn __action849< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action850< +fn __action851< >( source_code: &str, mode: Mode, @@ -49835,14 +49942,14 @@ fn __action850< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action624( + __action627( source_code, mode, __temp0, @@ -49856,7 +49963,7 @@ fn __action850< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action851< +fn __action852< >( source_code: &str, mode: Mode, @@ -49868,14 +49975,14 @@ fn __action851< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action625( + __action628( source_code, mode, __temp0, @@ -49888,7 +49995,7 @@ fn __action851< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action852< +fn __action853< >( source_code: &str, mode: Mode, @@ -49902,14 +50009,14 @@ fn __action852< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action626( + __action629( source_code, mode, __temp0, @@ -49924,7 +50031,7 @@ fn __action852< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action853< +fn __action854< >( source_code: &str, mode: Mode, @@ -49937,14 +50044,14 @@ fn __action853< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action627( + __action630( source_code, mode, __temp0, @@ -49958,7 +50065,7 @@ fn __action853< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action854< +fn __action855< >( source_code: &str, mode: Mode, @@ -49974,14 +50081,14 @@ fn __action854< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action628( + __action631( source_code, mode, __temp0, @@ -49998,7 +50105,7 @@ fn __action854< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action855< +fn __action856< >( source_code: &str, mode: Mode, @@ -50013,14 +50120,14 @@ fn __action855< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action629( + __action632( source_code, mode, __temp0, @@ -50036,7 +50143,7 @@ fn __action855< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action856< +fn __action857< >( source_code: &str, mode: Mode, @@ -50049,7 +50156,7 @@ fn __action856< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -50070,7 +50177,7 @@ fn __action856< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action857< +fn __action858< >( source_code: &str, mode: Mode, @@ -50082,14 +50189,14 @@ fn __action857< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action138( + __action139( source_code, mode, __temp0, @@ -50102,7 +50209,7 @@ fn __action857< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action858< +fn __action859< >( source_code: &str, mode: Mode, @@ -50112,14 +50219,14 @@ fn __action858< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action122( + __action123( source_code, mode, __temp0, @@ -50130,7 +50237,7 @@ fn __action858< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action859< +fn __action860< >( source_code: &str, mode: Mode, @@ -50142,14 +50249,14 @@ fn __action859< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action123( + __action124( source_code, mode, __temp0, @@ -50162,7 +50269,7 @@ fn __action859< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action860< +fn __action861< >( source_code: &str, mode: Mode, @@ -50174,14 +50281,14 @@ fn __action860< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action124( + __action125( source_code, mode, __temp0, @@ -50194,7 +50301,7 @@ fn __action860< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action861< +fn __action862< >( source_code: &str, mode: Mode, @@ -50209,7 +50316,7 @@ fn __action861< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -50232,7 +50339,7 @@ fn __action861< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action862< +fn __action863< >( source_code: &str, mode: Mode, @@ -50251,14 +50358,14 @@ fn __action862< let __end0 = __0.0; let __start1 = __0.2; let __end1 = __1.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - let __temp1 = __action414( + let __temp1 = __action417( source_code, mode, &__start1, @@ -50284,7 +50391,7 @@ fn __action862< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action863< +fn __action864< >( source_code: &str, mode: Mode, @@ -50303,21 +50410,21 @@ fn __action863< let __end0 = __0.0; let __start1 = __0.2; let __end1 = __1.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - let __temp1 = __action414( + let __temp1 = __action417( source_code, mode, &__start1, &__end1, ); let __temp1 = (__start1, __temp1, __end1); - __action630( + __action633( source_code, mode, __temp0, @@ -50336,7 +50443,7 @@ fn __action863< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action864< +fn __action865< >( source_code: &str, mode: Mode, @@ -50354,21 +50461,21 @@ fn __action864< let __end0 = __0.0; let __start1 = __0.2; let __end1 = __1.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - let __temp1 = __action414( + let __temp1 = __action417( source_code, mode, &__start1, &__end1, ); let __temp1 = (__start1, __temp1, __end1); - __action631( + __action634( source_code, mode, __temp0, @@ -50386,7 +50493,7 @@ fn __action864< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action865< +fn __action866< >( source_code: &str, mode: Mode, @@ -50398,14 +50505,14 @@ fn __action865< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action182( + __action183( source_code, mode, __temp0, @@ -50418,7 +50525,7 @@ fn __action865< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action866< +fn __action867< >( source_code: &str, mode: Mode, @@ -50428,14 +50535,14 @@ fn __action866< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action181( + __action182( source_code, mode, __temp0, @@ -50446,7 +50553,7 @@ fn __action866< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action867< +fn __action868< >( source_code: &str, mode: Mode, @@ -50457,7 +50564,7 @@ fn __action867< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -50474,36 +50581,6 @@ fn __action867< ) } -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action868< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), - __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr -{ - let __start0 = __0.0; - let __end0 = __0.0; - let __temp0 = __action414( - source_code, - mode, - &__start0, - &__end0, - ); - let __temp0 = (__start0, __temp0, __end0); - __action474( - source_code, - mode, - __temp0, - __0, - __1, - __2, - ) -} - #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] fn __action869< @@ -50517,14 +50594,14 @@ fn __action869< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action517( + __action477( source_code, mode, __temp0, @@ -50537,6 +50614,36 @@ fn __action869< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] fn __action870< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, token::Tok, TextSize), + __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, TextSize, TextSize), +) -> ast::ParenthesizedExpr +{ + let __start0 = __0.0; + let __end0 = __0.0; + let __temp0 = __action417( + source_code, + mode, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action520( + source_code, + mode, + __temp0, + __0, + __1, + __2, + ) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action871< >( source_code: &str, mode: Mode, @@ -50546,7 +50653,7 @@ fn __action870< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -50564,7 +50671,7 @@ fn __action870< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action871< +fn __action872< >( source_code: &str, mode: Mode, @@ -50575,7 +50682,7 @@ fn __action871< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -50594,7 +50701,7 @@ fn __action871< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action872< +fn __action873< >( source_code: &str, mode: Mode, @@ -50604,7 +50711,7 @@ fn __action872< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -50622,7 +50729,7 @@ fn __action872< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action873< +fn __action874< >( source_code: &str, mode: Mode, @@ -50633,14 +50740,14 @@ fn __action873< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action252( + __action255( source_code, mode, __temp0, @@ -50652,7 +50759,7 @@ fn __action873< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action874< +fn __action875< >( source_code: &str, mode: Mode, @@ -50663,14 +50770,14 @@ fn __action874< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action500( + __action503( source_code, mode, __temp0, @@ -50682,7 +50789,7 @@ fn __action874< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action875< +fn __action876< >( source_code: &str, mode: Mode, @@ -50694,14 +50801,14 @@ fn __action875< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action632( + __action635( source_code, mode, __temp0, @@ -50714,7 +50821,7 @@ fn __action875< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action876< +fn __action877< >( source_code: &str, mode: Mode, @@ -50725,14 +50832,14 @@ fn __action876< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action633( + __action636( source_code, mode, __temp0, @@ -50744,7 +50851,7 @@ fn __action876< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action877< +fn __action878< >( source_code: &str, mode: Mode, @@ -50757,14 +50864,14 @@ fn __action877< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action687( + __action690( source_code, mode, __temp0, @@ -50778,7 +50885,7 @@ fn __action877< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action878< +fn __action879< >( source_code: &str, mode: Mode, @@ -50790,14 +50897,14 @@ fn __action878< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action688( + __action691( source_code, mode, __temp0, @@ -50810,7 +50917,7 @@ fn __action878< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action879< +fn __action880< >( source_code: &str, mode: Mode, @@ -50821,14 +50928,14 @@ fn __action879< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action636( + __action639( source_code, mode, __temp0, @@ -50840,7 +50947,7 @@ fn __action879< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action880< +fn __action881< >( source_code: &str, mode: Mode, @@ -50850,14 +50957,14 @@ fn __action880< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action637( + __action640( source_code, mode, __temp0, @@ -50868,7 +50975,7 @@ fn __action880< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action881< +fn __action882< >( source_code: &str, mode: Mode, @@ -50879,14 +50986,14 @@ fn __action881< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action638( + __action641( source_code, mode, __temp0, @@ -50898,7 +51005,7 @@ fn __action881< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action882< +fn __action883< >( source_code: &str, mode: Mode, @@ -50908,14 +51015,14 @@ fn __action882< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action639( + __action642( source_code, mode, __temp0, @@ -50926,7 +51033,7 @@ fn __action882< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action883< +fn __action884< >( source_code: &str, mode: Mode, @@ -50938,14 +51045,14 @@ fn __action883< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action640( + __action643( source_code, mode, __temp0, @@ -50958,7 +51065,7 @@ fn __action883< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action884< +fn __action885< >( source_code: &str, mode: Mode, @@ -50969,14 +51076,14 @@ fn __action884< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action641( + __action644( source_code, mode, __temp0, @@ -50988,7 +51095,7 @@ fn __action884< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action885< +fn __action886< >( source_code: &str, mode: Mode, @@ -51001,14 +51108,14 @@ fn __action885< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action692( + __action695( source_code, mode, __temp0, @@ -51022,7 +51129,7 @@ fn __action885< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action886< +fn __action887< >( source_code: &str, mode: Mode, @@ -51034,14 +51141,14 @@ fn __action886< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action693( + __action696( source_code, mode, __temp0, @@ -51054,7 +51161,7 @@ fn __action886< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action887< +fn __action888< >( source_code: &str, mode: Mode, @@ -51065,14 +51172,14 @@ fn __action887< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action644( + __action647( source_code, mode, __temp0, @@ -51084,7 +51191,7 @@ fn __action887< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action888< +fn __action889< >( source_code: &str, mode: Mode, @@ -51094,14 +51201,14 @@ fn __action888< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action645( + __action648( source_code, mode, __temp0, @@ -51112,7 +51219,7 @@ fn __action888< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action889< +fn __action890< >( source_code: &str, mode: Mode, @@ -51123,14 +51230,14 @@ fn __action889< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action646( + __action649( source_code, mode, __temp0, @@ -51142,7 +51249,7 @@ fn __action889< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action890< +fn __action891< >( source_code: &str, mode: Mode, @@ -51152,14 +51259,14 @@ fn __action890< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action647( + __action650( source_code, mode, __temp0, @@ -51170,7 +51277,7 @@ fn __action890< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action891< +fn __action892< >( source_code: &str, mode: Mode, @@ -51182,14 +51289,14 @@ fn __action891< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action712( + __action715( source_code, mode, __temp0, @@ -51202,7 +51309,7 @@ fn __action891< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action892< +fn __action893< >( source_code: &str, mode: Mode, @@ -51213,14 +51320,14 @@ fn __action892< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action713( + __action716( source_code, mode, __temp0, @@ -51232,7 +51339,7 @@ fn __action892< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action893< +fn __action894< >( source_code: &str, mode: Mode, @@ -51245,14 +51352,14 @@ fn __action893< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action714( + __action717( source_code, mode, __temp0, @@ -51266,7 +51373,7 @@ fn __action893< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action894< +fn __action895< >( source_code: &str, mode: Mode, @@ -51278,14 +51385,14 @@ fn __action894< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action715( + __action718( source_code, mode, __temp0, @@ -51298,7 +51405,7 @@ fn __action894< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action895< +fn __action896< >( source_code: &str, mode: Mode, @@ -51308,14 +51415,14 @@ fn __action895< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action716( + __action719( source_code, mode, __temp0, @@ -51326,7 +51433,7 @@ fn __action895< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action896< +fn __action897< >( source_code: &str, mode: Mode, @@ -51335,14 +51442,14 @@ fn __action896< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action717( + __action720( source_code, mode, __temp0, @@ -51352,7 +51459,7 @@ fn __action896< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action897< +fn __action898< >( source_code: &str, mode: Mode, @@ -51363,14 +51470,14 @@ fn __action897< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action718( + __action721( source_code, mode, __temp0, @@ -51382,7 +51489,7 @@ fn __action897< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action898< +fn __action899< >( source_code: &str, mode: Mode, @@ -51392,14 +51499,14 @@ fn __action898< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action719( + __action722( source_code, mode, __temp0, @@ -51410,7 +51517,7 @@ fn __action898< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action899< +fn __action900< >( source_code: &str, mode: Mode, @@ -51422,14 +51529,14 @@ fn __action899< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action708( + __action711( source_code, mode, __temp0, @@ -51442,7 +51549,7 @@ fn __action899< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action900< +fn __action901< >( source_code: &str, mode: Mode, @@ -51455,14 +51562,14 @@ fn __action900< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action709( + __action712( source_code, mode, __temp0, @@ -51476,7 +51583,7 @@ fn __action900< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action901< +fn __action902< >( source_code: &str, mode: Mode, @@ -51486,14 +51593,14 @@ fn __action901< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action710( + __action713( source_code, mode, __temp0, @@ -51504,7 +51611,7 @@ fn __action901< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action902< +fn __action903< >( source_code: &str, mode: Mode, @@ -51515,14 +51622,14 @@ fn __action902< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action711( + __action714( source_code, mode, __temp0, @@ -51534,7 +51641,7 @@ fn __action902< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action903< +fn __action904< >( source_code: &str, mode: Mode, @@ -51546,14 +51653,14 @@ fn __action903< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action165( + __action166( source_code, mode, __temp0, @@ -51566,7 +51673,7 @@ fn __action903< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action904< +fn __action905< >( source_code: &str, mode: Mode, @@ -51576,7 +51683,7 @@ fn __action904< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -51594,7 +51701,7 @@ fn __action904< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action905< +fn __action906< >( source_code: &str, mode: Mode, @@ -51609,14 +51716,14 @@ fn __action905< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action648( + __action651( source_code, mode, __temp0, @@ -51632,7 +51739,7 @@ fn __action905< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action906< +fn __action907< >( source_code: &str, mode: Mode, @@ -51646,14 +51753,14 @@ fn __action906< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action649( + __action652( source_code, mode, __temp0, @@ -51668,7 +51775,7 @@ fn __action906< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action907< +fn __action908< >( source_code: &str, mode: Mode, @@ -51681,14 +51788,14 @@ fn __action907< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action650( + __action653( source_code, mode, __temp0, @@ -51702,7 +51809,7 @@ fn __action907< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action908< +fn __action909< >( source_code: &str, mode: Mode, @@ -51714,14 +51821,14 @@ fn __action908< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action651( + __action654( source_code, mode, __temp0, @@ -51734,7 +51841,7 @@ fn __action908< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action909< +fn __action910< >( source_code: &str, mode: Mode, @@ -51747,14 +51854,14 @@ fn __action909< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action652( + __action655( source_code, mode, __temp0, @@ -51768,7 +51875,7 @@ fn __action909< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action910< +fn __action911< >( source_code: &str, mode: Mode, @@ -51780,14 +51887,14 @@ fn __action910< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action653( + __action656( source_code, mode, __temp0, @@ -51800,7 +51907,7 @@ fn __action910< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action911< +fn __action912< >( source_code: &str, mode: Mode, @@ -51811,14 +51918,14 @@ fn __action911< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action144( + __action145( source_code, mode, __temp0, @@ -51830,7 +51937,7 @@ fn __action911< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action912< +fn __action913< >( source_code: &str, mode: Mode, @@ -51841,7 +51948,7 @@ fn __action912< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -51860,7 +51967,7 @@ fn __action912< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action913< +fn __action914< >( source_code: &str, mode: Mode, @@ -51871,14 +51978,14 @@ fn __action913< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action654( + __action657( source_code, mode, __temp0, @@ -51890,7 +51997,7 @@ fn __action913< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action914< +fn __action915< >( source_code: &str, mode: Mode, @@ -51900,14 +52007,14 @@ fn __action914< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action655( + __action658( source_code, mode, __temp0, @@ -51918,7 +52025,7 @@ fn __action914< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action915< +fn __action916< >( source_code: &str, mode: Mode, @@ -51930,14 +52037,14 @@ fn __action915< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action529( + __action532( source_code, mode, __temp0, @@ -51950,7 +52057,7 @@ fn __action915< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action916< +fn __action917< >( source_code: &str, mode: Mode, @@ -51962,14 +52069,14 @@ fn __action916< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action580( + __action583( source_code, mode, __temp0, @@ -51982,7 +52089,7 @@ fn __action916< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action917< +fn __action918< >( source_code: &str, mode: Mode, @@ -51992,7 +52099,7 @@ fn __action917< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -52010,7 +52117,7 @@ fn __action917< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action918< +fn __action919< >( source_code: &str, mode: Mode, @@ -52022,7 +52129,7 @@ fn __action918< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -52042,7 +52149,7 @@ fn __action918< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action919< +fn __action920< >( source_code: &str, mode: Mode, @@ -52054,7 +52161,7 @@ fn __action919< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -52074,7 +52181,7 @@ fn __action919< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action920< +fn __action921< >( source_code: &str, mode: Mode, @@ -52085,7 +52192,7 @@ fn __action920< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -52104,7 +52211,7 @@ fn __action920< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action921< +fn __action922< >( source_code: &str, mode: Mode, @@ -52117,7 +52224,7 @@ fn __action921< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -52138,7 +52245,7 @@ fn __action921< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action922< +fn __action923< >( source_code: &str, mode: Mode, @@ -52152,14 +52259,14 @@ fn __action922< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action656( + __action659( source_code, mode, __temp0, @@ -52174,7 +52281,7 @@ fn __action922< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action923< +fn __action924< >( source_code: &str, mode: Mode, @@ -52187,14 +52294,14 @@ fn __action923< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action657( + __action660( source_code, mode, __temp0, @@ -52208,7 +52315,7 @@ fn __action923< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action924< +fn __action925< >( source_code: &str, mode: Mode, @@ -52220,7 +52327,7 @@ fn __action924< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -52238,38 +52345,6 @@ fn __action924< ) } -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action925< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), - __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), - __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr -{ - let __start0 = __0.0; - let __end0 = __0.0; - let __temp0 = __action414( - source_code, - mode, - &__start0, - &__end0, - ); - let __temp0 = (__start0, __temp0, __end0); - __action504( - source_code, - mode, - __temp0, - __0, - __1, - __2, - __3, - ) -} - #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] fn __action926< @@ -52284,14 +52359,14 @@ fn __action926< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action541( + __action507( source_code, mode, __temp0, @@ -52305,6 +52380,38 @@ fn __action926< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] fn __action927< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, ast::Operator, TextSize), + __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, TextSize, TextSize), +) -> ast::ParenthesizedExpr +{ + let __start0 = __0.0; + let __end0 = __0.0; + let __temp0 = __action417( + source_code, + mode, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action544( + source_code, + mode, + __temp0, + __0, + __1, + __2, + __3, + ) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action928< >( source_code: &str, mode: Mode, @@ -52319,14 +52426,14 @@ fn __action927< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action682( + __action685( source_code, mode, __temp0, @@ -52342,7 +52449,7 @@ fn __action927< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action928< +fn __action929< >( source_code: &str, mode: Mode, @@ -52356,14 +52463,14 @@ fn __action928< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action683( + __action686( source_code, mode, __temp0, @@ -52378,7 +52485,7 @@ fn __action928< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action929< +fn __action930< >( source_code: &str, mode: Mode, @@ -52388,14 +52495,14 @@ fn __action929< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action211( + __action212( source_code, mode, __temp0, @@ -52406,7 +52513,7 @@ fn __action929< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action930< +fn __action931< >( source_code: &str, mode: Mode, @@ -52417,14 +52524,14 @@ fn __action930< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action233( + __action236( source_code, mode, __temp0, @@ -52436,7 +52543,7 @@ fn __action930< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action931< +fn __action932< >( source_code: &str, mode: Mode, @@ -52447,7 +52554,7 @@ fn __action931< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -52466,7 +52573,7 @@ fn __action931< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action932< +fn __action933< >( source_code: &str, mode: Mode, @@ -52477,14 +52584,14 @@ fn __action932< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action169( + __action170( source_code, mode, __temp0, @@ -52496,7 +52603,7 @@ fn __action932< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action933< +fn __action934< >( source_code: &str, mode: Mode, @@ -52506,14 +52613,14 @@ fn __action933< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action167( + __action168( source_code, mode, __temp0, @@ -52524,33 +52631,89 @@ fn __action933< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action934< +fn __action935< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, StringType, TextSize), +) -> ast::Expr +{ + let __start0 = __0.0; + let __end0 = __0.0; + let __temp0 = __action417( + source_code, + mode, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action213( + source_code, + mode, + __temp0, + __0, + ) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action936< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, Vec, TextSize), + __1: (TextSize, TextSize, TextSize), +) -> Result> +{ + let __start0 = __0.0; + let __end0 = __0.0; + let __temp0 = __action417( + source_code, + mode, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action214( + source_code, + mode, + __temp0, + __0, + __1, + ) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action937< >( source_code: &str, mode: Mode, __0: (TextSize, (String, StringKind, bool), TextSize), + __1: (TextSize, TextSize, TextSize), ) -> Result> { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action214( + __action217( source_code, mode, __temp0, __0, + __1, ) } #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action935< +fn __action938< >( source_code: &str, mode: Mode, @@ -52563,14 +52726,14 @@ fn __action935< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action210( + __action211( source_code, mode, __temp0, @@ -52584,7 +52747,7 @@ fn __action935< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action936< +fn __action939< >( source_code: &str, mode: Mode, @@ -52595,14 +52758,14 @@ fn __action936< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action207( + __action208( source_code, mode, __temp0, @@ -52614,7 +52777,7 @@ fn __action936< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action937< +fn __action940< >( source_code: &str, mode: Mode, @@ -52625,14 +52788,14 @@ fn __action937< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action660( + __action663( source_code, mode, __temp0, @@ -52644,7 +52807,7 @@ fn __action937< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action938< +fn __action941< >( source_code: &str, mode: Mode, @@ -52654,14 +52817,14 @@ fn __action938< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action661( + __action664( source_code, mode, __temp0, @@ -52672,7 +52835,7 @@ fn __action938< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action939< +fn __action942< >( source_code: &str, mode: Mode, @@ -52684,14 +52847,14 @@ fn __action939< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action521( + __action524( source_code, mode, __temp0, @@ -52704,7 +52867,7 @@ fn __action939< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action940< +fn __action943< >( source_code: &str, mode: Mode, @@ -52716,14 +52879,14 @@ fn __action940< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action574( + __action577( source_code, mode, __temp0, @@ -52736,7 +52899,7 @@ fn __action940< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action941< +fn __action944< >( source_code: &str, mode: Mode, @@ -52750,14 +52913,14 @@ fn __action941< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action400( + __action403( source_code, mode, __temp0, @@ -52772,7 +52935,7 @@ fn __action941< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action942< +fn __action945< >( source_code: &str, mode: Mode, @@ -52786,14 +52949,14 @@ fn __action942< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action432( + __action435( source_code, mode, __temp0, @@ -52808,7 +52971,7 @@ fn __action942< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action943< +fn __action946< >( source_code: &str, mode: Mode, @@ -52819,7 +52982,7 @@ fn __action943< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -52838,7 +53001,7 @@ fn __action943< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action944< +fn __action947< >( source_code: &str, mode: Mode, @@ -52850,7 +53013,7 @@ fn __action944< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, @@ -52870,7 +53033,7 @@ fn __action944< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action945< +fn __action948< >( source_code: &str, mode: Mode, @@ -52885,14 +53048,14 @@ fn __action945< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action148( + __action149( source_code, mode, __temp0, @@ -52908,7 +53071,7 @@ fn __action945< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action946< +fn __action949< >( source_code: &str, mode: Mode, @@ -52923,14 +53086,14 @@ fn __action946< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action149( + __action150( source_code, mode, __temp0, @@ -52946,7 +53109,7 @@ fn __action946< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action947< +fn __action950< >( source_code: &str, mode: Mode, @@ -52958,14 +53121,14 @@ fn __action947< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action150( + __action151( source_code, mode, __temp0, @@ -52978,7 +53141,7 @@ fn __action947< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action948< +fn __action951< >( source_code: &str, mode: Mode, @@ -52988,14 +53151,14 @@ fn __action948< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action163( + __action164( source_code, mode, __temp0, @@ -53006,7 +53169,7 @@ fn __action948< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action949< +fn __action952< >( source_code: &str, mode: Mode, @@ -53020,14 +53183,14 @@ fn __action949< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action164( + __action165( source_code, mode, __temp0, @@ -53042,7 +53205,7 @@ fn __action949< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action950< +fn __action953< >( source_code: &str, mode: Mode, @@ -53053,14 +53216,14 @@ fn __action950< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action173( + __action174( source_code, mode, __temp0, @@ -53072,7 +53235,7 @@ fn __action950< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action951< +fn __action954< >( source_code: &str, mode: Mode, @@ -53083,14 +53246,14 @@ fn __action951< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action174( + __action175( source_code, mode, __temp0, @@ -53102,7 +53265,7 @@ fn __action951< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action952< +fn __action955< >( source_code: &str, mode: Mode, @@ -53113,14 +53276,14 @@ fn __action952< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action175( + __action176( source_code, mode, __temp0, @@ -53132,7 +53295,7 @@ fn __action952< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action953< +fn __action956< >( source_code: &str, mode: Mode, @@ -53145,14 +53308,14 @@ fn __action953< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action662( + __action665( source_code, mode, __temp0, @@ -53166,7 +53329,7 @@ fn __action953< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action954< +fn __action957< >( source_code: &str, mode: Mode, @@ -53178,14 +53341,14 @@ fn __action954< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action663( + __action666( source_code, mode, __temp0, @@ -53198,7 +53361,7 @@ fn __action954< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action955< +fn __action958< >( source_code: &str, mode: Mode, @@ -53209,14 +53372,14 @@ fn __action955< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action168( + __action169( source_code, mode, __temp0, @@ -53228,7 +53391,7 @@ fn __action955< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action956< +fn __action959< >( source_code: &str, mode: Mode, @@ -53238,14 +53401,14 @@ fn __action956< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action166( + __action167( source_code, mode, __temp0, @@ -53256,7 +53419,7 @@ fn __action956< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action957< +fn __action960< >( source_code: &str, mode: Mode, @@ -53266,14 +53429,14 @@ fn __action957< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action125( + __action126( source_code, mode, __temp0, @@ -53284,7 +53447,7 @@ fn __action957< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action958< +fn __action961< >( source_code: &str, mode: Mode, @@ -53297,14 +53460,14 @@ fn __action958< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action146( + __action147( source_code, mode, __temp0, @@ -53318,7 +53481,7 @@ fn __action958< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action959< +fn __action962< >( source_code: &str, mode: Mode, @@ -53330,14 +53493,14 @@ fn __action959< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action161( + __action162( source_code, mode, __temp0, @@ -53350,7 +53513,7 @@ fn __action959< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action960< +fn __action963< >( source_code: &str, mode: Mode, @@ -53363,14 +53526,14 @@ fn __action960< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action684( + __action687( source_code, mode, __temp0, @@ -53384,7 +53547,7 @@ fn __action960< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action961< +fn __action964< >( source_code: &str, mode: Mode, @@ -53396,14 +53559,14 @@ fn __action961< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action685( + __action688( source_code, mode, __temp0, @@ -53416,7 +53579,7 @@ fn __action961< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action962< +fn __action965< >( source_code: &str, mode: Mode, @@ -53428,14 +53591,14 @@ fn __action962< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action424( + __action427( source_code, mode, __temp0, @@ -53448,7 +53611,7 @@ fn __action962< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action963< +fn __action966< >( source_code: &str, mode: Mode, @@ -53460,14 +53623,14 @@ fn __action963< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action531( + __action534( source_code, mode, __temp0, @@ -53480,7 +53643,7 @@ fn __action963< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action964< +fn __action967< >( source_code: &str, mode: Mode, @@ -53491,14 +53654,14 @@ fn __action964< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action177( + __action178( source_code, mode, __temp0, @@ -53510,7 +53673,7 @@ fn __action964< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action965< +fn __action968< >( source_code: &str, mode: Mode, @@ -53522,14 +53685,14 @@ fn __action965< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action414( + let __temp0 = __action417( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action178( + __action179( source_code, mode, __temp0, @@ -53542,7 +53705,7 @@ fn __action965< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action966< +fn __action969< >( source_code: &str, mode: Mode, @@ -53555,7 +53718,7 @@ fn __action966< { let __start0 = __1.0; let __end0 = __4.2; - let __temp0 = __action891( + let __temp0 = __action892( source_code, mode, __1, @@ -53564,7 +53727,7 @@ fn __action966< __4, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action441( + Ok(__action444( source_code, mode, __0, @@ -53574,7 +53737,7 @@ fn __action966< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action967< +fn __action970< >( source_code: &str, mode: Mode, @@ -53586,7 +53749,7 @@ fn __action967< { let __start0 = __1.0; let __end0 = __3.2; - let __temp0 = __action892( + let __temp0 = __action893( source_code, mode, __1, @@ -53594,7 +53757,7 @@ fn __action967< __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action441( + Ok(__action444( source_code, mode, __0, @@ -53604,7 +53767,7 @@ fn __action967< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action968< +fn __action971< >( source_code: &str, mode: Mode, @@ -53618,7 +53781,7 @@ fn __action968< { let __start0 = __1.0; let __end0 = __5.2; - let __temp0 = __action893( + let __temp0 = __action894( source_code, mode, __1, @@ -53628,7 +53791,7 @@ fn __action968< __5, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action441( + Ok(__action444( source_code, mode, __0, @@ -53638,7 +53801,7 @@ fn __action968< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action969< +fn __action972< >( source_code: &str, mode: Mode, @@ -53651,7 +53814,7 @@ fn __action969< { let __start0 = __1.0; let __end0 = __4.2; - let __temp0 = __action894( + let __temp0 = __action895( source_code, mode, __1, @@ -53660,7 +53823,7 @@ fn __action969< __4, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action441( + Ok(__action444( source_code, mode, __0, @@ -53670,7 +53833,7 @@ fn __action969< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action970< +fn __action973< >( source_code: &str, mode: Mode, @@ -53681,14 +53844,14 @@ fn __action970< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action895( + let __temp0 = __action896( source_code, mode, __1, __2, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action441( + Ok(__action444( source_code, mode, __0, @@ -53698,7 +53861,7 @@ fn __action970< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action971< +fn __action974< >( source_code: &str, mode: Mode, @@ -53708,13 +53871,13 @@ fn __action971< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action896( + let __temp0 = __action897( source_code, mode, __1, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action441( + Ok(__action444( source_code, mode, __0, @@ -53724,7 +53887,7 @@ fn __action971< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action972< +fn __action975< >( source_code: &str, mode: Mode, @@ -53736,7 +53899,7 @@ fn __action972< { let __start0 = __1.0; let __end0 = __3.2; - let __temp0 = __action897( + let __temp0 = __action898( source_code, mode, __1, @@ -53744,7 +53907,7 @@ fn __action972< __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action441( + Ok(__action444( source_code, mode, __0, @@ -53754,7 +53917,7 @@ fn __action972< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action973< +fn __action976< >( source_code: &str, mode: Mode, @@ -53765,14 +53928,14 @@ fn __action973< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action898( + let __temp0 = __action899( source_code, mode, __1, __2, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action441( + Ok(__action444( source_code, mode, __0, @@ -53782,7 +53945,7 @@ fn __action973< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action974< +fn __action977< >( source_code: &str, mode: Mode, @@ -53796,7 +53959,7 @@ fn __action974< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action891( + let __temp0 = __action892( source_code, mode, __0, @@ -53805,7 +53968,7 @@ fn __action974< __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action879( + Ok(__action880( source_code, mode, __temp0, @@ -53816,7 +53979,7 @@ fn __action974< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action975< +fn __action978< >( source_code: &str, mode: Mode, @@ -53829,7 +53992,7 @@ fn __action975< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action892( + let __temp0 = __action893( source_code, mode, __0, @@ -53837,7 +54000,7 @@ fn __action975< __2, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action879( + Ok(__action880( source_code, mode, __temp0, @@ -53848,7 +54011,7 @@ fn __action975< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action976< +fn __action979< >( source_code: &str, mode: Mode, @@ -53863,7 +54026,7 @@ fn __action976< { let __start0 = __0.0; let __end0 = __4.2; - let __temp0 = __action893( + let __temp0 = __action894( source_code, mode, __0, @@ -53873,7 +54036,7 @@ fn __action976< __4, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action879( + Ok(__action880( source_code, mode, __temp0, @@ -53884,7 +54047,7 @@ fn __action976< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action977< +fn __action980< >( source_code: &str, mode: Mode, @@ -53898,7 +54061,7 @@ fn __action977< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action894( + let __temp0 = __action895( source_code, mode, __0, @@ -53907,7 +54070,7 @@ fn __action977< __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action879( + Ok(__action880( source_code, mode, __temp0, @@ -53918,7 +54081,7 @@ fn __action977< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action978< +fn __action981< >( source_code: &str, mode: Mode, @@ -53930,14 +54093,14 @@ fn __action978< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action895( + let __temp0 = __action896( source_code, mode, __0, __1, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action879( + Ok(__action880( source_code, mode, __temp0, @@ -53948,7 +54111,7 @@ fn __action978< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action979< +fn __action982< >( source_code: &str, mode: Mode, @@ -53959,13 +54122,13 @@ fn __action979< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action896( + let __temp0 = __action897( source_code, mode, __0, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action879( + Ok(__action880( source_code, mode, __temp0, @@ -53976,7 +54139,7 @@ fn __action979< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action980< +fn __action983< >( source_code: &str, mode: Mode, @@ -53989,7 +54152,7 @@ fn __action980< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action897( + let __temp0 = __action898( source_code, mode, __0, @@ -53997,7 +54160,7 @@ fn __action980< __2, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action879( + Ok(__action880( source_code, mode, __temp0, @@ -54008,7 +54171,7 @@ fn __action980< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action981< +fn __action984< >( source_code: &str, mode: Mode, @@ -54020,14 +54183,14 @@ fn __action981< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action898( + let __temp0 = __action899( source_code, mode, __0, __1, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action879( + Ok(__action880( source_code, mode, __temp0, @@ -54038,7 +54201,7 @@ fn __action981< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action982< +fn __action985< >( source_code: &str, mode: Mode, @@ -54051,7 +54214,7 @@ fn __action982< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action891( + let __temp0 = __action892( source_code, mode, __0, @@ -54060,7 +54223,7 @@ fn __action982< __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action880( + Ok(__action881( source_code, mode, __temp0, @@ -54070,7 +54233,7 @@ fn __action982< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action983< +fn __action986< >( source_code: &str, mode: Mode, @@ -54082,7 +54245,7 @@ fn __action983< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action892( + let __temp0 = __action893( source_code, mode, __0, @@ -54090,7 +54253,7 @@ fn __action983< __2, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action880( + Ok(__action881( source_code, mode, __temp0, @@ -54100,7 +54263,7 @@ fn __action983< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action984< +fn __action987< >( source_code: &str, mode: Mode, @@ -54114,7 +54277,7 @@ fn __action984< { let __start0 = __0.0; let __end0 = __4.2; - let __temp0 = __action893( + let __temp0 = __action894( source_code, mode, __0, @@ -54124,7 +54287,7 @@ fn __action984< __4, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action880( + Ok(__action881( source_code, mode, __temp0, @@ -54134,7 +54297,7 @@ fn __action984< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action985< +fn __action988< >( source_code: &str, mode: Mode, @@ -54147,7 +54310,7 @@ fn __action985< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action894( + let __temp0 = __action895( source_code, mode, __0, @@ -54156,7 +54319,7 @@ fn __action985< __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action880( + Ok(__action881( source_code, mode, __temp0, @@ -54166,7 +54329,7 @@ fn __action985< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action986< +fn __action989< >( source_code: &str, mode: Mode, @@ -54177,14 +54340,14 @@ fn __action986< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action895( + let __temp0 = __action896( source_code, mode, __0, __1, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action880( + Ok(__action881( source_code, mode, __temp0, @@ -54194,7 +54357,7 @@ fn __action986< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action987< +fn __action990< >( source_code: &str, mode: Mode, @@ -54204,13 +54367,13 @@ fn __action987< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action896( + let __temp0 = __action897( source_code, mode, __0, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action880( + Ok(__action881( source_code, mode, __temp0, @@ -54220,7 +54383,7 @@ fn __action987< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action988< +fn __action991< >( source_code: &str, mode: Mode, @@ -54232,7 +54395,7 @@ fn __action988< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action897( + let __temp0 = __action898( source_code, mode, __0, @@ -54240,7 +54403,7 @@ fn __action988< __2, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action880( + Ok(__action881( source_code, mode, __temp0, @@ -54250,7 +54413,7 @@ fn __action988< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action989< +fn __action992< >( source_code: &str, mode: Mode, @@ -54261,14 +54424,14 @@ fn __action989< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action898( + let __temp0 = __action899( source_code, mode, __0, __1, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action880( + Ok(__action881( source_code, mode, __temp0, @@ -54278,7 +54441,7 @@ fn __action989< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action990< +fn __action993< >( source_code: &str, mode: Mode, @@ -54291,7 +54454,7 @@ fn __action990< { let __start0 = __0.0; let __end0 = __4.2; - let __temp0 = __action966( + let __temp0 = __action969( source_code, mode, __0, @@ -54301,7 +54464,7 @@ fn __action990< __4, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action439( + Ok(__action442( source_code, mode, __temp0, @@ -54310,7 +54473,7 @@ fn __action990< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action991< +fn __action994< >( source_code: &str, mode: Mode, @@ -54322,7 +54485,7 @@ fn __action991< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action967( + let __temp0 = __action970( source_code, mode, __0, @@ -54331,7 +54494,7 @@ fn __action991< __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action439( + Ok(__action442( source_code, mode, __temp0, @@ -54340,7 +54503,7 @@ fn __action991< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action992< +fn __action995< >( source_code: &str, mode: Mode, @@ -54354,7 +54517,7 @@ fn __action992< { let __start0 = __0.0; let __end0 = __5.2; - let __temp0 = __action968( + let __temp0 = __action971( source_code, mode, __0, @@ -54365,7 +54528,7 @@ fn __action992< __5, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action439( + Ok(__action442( source_code, mode, __temp0, @@ -54374,7 +54537,7 @@ fn __action992< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action993< +fn __action996< >( source_code: &str, mode: Mode, @@ -54387,91 +54550,6 @@ fn __action993< { let __start0 = __0.0; let __end0 = __4.2; - let __temp0 = __action969( - source_code, - mode, - __0, - __1, - __2, - __3, - __4, - )?; - let __temp0 = (__start0, __temp0, __end0); - Ok(__action439( - source_code, - mode, - __temp0, - )) -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action994< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::Parameter, TextSize), -) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> -{ - let __start0 = __0.0; - let __end0 = __2.2; - let __temp0 = __action970( - source_code, - mode, - __0, - __1, - __2, - )?; - let __temp0 = (__start0, __temp0, __end0); - Ok(__action439( - source_code, - mode, - __temp0, - )) -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action995< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), -) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> -{ - let __start0 = __0.0; - let __end0 = __1.2; - let __temp0 = __action971( - source_code, - mode, - __0, - __1, - )?; - let __temp0 = (__start0, __temp0, __end0); - Ok(__action439( - source_code, - mode, - __temp0, - )) -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action996< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::Parameter, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), -) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> -{ - let __start0 = __0.0; - let __end0 = __3.2; let __temp0 = __action972( source_code, mode, @@ -54479,9 +54557,10 @@ fn __action996< __1, __2, __3, + __4, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action439( + Ok(__action442( source_code, mode, __temp0, @@ -54496,7 +54575,7 @@ fn __action997< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), + __2: (TextSize, ast::Parameter, TextSize), ) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> { let __start0 = __0.0; @@ -54509,7 +54588,7 @@ fn __action997< __2, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action439( + Ok(__action442( source_code, mode, __temp0, @@ -54519,6 +54598,90 @@ fn __action997< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] fn __action998< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, token::Tok, TextSize), + __1: (TextSize, token::Tok, TextSize), +) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> +{ + let __start0 = __0.0; + let __end0 = __1.2; + let __temp0 = __action974( + source_code, + mode, + __0, + __1, + )?; + let __temp0 = (__start0, __temp0, __end0); + Ok(__action442( + source_code, + mode, + __temp0, + )) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action999< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, token::Tok, TextSize), + __1: (TextSize, token::Tok, TextSize), + __2: (TextSize, ast::Parameter, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), +) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> +{ + let __start0 = __0.0; + let __end0 = __3.2; + let __temp0 = __action975( + source_code, + mode, + __0, + __1, + __2, + __3, + )?; + let __temp0 = (__start0, __temp0, __end0); + Ok(__action442( + source_code, + mode, + __temp0, + )) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action1000< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, token::Tok, TextSize), + __1: (TextSize, token::Tok, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), +) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> +{ + let __start0 = __0.0; + let __end0 = __2.2; + let __temp0 = __action976( + source_code, + mode, + __0, + __1, + __2, + )?; + let __temp0 = (__start0, __temp0, __end0); + Ok(__action442( + source_code, + mode, + __temp0, + )) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action1001< >( source_code: &str, mode: Mode, @@ -54534,7 +54697,7 @@ fn __action998< { let __start0 = __1.0; let __end0 = __5.2; - let __temp0 = __action990( + let __temp0 = __action993( source_code, mode, __1, @@ -54544,7 +54707,7 @@ fn __action998< __5, )?; let __temp0 = (__start0, __temp0, __end0); - __action875( + __action876( source_code, mode, __0, @@ -54556,7 +54719,7 @@ fn __action998< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action999< +fn __action1002< >( source_code: &str, mode: Mode, @@ -54571,7 +54734,7 @@ fn __action999< { let __start0 = __1.0; let __end0 = __4.2; - let __temp0 = __action991( + let __temp0 = __action994( source_code, mode, __1, @@ -54580,7 +54743,7 @@ fn __action999< __4, )?; let __temp0 = (__start0, __temp0, __end0); - __action875( + __action876( source_code, mode, __0, @@ -54592,7 +54755,7 @@ fn __action999< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1000< +fn __action1003< >( source_code: &str, mode: Mode, @@ -54609,7 +54772,7 @@ fn __action1000< { let __start0 = __1.0; let __end0 = __6.2; - let __temp0 = __action992( + let __temp0 = __action995( source_code, mode, __1, @@ -54620,7 +54783,7 @@ fn __action1000< __6, )?; let __temp0 = (__start0, __temp0, __end0); - __action875( + __action876( source_code, mode, __0, @@ -54632,7 +54795,7 @@ fn __action1000< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1001< +fn __action1004< >( source_code: &str, mode: Mode, @@ -54648,7 +54811,7 @@ fn __action1001< { let __start0 = __1.0; let __end0 = __5.2; - let __temp0 = __action993( + let __temp0 = __action996( source_code, mode, __1, @@ -54658,7 +54821,7 @@ fn __action1001< __5, )?; let __temp0 = (__start0, __temp0, __end0); - __action875( + __action876( source_code, mode, __0, @@ -54670,7 +54833,7 @@ fn __action1001< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1002< +fn __action1005< >( source_code: &str, mode: Mode, @@ -54684,7 +54847,7 @@ fn __action1002< { let __start0 = __1.0; let __end0 = __3.2; - let __temp0 = __action994( + let __temp0 = __action997( source_code, mode, __1, @@ -54692,7 +54855,7 @@ fn __action1002< __3, )?; let __temp0 = (__start0, __temp0, __end0); - __action875( + __action876( source_code, mode, __0, @@ -54704,7 +54867,7 @@ fn __action1002< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1003< +fn __action1006< >( source_code: &str, mode: Mode, @@ -54717,14 +54880,14 @@ fn __action1003< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action995( + let __temp0 = __action998( source_code, mode, __1, __2, )?; let __temp0 = (__start0, __temp0, __end0); - __action875( + __action876( source_code, mode, __0, @@ -54736,7 +54899,7 @@ fn __action1003< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1004< +fn __action1007< >( source_code: &str, mode: Mode, @@ -54751,7 +54914,7 @@ fn __action1004< { let __start0 = __1.0; let __end0 = __4.2; - let __temp0 = __action996( + let __temp0 = __action999( source_code, mode, __1, @@ -54760,7 +54923,7 @@ fn __action1004< __4, )?; let __temp0 = (__start0, __temp0, __end0); - __action875( + __action876( source_code, mode, __0, @@ -54772,7 +54935,7 @@ fn __action1004< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1005< +fn __action1008< >( source_code: &str, mode: Mode, @@ -54786,7 +54949,7 @@ fn __action1005< { let __start0 = __1.0; let __end0 = __3.2; - let __temp0 = __action997( + let __temp0 = __action1000( source_code, mode, __1, @@ -54794,7 +54957,7 @@ fn __action1005< __3, )?; let __temp0 = (__start0, __temp0, __end0); - __action875( + __action876( source_code, mode, __0, @@ -54806,7 +54969,7 @@ fn __action1005< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1006< +fn __action1009< >( source_code: &str, mode: Mode, @@ -54817,14 +54980,14 @@ fn __action1006< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action440( + let __temp0 = __action443( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action875( + __action876( source_code, mode, __0, @@ -54836,7 +54999,7 @@ fn __action1006< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1007< +fn __action1010< >( source_code: &str, mode: Mode, @@ -54851,7 +55014,7 @@ fn __action1007< { let __start0 = __1.0; let __end0 = __5.2; - let __temp0 = __action990( + let __temp0 = __action993( source_code, mode, __1, @@ -54861,7 +55024,7 @@ fn __action1007< __5, )?; let __temp0 = (__start0, __temp0, __end0); - __action876( + __action877( source_code, mode, __0, @@ -54872,7 +55035,7 @@ fn __action1007< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1008< +fn __action1011< >( source_code: &str, mode: Mode, @@ -54886,7 +55049,7 @@ fn __action1008< { let __start0 = __1.0; let __end0 = __4.2; - let __temp0 = __action991( + let __temp0 = __action994( source_code, mode, __1, @@ -54895,7 +55058,7 @@ fn __action1008< __4, )?; let __temp0 = (__start0, __temp0, __end0); - __action876( + __action877( source_code, mode, __0, @@ -54906,7 +55069,7 @@ fn __action1008< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1009< +fn __action1012< >( source_code: &str, mode: Mode, @@ -54922,7 +55085,7 @@ fn __action1009< { let __start0 = __1.0; let __end0 = __6.2; - let __temp0 = __action992( + let __temp0 = __action995( source_code, mode, __1, @@ -54933,7 +55096,7 @@ fn __action1009< __6, )?; let __temp0 = (__start0, __temp0, __end0); - __action876( + __action877( source_code, mode, __0, @@ -54944,7 +55107,7 @@ fn __action1009< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1010< +fn __action1013< >( source_code: &str, mode: Mode, @@ -54959,7 +55122,7 @@ fn __action1010< { let __start0 = __1.0; let __end0 = __5.2; - let __temp0 = __action993( + let __temp0 = __action996( source_code, mode, __1, @@ -54969,7 +55132,7 @@ fn __action1010< __5, )?; let __temp0 = (__start0, __temp0, __end0); - __action876( + __action877( source_code, mode, __0, @@ -54980,7 +55143,7 @@ fn __action1010< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1011< +fn __action1014< >( source_code: &str, mode: Mode, @@ -54993,7 +55156,7 @@ fn __action1011< { let __start0 = __1.0; let __end0 = __3.2; - let __temp0 = __action994( + let __temp0 = __action997( source_code, mode, __1, @@ -55001,7 +55164,7 @@ fn __action1011< __3, )?; let __temp0 = (__start0, __temp0, __end0); - __action876( + __action877( source_code, mode, __0, @@ -55012,7 +55175,7 @@ fn __action1011< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1012< +fn __action1015< >( source_code: &str, mode: Mode, @@ -55024,14 +55187,14 @@ fn __action1012< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action995( + let __temp0 = __action998( source_code, mode, __1, __2, )?; let __temp0 = (__start0, __temp0, __end0); - __action876( + __action877( source_code, mode, __0, @@ -55042,7 +55205,7 @@ fn __action1012< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1013< +fn __action1016< >( source_code: &str, mode: Mode, @@ -55056,7 +55219,7 @@ fn __action1013< { let __start0 = __1.0; let __end0 = __4.2; - let __temp0 = __action996( + let __temp0 = __action999( source_code, mode, __1, @@ -55065,7 +55228,7 @@ fn __action1013< __4, )?; let __temp0 = (__start0, __temp0, __end0); - __action876( + __action877( source_code, mode, __0, @@ -55076,7 +55239,7 @@ fn __action1013< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1014< +fn __action1017< >( source_code: &str, mode: Mode, @@ -55089,7 +55252,7 @@ fn __action1014< { let __start0 = __1.0; let __end0 = __3.2; - let __temp0 = __action997( + let __temp0 = __action1000( source_code, mode, __1, @@ -55097,7 +55260,7 @@ fn __action1014< __3, )?; let __temp0 = (__start0, __temp0, __end0); - __action876( + __action877( source_code, mode, __0, @@ -55108,7 +55271,7 @@ fn __action1014< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1015< +fn __action1018< >( source_code: &str, mode: Mode, @@ -55118,14 +55281,14 @@ fn __action1015< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action440( + let __temp0 = __action443( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action876( + __action877( source_code, mode, __0, @@ -55136,7 +55299,7 @@ fn __action1015< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1016< +fn __action1019< >( source_code: &str, mode: Mode, @@ -55146,13 +55309,13 @@ fn __action1016< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action485( + let __temp0 = __action488( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action446( + __action449( source_code, mode, __0, @@ -55162,7 +55325,7 @@ fn __action1016< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1017< +fn __action1020< >( source_code: &str, mode: Mode, @@ -55171,14 +55334,14 @@ fn __action1017< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action486( + let __temp0 = __action489( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action446( + __action449( source_code, mode, __0, @@ -55188,7 +55351,7 @@ fn __action1017< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1018< +fn __action1021< >( source_code: &str, mode: Mode, @@ -55200,13 +55363,13 @@ fn __action1018< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action485( + let __temp0 = __action488( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action899( + __action900( source_code, mode, __0, @@ -55218,7 +55381,7 @@ fn __action1018< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1019< +fn __action1022< >( source_code: &str, mode: Mode, @@ -55229,14 +55392,14 @@ fn __action1019< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action486( + let __temp0 = __action489( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action899( + __action900( source_code, mode, __0, @@ -55248,7 +55411,7 @@ fn __action1019< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1020< +fn __action1023< >( source_code: &str, mode: Mode, @@ -55261,13 +55424,13 @@ fn __action1020< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action485( + let __temp0 = __action488( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action900( + __action901( source_code, mode, __0, @@ -55280,7 +55443,7 @@ fn __action1020< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1021< +fn __action1024< >( source_code: &str, mode: Mode, @@ -55292,14 +55455,14 @@ fn __action1021< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action486( + let __temp0 = __action489( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action900( + __action901( source_code, mode, __0, @@ -55312,7 +55475,7 @@ fn __action1021< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1022< +fn __action1025< >( source_code: &str, mode: Mode, @@ -55322,13 +55485,13 @@ fn __action1022< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action485( + let __temp0 = __action488( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action901( + __action902( source_code, mode, __0, @@ -55338,7 +55501,7 @@ fn __action1022< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1023< +fn __action1026< >( source_code: &str, mode: Mode, @@ -55347,14 +55510,14 @@ fn __action1023< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action486( + let __temp0 = __action489( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action901( + __action902( source_code, mode, __0, @@ -55364,7 +55527,7 @@ fn __action1023< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1024< +fn __action1027< >( source_code: &str, mode: Mode, @@ -55375,13 +55538,13 @@ fn __action1024< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action485( + let __temp0 = __action488( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action902( + __action903( source_code, mode, __0, @@ -55392,7 +55555,7 @@ fn __action1024< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1025< +fn __action1028< >( source_code: &str, mode: Mode, @@ -55402,14 +55565,14 @@ fn __action1025< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action486( + let __temp0 = __action489( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action902( + __action903( source_code, mode, __0, @@ -55418,102 +55581,6 @@ fn __action1025< ) } -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action1026< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::Parameter, TextSize), - __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, Option>, TextSize), -) -> Result<(Option>, Vec, Option>),__lalrpop_util::ParseError> -{ - let __start0 = __1.0; - let __end0 = __4.2; - let __temp0 = __action1018( - source_code, - mode, - __1, - __2, - __3, - __4, - )?; - let __temp0 = (__start0, __temp0, __end0); - Ok(__action449( - source_code, - mode, - __0, - __temp0, - )) -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action1027< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, Option>, TextSize), -) -> Result<(Option>, Vec, Option>),__lalrpop_util::ParseError> -{ - let __start0 = __1.0; - let __end0 = __3.2; - let __temp0 = __action1019( - source_code, - mode, - __1, - __2, - __3, - )?; - let __temp0 = (__start0, __temp0, __end0); - Ok(__action449( - source_code, - mode, - __0, - __temp0, - )) -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action1028< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::Parameter, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), - __4: (TextSize, token::Tok, TextSize), - __5: (TextSize, Option>, TextSize), -) -> Result<(Option>, Vec, Option>),__lalrpop_util::ParseError> -{ - let __start0 = __1.0; - let __end0 = __5.2; - let __temp0 = __action1020( - source_code, - mode, - __1, - __2, - __3, - __4, - __5, - )?; - let __temp0 = (__start0, __temp0, __end0); - Ok(__action449( - source_code, - mode, - __0, - __temp0, - )) -} - #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] fn __action1029< @@ -55522,7 +55589,7 @@ fn __action1029< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), + __2: (TextSize, ast::Parameter, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, Option>, TextSize), ) -> Result<(Option>, Vec, Option>),__lalrpop_util::ParseError> @@ -55538,7 +55605,7 @@ fn __action1029< __4, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action449( + Ok(__action452( source_code, mode, __0, @@ -55554,19 +55621,21 @@ fn __action1030< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::Parameter, TextSize), + __2: (TextSize, token::Tok, TextSize), + __3: (TextSize, Option>, TextSize), ) -> Result<(Option>, Vec, Option>),__lalrpop_util::ParseError> { let __start0 = __1.0; - let __end0 = __2.2; + let __end0 = __3.2; let __temp0 = __action1022( source_code, mode, __1, __2, + __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action449( + Ok(__action452( source_code, mode, __0, @@ -55582,17 +55651,25 @@ fn __action1031< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), + __2: (TextSize, ast::Parameter, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), + __4: (TextSize, token::Tok, TextSize), + __5: (TextSize, Option>, TextSize), ) -> Result<(Option>, Vec, Option>),__lalrpop_util::ParseError> { let __start0 = __1.0; - let __end0 = __1.2; + let __end0 = __5.2; let __temp0 = __action1023( source_code, mode, __1, + __2, + __3, + __4, + __5, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action449( + Ok(__action452( source_code, mode, __0, @@ -55608,21 +55685,23 @@ fn __action1032< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::Parameter, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, token::Tok, TextSize), + __4: (TextSize, Option>, TextSize), ) -> Result<(Option>, Vec, Option>),__lalrpop_util::ParseError> { let __start0 = __1.0; - let __end0 = __3.2; + let __end0 = __4.2; let __temp0 = __action1024( source_code, mode, __1, __2, __3, + __4, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action449( + Ok(__action452( source_code, mode, __0, @@ -55638,7 +55717,7 @@ fn __action1033< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), + __2: (TextSize, ast::Parameter, TextSize), ) -> Result<(Option>, Vec, Option>),__lalrpop_util::ParseError> { let __start0 = __1.0; @@ -55650,7 +55729,7 @@ fn __action1033< __2, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action449( + Ok(__action452( source_code, mode, __0, @@ -55665,30 +55744,22 @@ fn __action1034< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::Parameter, TextSize), - __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, Option>, TextSize), - __4: (TextSize, token::Tok, TextSize), - __5: (TextSize, TextSize, TextSize), -) -> Result> + __1: (TextSize, token::Tok, TextSize), +) -> Result<(Option>, Vec, Option>),__lalrpop_util::ParseError> { - let __start0 = __0.0; - let __end0 = __3.2; - let __temp0 = __action1018( + let __start0 = __1.0; + let __end0 = __1.2; + let __temp0 = __action1026( source_code, mode, - __0, __1, - __2, - __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action887( + Ok(__action452( source_code, mode, + __0, __temp0, - __4, - __5, )) } @@ -55700,27 +55771,25 @@ fn __action1035< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, Option>, TextSize), - __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, TextSize, TextSize), -) -> Result> + __2: (TextSize, ast::Parameter, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), +) -> Result<(Option>, Vec, Option>),__lalrpop_util::ParseError> { - let __start0 = __0.0; - let __end0 = __2.2; - let __temp0 = __action1019( + let __start0 = __1.0; + let __end0 = __3.2; + let __temp0 = __action1027( source_code, mode, - __0, __1, __2, + __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action887( + Ok(__action452( source_code, mode, + __0, __temp0, - __3, - __4, )) } @@ -55731,32 +55800,24 @@ fn __action1036< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::Parameter, TextSize), + __1: (TextSize, token::Tok, TextSize), __2: (TextSize, alloc::vec::Vec, TextSize), - __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, Option>, TextSize), - __5: (TextSize, token::Tok, TextSize), - __6: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result<(Option>, Vec, Option>),__lalrpop_util::ParseError> { - let __start0 = __0.0; - let __end0 = __4.2; - let __temp0 = __action1020( + let __start0 = __1.0; + let __end0 = __2.2; + let __temp0 = __action1028( source_code, mode, - __0, __1, __2, - __3, - __4, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action887( + Ok(__action452( source_code, mode, + __0, __temp0, - __5, - __6, )) } @@ -55767,7 +55828,7 @@ fn __action1037< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, ast::Parameter, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, Option>, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -55785,7 +55846,7 @@ fn __action1037< __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action887( + Ok(__action888( source_code, mode, __temp0, @@ -55801,26 +55862,28 @@ fn __action1038< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::Parameter, TextSize), - __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, TextSize, TextSize), + __1: (TextSize, token::Tok, TextSize), + __2: (TextSize, Option>, TextSize), + __3: (TextSize, token::Tok, TextSize), + __4: (TextSize, TextSize, TextSize), ) -> Result> { let __start0 = __0.0; - let __end0 = __1.2; + let __end0 = __2.2; let __temp0 = __action1022( source_code, mode, __0, __1, + __2, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action887( + Ok(__action888( source_code, mode, __temp0, - __2, __3, + __4, )) } @@ -55831,24 +55894,32 @@ fn __action1039< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, TextSize, TextSize), + __1: (TextSize, ast::Parameter, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, token::Tok, TextSize), + __4: (TextSize, Option>, TextSize), + __5: (TextSize, token::Tok, TextSize), + __6: (TextSize, TextSize, TextSize), ) -> Result> { let __start0 = __0.0; - let __end0 = __0.2; + let __end0 = __4.2; let __temp0 = __action1023( source_code, mode, __0, + __1, + __2, + __3, + __4, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action887( + Ok(__action888( source_code, mode, __temp0, - __1, - __2, + __5, + __6, )) } @@ -55859,28 +55930,30 @@ fn __action1040< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::Parameter, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), - __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, TextSize, TextSize), + __1: (TextSize, alloc::vec::Vec, TextSize), + __2: (TextSize, token::Tok, TextSize), + __3: (TextSize, Option>, TextSize), + __4: (TextSize, token::Tok, TextSize), + __5: (TextSize, TextSize, TextSize), ) -> Result> { let __start0 = __0.0; - let __end0 = __2.2; + let __end0 = __3.2; let __temp0 = __action1024( source_code, mode, __0, __1, __2, + __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action887( + Ok(__action888( source_code, mode, __temp0, - __3, __4, + __5, )) } @@ -55891,7 +55964,7 @@ fn __action1041< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, ast::Parameter, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), ) -> Result> @@ -55905,7 +55978,7 @@ fn __action1041< __1, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action887( + Ok(__action888( source_code, mode, __temp0, @@ -55921,28 +55994,24 @@ fn __action1042< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::Parameter, TextSize), - __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, Option>, TextSize), - __4: (TextSize, TextSize, TextSize), + __1: (TextSize, token::Tok, TextSize), + __2: (TextSize, TextSize, TextSize), ) -> Result> { let __start0 = __0.0; - let __end0 = __3.2; - let __temp0 = __action1018( + let __end0 = __0.2; + let __temp0 = __action1026( source_code, mode, __0, - __1, - __2, - __3, )?; let __temp0 = (__start0, __temp0, __end0); Ok(__action888( source_code, mode, __temp0, - __4, + __1, + __2, )) } @@ -55953,14 +56022,15 @@ fn __action1043< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, Option>, TextSize), - __3: (TextSize, TextSize, TextSize), + __1: (TextSize, ast::Parameter, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, token::Tok, TextSize), + __4: (TextSize, TextSize, TextSize), ) -> Result> { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action1019( + let __temp0 = __action1027( source_code, mode, __0, @@ -55973,6 +56043,7 @@ fn __action1043< mode, __temp0, __3, + __4, )) } @@ -55983,30 +56054,26 @@ fn __action1044< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::Parameter, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), - __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, Option>, TextSize), - __5: (TextSize, TextSize, TextSize), + __1: (TextSize, alloc::vec::Vec, TextSize), + __2: (TextSize, token::Tok, TextSize), + __3: (TextSize, TextSize, TextSize), ) -> Result> { let __start0 = __0.0; - let __end0 = __4.2; - let __temp0 = __action1020( + let __end0 = __1.2; + let __temp0 = __action1028( source_code, mode, __0, __1, - __2, - __3, - __4, )?; let __temp0 = (__start0, __temp0, __end0); Ok(__action888( source_code, mode, __temp0, - __5, + __2, + __3, )) } @@ -56017,7 +56084,7 @@ fn __action1045< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, ast::Parameter, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, Option>, TextSize), __4: (TextSize, TextSize, TextSize), @@ -56034,7 +56101,7 @@ fn __action1045< __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action888( + Ok(__action889( source_code, mode, __temp0, @@ -56049,24 +56116,26 @@ fn __action1046< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::Parameter, TextSize), - __2: (TextSize, TextSize, TextSize), + __1: (TextSize, token::Tok, TextSize), + __2: (TextSize, Option>, TextSize), + __3: (TextSize, TextSize, TextSize), ) -> Result> { let __start0 = __0.0; - let __end0 = __1.2; + let __end0 = __2.2; let __temp0 = __action1022( source_code, mode, __0, __1, + __2, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action888( + Ok(__action889( source_code, mode, __temp0, - __2, + __3, )) } @@ -56077,22 +56146,30 @@ fn __action1047< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, TextSize, TextSize), + __1: (TextSize, ast::Parameter, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, token::Tok, TextSize), + __4: (TextSize, Option>, TextSize), + __5: (TextSize, TextSize, TextSize), ) -> Result> { let __start0 = __0.0; - let __end0 = __0.2; + let __end0 = __4.2; let __temp0 = __action1023( source_code, mode, __0, + __1, + __2, + __3, + __4, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action888( + Ok(__action889( source_code, mode, __temp0, - __1, + __5, )) } @@ -56103,26 +56180,28 @@ fn __action1048< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::Parameter, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), - __3: (TextSize, TextSize, TextSize), + __1: (TextSize, alloc::vec::Vec, TextSize), + __2: (TextSize, token::Tok, TextSize), + __3: (TextSize, Option>, TextSize), + __4: (TextSize, TextSize, TextSize), ) -> Result> { let __start0 = __0.0; - let __end0 = __2.2; + let __end0 = __3.2; let __temp0 = __action1024( source_code, mode, __0, __1, __2, + __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action888( + Ok(__action889( source_code, mode, __temp0, - __3, + __4, )) } @@ -56133,7 +56212,7 @@ fn __action1049< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, ast::Parameter, TextSize), __2: (TextSize, TextSize, TextSize), ) -> Result> { @@ -56146,7 +56225,7 @@ fn __action1049< __1, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action888( + Ok(__action889( source_code, mode, __temp0, @@ -56161,28 +56240,22 @@ fn __action1050< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::Parameter, TextSize), - __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, Option>, TextSize), -) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> + __1: (TextSize, TextSize, TextSize), +) -> Result> { let __start0 = __0.0; - let __end0 = __4.2; + let __end0 = __0.2; let __temp0 = __action1026( source_code, mode, __0, - __1, - __2, - __3, - __4, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action447( + Ok(__action889( source_code, mode, __temp0, + __1, )) } @@ -56193,26 +56266,26 @@ fn __action1051< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, Option>, TextSize), -) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> + __1: (TextSize, ast::Parameter, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, TextSize, TextSize), +) -> Result> { let __start0 = __0.0; - let __end0 = __3.2; + let __end0 = __2.2; let __temp0 = __action1027( source_code, mode, __0, __1, __2, - __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action447( + Ok(__action889( source_code, mode, __temp0, + __3, )) } @@ -56223,30 +56296,24 @@ fn __action1052< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::Parameter, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), - __4: (TextSize, token::Tok, TextSize), - __5: (TextSize, Option>, TextSize), -) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> + __1: (TextSize, alloc::vec::Vec, TextSize), + __2: (TextSize, TextSize, TextSize), +) -> Result> { let __start0 = __0.0; - let __end0 = __5.2; + let __end0 = __1.2; let __temp0 = __action1028( source_code, mode, __0, __1, - __2, - __3, - __4, - __5, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action447( + Ok(__action889( source_code, mode, __temp0, + __2, )) } @@ -56258,7 +56325,7 @@ fn __action1053< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), + __2: (TextSize, ast::Parameter, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, Option>, TextSize), ) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> @@ -56275,7 +56342,7 @@ fn __action1053< __4, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action447( + Ok(__action450( source_code, mode, __temp0, @@ -56290,20 +56357,22 @@ fn __action1054< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::Parameter, TextSize), + __2: (TextSize, token::Tok, TextSize), + __3: (TextSize, Option>, TextSize), ) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> { let __start0 = __0.0; - let __end0 = __2.2; + let __end0 = __3.2; let __temp0 = __action1030( source_code, mode, __0, __1, __2, + __3, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action447( + Ok(__action450( source_code, mode, __temp0, @@ -56318,18 +56387,26 @@ fn __action1055< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), + __2: (TextSize, ast::Parameter, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), + __4: (TextSize, token::Tok, TextSize), + __5: (TextSize, Option>, TextSize), ) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> { let __start0 = __0.0; - let __end0 = __1.2; + let __end0 = __5.2; let __temp0 = __action1031( source_code, mode, __0, __1, + __2, + __3, + __4, + __5, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action447( + Ok(__action450( source_code, mode, __temp0, @@ -56344,12 +56421,13 @@ fn __action1056< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::Parameter, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, token::Tok, TextSize), + __4: (TextSize, Option>, TextSize), ) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> { let __start0 = __0.0; - let __end0 = __3.2; + let __end0 = __4.2; let __temp0 = __action1032( source_code, mode, @@ -56357,9 +56435,10 @@ fn __action1056< __1, __2, __3, + __4, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action447( + Ok(__action450( source_code, mode, __temp0, @@ -56374,7 +56453,7 @@ fn __action1057< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), + __2: (TextSize, ast::Parameter, TextSize), ) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> { let __start0 = __0.0; @@ -56387,7 +56466,7 @@ fn __action1057< __2, )?; let __temp0 = (__start0, __temp0, __end0); - Ok(__action447( + Ok(__action450( source_code, mode, __temp0, @@ -56397,6 +56476,90 @@ fn __action1057< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] fn __action1058< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, token::Tok, TextSize), + __1: (TextSize, token::Tok, TextSize), +) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> +{ + let __start0 = __0.0; + let __end0 = __1.2; + let __temp0 = __action1034( + source_code, + mode, + __0, + __1, + )?; + let __temp0 = (__start0, __temp0, __end0); + Ok(__action450( + source_code, + mode, + __temp0, + )) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action1059< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, token::Tok, TextSize), + __1: (TextSize, token::Tok, TextSize), + __2: (TextSize, ast::Parameter, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), +) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> +{ + let __start0 = __0.0; + let __end0 = __3.2; + let __temp0 = __action1035( + source_code, + mode, + __0, + __1, + __2, + __3, + )?; + let __temp0 = (__start0, __temp0, __end0); + Ok(__action450( + source_code, + mode, + __temp0, + )) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action1060< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, token::Tok, TextSize), + __1: (TextSize, token::Tok, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), +) -> Result>, Vec, Option>)>,__lalrpop_util::ParseError> +{ + let __start0 = __0.0; + let __end0 = __2.2; + let __temp0 = __action1036( + source_code, + mode, + __0, + __1, + __2, + )?; + let __temp0 = (__start0, __temp0, __end0); + Ok(__action450( + source_code, + mode, + __temp0, + )) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action1061< >( source_code: &str, mode: Mode, @@ -56412,7 +56575,7 @@ fn __action1058< { let __start0 = __1.0; let __end0 = __5.2; - let __temp0 = __action1050( + let __temp0 = __action1053( source_code, mode, __1, @@ -56422,7 +56585,7 @@ fn __action1058< __5, )?; let __temp0 = (__start0, __temp0, __end0); - __action883( + __action884( source_code, mode, __0, @@ -56434,7 +56597,7 @@ fn __action1058< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1059< +fn __action1062< >( source_code: &str, mode: Mode, @@ -56449,7 +56612,7 @@ fn __action1059< { let __start0 = __1.0; let __end0 = __4.2; - let __temp0 = __action1051( + let __temp0 = __action1054( source_code, mode, __1, @@ -56458,7 +56621,7 @@ fn __action1059< __4, )?; let __temp0 = (__start0, __temp0, __end0); - __action883( + __action884( source_code, mode, __0, @@ -56470,7 +56633,7 @@ fn __action1059< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1060< +fn __action1063< >( source_code: &str, mode: Mode, @@ -56487,7 +56650,7 @@ fn __action1060< { let __start0 = __1.0; let __end0 = __6.2; - let __temp0 = __action1052( + let __temp0 = __action1055( source_code, mode, __1, @@ -56498,7 +56661,7 @@ fn __action1060< __6, )?; let __temp0 = (__start0, __temp0, __end0); - __action883( + __action884( source_code, mode, __0, @@ -56510,7 +56673,7 @@ fn __action1060< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1061< +fn __action1064< >( source_code: &str, mode: Mode, @@ -56526,7 +56689,7 @@ fn __action1061< { let __start0 = __1.0; let __end0 = __5.2; - let __temp0 = __action1053( + let __temp0 = __action1056( source_code, mode, __1, @@ -56536,7 +56699,7 @@ fn __action1061< __5, )?; let __temp0 = (__start0, __temp0, __end0); - __action883( + __action884( source_code, mode, __0, @@ -56548,7 +56711,7 @@ fn __action1061< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1062< +fn __action1065< >( source_code: &str, mode: Mode, @@ -56562,7 +56725,7 @@ fn __action1062< { let __start0 = __1.0; let __end0 = __3.2; - let __temp0 = __action1054( + let __temp0 = __action1057( source_code, mode, __1, @@ -56570,7 +56733,7 @@ fn __action1062< __3, )?; let __temp0 = (__start0, __temp0, __end0); - __action883( + __action884( source_code, mode, __0, @@ -56582,7 +56745,7 @@ fn __action1062< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1063< +fn __action1066< >( source_code: &str, mode: Mode, @@ -56595,14 +56758,14 @@ fn __action1063< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1055( + let __temp0 = __action1058( source_code, mode, __1, __2, )?; let __temp0 = (__start0, __temp0, __end0); - __action883( + __action884( source_code, mode, __0, @@ -56614,7 +56777,7 @@ fn __action1063< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1064< +fn __action1067< >( source_code: &str, mode: Mode, @@ -56629,7 +56792,7 @@ fn __action1064< { let __start0 = __1.0; let __end0 = __4.2; - let __temp0 = __action1056( + let __temp0 = __action1059( source_code, mode, __1, @@ -56638,7 +56801,7 @@ fn __action1064< __4, )?; let __temp0 = (__start0, __temp0, __end0); - __action883( + __action884( source_code, mode, __0, @@ -56650,7 +56813,7 @@ fn __action1064< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1065< +fn __action1068< >( source_code: &str, mode: Mode, @@ -56664,7 +56827,7 @@ fn __action1065< { let __start0 = __1.0; let __end0 = __3.2; - let __temp0 = __action1057( + let __temp0 = __action1060( source_code, mode, __1, @@ -56672,7 +56835,7 @@ fn __action1065< __3, )?; let __temp0 = (__start0, __temp0, __end0); - __action883( + __action884( source_code, mode, __0, @@ -56684,7 +56847,7 @@ fn __action1065< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1066< +fn __action1069< >( source_code: &str, mode: Mode, @@ -56695,14 +56858,14 @@ fn __action1066< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action448( + let __temp0 = __action451( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action883( + __action884( source_code, mode, __0, @@ -56714,7 +56877,7 @@ fn __action1066< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1067< +fn __action1070< >( source_code: &str, mode: Mode, @@ -56729,7 +56892,7 @@ fn __action1067< { let __start0 = __1.0; let __end0 = __5.2; - let __temp0 = __action1050( + let __temp0 = __action1053( source_code, mode, __1, @@ -56739,7 +56902,7 @@ fn __action1067< __5, )?; let __temp0 = (__start0, __temp0, __end0); - __action884( + __action885( source_code, mode, __0, @@ -56750,7 +56913,7 @@ fn __action1067< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1068< +fn __action1071< >( source_code: &str, mode: Mode, @@ -56764,7 +56927,7 @@ fn __action1068< { let __start0 = __1.0; let __end0 = __4.2; - let __temp0 = __action1051( + let __temp0 = __action1054( source_code, mode, __1, @@ -56773,7 +56936,7 @@ fn __action1068< __4, )?; let __temp0 = (__start0, __temp0, __end0); - __action884( + __action885( source_code, mode, __0, @@ -56784,7 +56947,7 @@ fn __action1068< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1069< +fn __action1072< >( source_code: &str, mode: Mode, @@ -56800,7 +56963,7 @@ fn __action1069< { let __start0 = __1.0; let __end0 = __6.2; - let __temp0 = __action1052( + let __temp0 = __action1055( source_code, mode, __1, @@ -56811,7 +56974,7 @@ fn __action1069< __6, )?; let __temp0 = (__start0, __temp0, __end0); - __action884( + __action885( source_code, mode, __0, @@ -56822,7 +56985,7 @@ fn __action1069< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1070< +fn __action1073< >( source_code: &str, mode: Mode, @@ -56837,7 +57000,7 @@ fn __action1070< { let __start0 = __1.0; let __end0 = __5.2; - let __temp0 = __action1053( + let __temp0 = __action1056( source_code, mode, __1, @@ -56847,7 +57010,7 @@ fn __action1070< __5, )?; let __temp0 = (__start0, __temp0, __end0); - __action884( + __action885( source_code, mode, __0, @@ -56858,7 +57021,7 @@ fn __action1070< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1071< +fn __action1074< >( source_code: &str, mode: Mode, @@ -56871,7 +57034,7 @@ fn __action1071< { let __start0 = __1.0; let __end0 = __3.2; - let __temp0 = __action1054( + let __temp0 = __action1057( source_code, mode, __1, @@ -56879,7 +57042,7 @@ fn __action1071< __3, )?; let __temp0 = (__start0, __temp0, __end0); - __action884( + __action885( source_code, mode, __0, @@ -56890,7 +57053,7 @@ fn __action1071< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1072< +fn __action1075< >( source_code: &str, mode: Mode, @@ -56902,14 +57065,14 @@ fn __action1072< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1055( + let __temp0 = __action1058( source_code, mode, __1, __2, )?; let __temp0 = (__start0, __temp0, __end0); - __action884( + __action885( source_code, mode, __0, @@ -56920,7 +57083,7 @@ fn __action1072< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1073< +fn __action1076< >( source_code: &str, mode: Mode, @@ -56934,7 +57097,7 @@ fn __action1073< { let __start0 = __1.0; let __end0 = __4.2; - let __temp0 = __action1056( + let __temp0 = __action1059( source_code, mode, __1, @@ -56943,7 +57106,7 @@ fn __action1073< __4, )?; let __temp0 = (__start0, __temp0, __end0); - __action884( + __action885( source_code, mode, __0, @@ -56954,7 +57117,7 @@ fn __action1073< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1074< +fn __action1077< >( source_code: &str, mode: Mode, @@ -56967,7 +57130,7 @@ fn __action1074< { let __start0 = __1.0; let __end0 = __3.2; - let __temp0 = __action1057( + let __temp0 = __action1060( source_code, mode, __1, @@ -56975,7 +57138,7 @@ fn __action1074< __3, )?; let __temp0 = (__start0, __temp0, __end0); - __action884( + __action885( source_code, mode, __0, @@ -56986,7 +57149,7 @@ fn __action1074< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1075< +fn __action1078< >( source_code: &str, mode: Mode, @@ -56996,14 +57159,14 @@ fn __action1075< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action448( + let __temp0 = __action451( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action884( + __action885( source_code, mode, __0, @@ -57014,7 +57177,7 @@ fn __action1075< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1076< +fn __action1079< >( source_code: &str, mode: Mode, @@ -57024,14 +57187,14 @@ fn __action1076< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action375( + let __temp0 = __action378( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action373( + __action376( source_code, mode, __temp0, @@ -57040,7 +57203,7 @@ fn __action1076< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1077< +fn __action1080< >( source_code: &str, mode: Mode, @@ -57053,14 +57216,14 @@ fn __action1077< { let __start0 = __2.0; let __end0 = __3.2; - let __temp0 = __action1076( + let __temp0 = __action1079( source_code, mode, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action731( + __action734( source_code, mode, __0, @@ -57072,7 +57235,7 @@ fn __action1077< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1078< +fn __action1081< >( source_code: &str, mode: Mode, @@ -57083,14 +57246,14 @@ fn __action1078< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action374( + let __temp0 = __action377( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action731( + __action734( source_code, mode, __0, @@ -57102,7 +57265,7 @@ fn __action1078< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1079< +fn __action1082< >( source_code: &str, mode: Mode, @@ -57112,14 +57275,14 @@ fn __action1079< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action568( + let __temp0 = __action571( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action578( + __action581( source_code, mode, __temp0, @@ -57128,7 +57291,7 @@ fn __action1079< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1080< +fn __action1083< >( source_code: &str, mode: Mode, @@ -57139,14 +57302,14 @@ fn __action1080< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action568( + let __temp0 = __action571( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action579( + __action582( source_code, mode, __0, @@ -57156,7 +57319,7 @@ fn __action1080< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1081< +fn __action1084< >( source_code: &str, mode: Mode, @@ -57170,14 +57333,14 @@ fn __action1081< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action566( + let __temp0 = __action569( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action739( + __action741( source_code, mode, __0, @@ -57192,7 +57355,7 @@ fn __action1081< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1082< +fn __action1085< >( source_code: &str, mode: Mode, @@ -57207,13 +57370,13 @@ fn __action1082< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action567( + let __temp0 = __action570( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action739( + __action741( source_code, mode, __0, @@ -57228,7 +57391,7 @@ fn __action1082< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1083< +fn __action1086< >( source_code: &str, mode: Mode, @@ -57241,14 +57404,14 @@ fn __action1083< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action566( + let __temp0 = __action569( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action740( + __action742( source_code, mode, __0, @@ -57262,7 +57425,7 @@ fn __action1083< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1084< +fn __action1087< >( source_code: &str, mode: Mode, @@ -57276,13 +57439,13 @@ fn __action1084< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action567( + let __temp0 = __action570( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action740( + __action742( source_code, mode, __0, @@ -57296,7 +57459,7 @@ fn __action1084< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1085< +fn __action1088< >( source_code: &str, mode: Mode, @@ -57310,14 +57473,14 @@ fn __action1085< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action566( + let __temp0 = __action569( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action758( + __action759( source_code, mode, __0, @@ -57332,7 +57495,7 @@ fn __action1085< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1086< +fn __action1089< >( source_code: &str, mode: Mode, @@ -57347,13 +57510,13 @@ fn __action1086< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action567( + let __temp0 = __action570( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action758( + __action759( source_code, mode, __0, @@ -57368,7 +57531,7 @@ fn __action1086< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1087< +fn __action1090< >( source_code: &str, mode: Mode, @@ -57381,14 +57544,14 @@ fn __action1087< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action566( + let __temp0 = __action569( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action759( + __action760( source_code, mode, __0, @@ -57402,7 +57565,7 @@ fn __action1087< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1088< +fn __action1091< >( source_code: &str, mode: Mode, @@ -57416,13 +57579,13 @@ fn __action1088< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action567( + let __temp0 = __action570( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action759( + __action760( source_code, mode, __0, @@ -57436,7 +57599,7 @@ fn __action1088< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1089< +fn __action1092< >( source_code: &str, mode: Mode, @@ -57446,14 +57609,14 @@ fn __action1089< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action316( + let __temp0 = __action321( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action310( + __action315( source_code, mode, __temp0, @@ -57462,7 +57625,7 @@ fn __action1089< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1090< +fn __action1093< >( source_code: &str, mode: Mode, @@ -57473,14 +57636,14 @@ fn __action1090< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action316( + let __temp0 = __action321( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action311( + __action316( source_code, mode, __0, @@ -57490,7 +57653,7 @@ fn __action1090< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1091< +fn __action1094< >( source_code: &str, mode: Mode, @@ -57503,14 +57666,14 @@ fn __action1091< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action314( + let __temp0 = __action319( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action666( + __action669( source_code, mode, __0, @@ -57524,7 +57687,7 @@ fn __action1091< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1092< +fn __action1095< >( source_code: &str, mode: Mode, @@ -57538,13 +57701,13 @@ fn __action1092< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action315( + let __temp0 = __action320( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action666( + __action669( source_code, mode, __0, @@ -57558,7 +57721,7 @@ fn __action1092< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1093< +fn __action1096< >( source_code: &str, mode: Mode, @@ -57570,14 +57733,14 @@ fn __action1093< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action314( + let __temp0 = __action319( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action667( + __action670( source_code, mode, __0, @@ -57590,7 +57753,7 @@ fn __action1093< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1094< +fn __action1097< >( source_code: &str, mode: Mode, @@ -57603,13 +57766,13 @@ fn __action1094< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action315( + let __temp0 = __action320( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action667( + __action670( source_code, mode, __0, @@ -57622,7 +57785,7 @@ fn __action1094< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1095< +fn __action1098< >( source_code: &str, mode: Mode, @@ -57632,14 +57795,14 @@ fn __action1095< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action303( + let __temp0 = __action308( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action301( + __action306( source_code, mode, __temp0, @@ -57648,7 +57811,7 @@ fn __action1095< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1096< +fn __action1099< >( source_code: &str, mode: Mode, @@ -57666,14 +57829,14 @@ fn __action1096< { let __start0 = __6.0; let __end0 = __7.2; - let __temp0 = __action1095( + let __temp0 = __action1098( source_code, mode, __6, __7, ); let __temp0 = (__start0, __temp0, __end0); - __action814( + __action815( source_code, mode, __0, @@ -57690,7 +57853,7 @@ fn __action1096< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1097< +fn __action1100< >( source_code: &str, mode: Mode, @@ -57706,14 +57869,14 @@ fn __action1097< { let __start0 = __5.2; let __end0 = __6.0; - let __temp0 = __action302( + let __temp0 = __action307( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action814( + __action815( source_code, mode, __0, @@ -57730,7 +57893,7 @@ fn __action1097< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1098< +fn __action1101< >( source_code: &str, mode: Mode, @@ -57747,14 +57910,14 @@ fn __action1098< { let __start0 = __5.0; let __end0 = __6.2; - let __temp0 = __action1095( + let __temp0 = __action1098( source_code, mode, __5, __6, ); let __temp0 = (__start0, __temp0, __end0); - __action815( + __action816( source_code, mode, __0, @@ -57770,7 +57933,7 @@ fn __action1098< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1099< +fn __action1102< >( source_code: &str, mode: Mode, @@ -57785,14 +57948,14 @@ fn __action1099< { let __start0 = __4.2; let __end0 = __5.0; - let __temp0 = __action302( + let __temp0 = __action307( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action815( + __action816( source_code, mode, __0, @@ -57808,7 +57971,7 @@ fn __action1099< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1100< +fn __action1103< >( source_code: &str, mode: Mode, @@ -57818,14 +57981,14 @@ fn __action1100< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action380( + let __temp0 = __action383( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action378( + __action381( source_code, mode, __temp0, @@ -57834,7 +57997,7 @@ fn __action1100< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1101< +fn __action1104< >( source_code: &str, mode: Mode, @@ -57845,14 +58008,14 @@ fn __action1101< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action380( + let __temp0 = __action383( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action379( + __action382( source_code, mode, __0, @@ -57862,7 +58025,7 @@ fn __action1101< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1102< +fn __action1105< >( source_code: &str, mode: Mode, @@ -57872,14 +58035,14 @@ fn __action1102< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action293( + let __temp0 = __action298( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action291( + __action296( source_code, mode, __temp0, @@ -57888,7 +58051,7 @@ fn __action1102< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1103< +fn __action1106< >( source_code: &str, mode: Mode, @@ -57900,14 +58063,14 @@ fn __action1103< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1102( + let __temp0 = __action1105( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action790( + __action791( source_code, mode, __0, @@ -57918,7 +58081,7 @@ fn __action1103< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1104< +fn __action1107< >( source_code: &str, mode: Mode, @@ -57928,14 +58091,14 @@ fn __action1104< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action292( + let __temp0 = __action297( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action790( + __action791( source_code, mode, __0, @@ -57946,7 +58109,7 @@ fn __action1104< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1105< +fn __action1108< >( source_code: &str, mode: Mode, @@ -57958,14 +58121,14 @@ fn __action1105< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1102( + let __temp0 = __action1105( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action950( + __action953( source_code, mode, __0, @@ -57976,7 +58139,7 @@ fn __action1105< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1106< +fn __action1109< >( source_code: &str, mode: Mode, @@ -57986,14 +58149,14 @@ fn __action1106< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action292( + let __temp0 = __action297( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action950( + __action953( source_code, mode, __0, @@ -58004,7 +58167,7 @@ fn __action1106< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1107< +fn __action1110< >( source_code: &str, mode: Mode, @@ -58016,14 +58179,14 @@ fn __action1107< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1102( + let __temp0 = __action1105( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action955( + __action958( source_code, mode, __0, @@ -58034,7 +58197,7 @@ fn __action1107< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1108< +fn __action1111< >( source_code: &str, mode: Mode, @@ -58044,14 +58207,14 @@ fn __action1108< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action292( + let __temp0 = __action297( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action955( + __action958( source_code, mode, __0, @@ -58062,7 +58225,7 @@ fn __action1108< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1109< +fn __action1112< >( source_code: &str, mode: Mode, @@ -58072,14 +58235,14 @@ fn __action1109< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action290( + let __temp0 = __action295( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action288( + __action293( source_code, mode, __temp0, @@ -58088,7 +58251,7 @@ fn __action1109< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1110< +fn __action1113< >( source_code: &str, mode: Mode, @@ -58100,14 +58263,14 @@ fn __action1110< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1109( + let __temp0 = __action1112( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action932( + __action933( source_code, mode, __0, @@ -58118,7 +58281,7 @@ fn __action1110< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1111< +fn __action1114< >( source_code: &str, mode: Mode, @@ -58128,14 +58291,14 @@ fn __action1111< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action289( + let __temp0 = __action294( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action932( + __action933( source_code, mode, __0, @@ -58146,7 +58309,7 @@ fn __action1111< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1112< +fn __action1115< >( source_code: &str, mode: Mode, @@ -58155,13 +58318,13 @@ fn __action1112< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action370( + let __temp0 = __action373( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action368( + __action371( source_code, mode, __temp0, @@ -58170,7 +58333,7 @@ fn __action1112< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1113< +fn __action1116< >( source_code: &str, mode: Mode, @@ -58180,13 +58343,13 @@ fn __action1113< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action370( + let __temp0 = __action373( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action369( + __action372( source_code, mode, __0, @@ -58196,7 +58359,7 @@ fn __action1113< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1114< +fn __action1117< >( source_code: &str, mode: Mode, @@ -58205,13 +58368,13 @@ fn __action1114< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action412( + let __temp0 = __action415( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action415( + __action418( source_code, mode, __temp0, @@ -58220,7 +58383,7 @@ fn __action1114< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1115< +fn __action1118< >( source_code: &str, mode: Mode, @@ -58230,13 +58393,13 @@ fn __action1115< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action412( + let __temp0 = __action415( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action416( + __action419( source_code, mode, __0, @@ -58246,7 +58409,7 @@ fn __action1115< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1116< +fn __action1119< >( source_code: &str, mode: Mode, @@ -58257,14 +58420,14 @@ fn __action1116< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action410( + let __temp0 = __action413( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action944( + __action947( source_code, mode, __0, @@ -58276,7 +58439,7 @@ fn __action1116< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1117< +fn __action1120< >( source_code: &str, mode: Mode, @@ -58288,13 +58451,13 @@ fn __action1117< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action411( + let __temp0 = __action414( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action944( + __action947( source_code, mode, __0, @@ -58306,7 +58469,7 @@ fn __action1117< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1118< +fn __action1121< >( source_code: &str, mode: Mode, @@ -58316,14 +58479,14 @@ fn __action1118< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action423( + let __temp0 = __action426( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action421( + __action424( source_code, mode, __temp0, @@ -58332,7 +58495,7 @@ fn __action1118< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1119< +fn __action1122< >( source_code: &str, mode: Mode, @@ -58344,14 +58507,14 @@ fn __action1119< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1118( + let __temp0 = __action1121( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action827( + __action828( source_code, mode, __0, @@ -58362,7 +58525,7 @@ fn __action1119< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1120< +fn __action1123< >( source_code: &str, mode: Mode, @@ -58372,14 +58535,14 @@ fn __action1120< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action422( + let __temp0 = __action425( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action827( + __action828( source_code, mode, __0, @@ -58390,7 +58553,7 @@ fn __action1120< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1121< +fn __action1124< >( source_code: &str, mode: Mode, @@ -58402,14 +58565,14 @@ fn __action1121< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1118( + let __temp0 = __action1121( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action828( + __action829( source_code, mode, __0, @@ -58420,7 +58583,7 @@ fn __action1121< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1122< +fn __action1125< >( source_code: &str, mode: Mode, @@ -58430,14 +58593,14 @@ fn __action1122< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action422( + let __temp0 = __action425( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action828( + __action829( source_code, mode, __0, @@ -58448,7 +58611,7 @@ fn __action1122< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1123< +fn __action1126< >( source_code: &str, mode: Mode, @@ -58459,7 +58622,7 @@ fn __action1123< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action336( + let __temp0 = __action341( source_code, mode, __0, @@ -58467,7 +58630,7 @@ fn __action1123< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action334( + __action339( source_code, mode, __temp0, @@ -58476,7 +58639,7 @@ fn __action1123< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1124< +fn __action1127< >( source_code: &str, mode: Mode, @@ -58494,7 +58657,7 @@ fn __action1124< { let __start0 = __7.0; let __end0 = __9.2; - let __temp0 = __action1123( + let __temp0 = __action1126( source_code, mode, __7, @@ -58502,7 +58665,7 @@ fn __action1124< __9, ); let __temp0 = (__start0, __temp0, __end0); - __action812( + __action813( source_code, mode, __0, @@ -58518,7 +58681,7 @@ fn __action1124< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1125< +fn __action1128< >( source_code: &str, mode: Mode, @@ -58533,14 +58696,14 @@ fn __action1125< { let __start0 = __6.2; let __end0 = __6.2; - let __temp0 = __action335( + let __temp0 = __action340( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action812( + __action813( source_code, mode, __0, @@ -58556,7 +58719,7 @@ fn __action1125< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1126< +fn __action1129< >( source_code: &str, mode: Mode, @@ -58573,7 +58736,7 @@ fn __action1126< { let __start0 = __6.0; let __end0 = __8.2; - let __temp0 = __action1123( + let __temp0 = __action1126( source_code, mode, __6, @@ -58581,7 +58744,7 @@ fn __action1126< __8, ); let __temp0 = (__start0, __temp0, __end0); - __action813( + __action814( source_code, mode, __0, @@ -58596,7 +58759,7 @@ fn __action1126< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1127< +fn __action1130< >( source_code: &str, mode: Mode, @@ -58610,14 +58773,14 @@ fn __action1127< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action335( + let __temp0 = __action340( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action813( + __action814( source_code, mode, __0, @@ -58632,7 +58795,7 @@ fn __action1127< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1128< +fn __action1131< >( source_code: &str, mode: Mode, @@ -58649,7 +58812,7 @@ fn __action1128< { let __start0 = __4.0; let __end0 = __6.2; - let __temp0 = __action1123( + let __temp0 = __action1126( source_code, mode, __4, @@ -58657,7 +58820,7 @@ fn __action1128< __6, ); let __temp0 = (__start0, __temp0, __end0); - __action945( + __action948( source_code, mode, __0, @@ -58672,7 +58835,7 @@ fn __action1128< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1129< +fn __action1132< >( source_code: &str, mode: Mode, @@ -58686,14 +58849,14 @@ fn __action1129< { let __start0 = __3.2; let __end0 = __4.0; - let __temp0 = __action335( + let __temp0 = __action340( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action945( + __action948( source_code, mode, __0, @@ -58708,7 +58871,7 @@ fn __action1129< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1130< +fn __action1133< >( source_code: &str, mode: Mode, @@ -58725,7 +58888,7 @@ fn __action1130< { let __start0 = __4.0; let __end0 = __6.2; - let __temp0 = __action1123( + let __temp0 = __action1126( source_code, mode, __4, @@ -58733,7 +58896,7 @@ fn __action1130< __6, ); let __temp0 = (__start0, __temp0, __end0); - __action946( + __action949( source_code, mode, __0, @@ -58748,7 +58911,7 @@ fn __action1130< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1131< +fn __action1134< >( source_code: &str, mode: Mode, @@ -58762,14 +58925,14 @@ fn __action1131< { let __start0 = __3.2; let __end0 = __4.0; - let __temp0 = __action335( + let __temp0 = __action340( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action946( + __action949( source_code, mode, __0, @@ -58784,7 +58947,7 @@ fn __action1131< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1132< +fn __action1135< >( source_code: &str, mode: Mode, @@ -58799,7 +58962,7 @@ fn __action1132< { let __start0 = __4.0; let __end0 = __6.2; - let __temp0 = __action1123( + let __temp0 = __action1126( source_code, mode, __4, @@ -58807,7 +58970,7 @@ fn __action1132< __6, ); let __temp0 = (__start0, __temp0, __end0); - __action958( + __action961( source_code, mode, __0, @@ -58820,7 +58983,7 @@ fn __action1132< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1133< +fn __action1136< >( source_code: &str, mode: Mode, @@ -58832,14 +58995,14 @@ fn __action1133< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action335( + let __temp0 = __action340( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action958( + __action961( source_code, mode, __0, @@ -58852,7 +59015,7 @@ fn __action1133< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1134< +fn __action1137< >( source_code: &str, mode: Mode, @@ -58863,7 +59026,7 @@ fn __action1134< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action329( + let __temp0 = __action334( source_code, mode, __0, @@ -58871,7 +59034,7 @@ fn __action1134< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action327( + __action332( source_code, mode, __temp0, @@ -58880,7 +59043,7 @@ fn __action1134< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1135< +fn __action1138< >( source_code: &str, mode: Mode, @@ -58894,7 +59057,7 @@ fn __action1135< { let __start0 = __3.0; let __end0 = __5.2; - let __temp0 = __action329( + let __temp0 = __action334( source_code, mode, __3, @@ -58902,7 +59065,7 @@ fn __action1135< __5, ); let __temp0 = (__start0, __temp0, __end0); - __action947( + __action950( source_code, mode, __0, @@ -58914,7 +59077,7 @@ fn __action1135< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1136< +fn __action1139< >( source_code: &str, mode: Mode, @@ -58933,7 +59096,7 @@ fn __action1136< { let __start0 = __7.0; let __end0 = __9.2; - let __temp0 = __action1134( + let __temp0 = __action1137( source_code, mode, __7, @@ -58941,7 +59104,7 @@ fn __action1136< __9, ); let __temp0 = (__start0, __temp0, __end0); - __action1128( + __action1131( source_code, mode, __0, @@ -58958,7 +59121,7 @@ fn __action1136< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1137< +fn __action1140< >( source_code: &str, mode: Mode, @@ -58974,14 +59137,14 @@ fn __action1137< { let __start0 = __6.2; let __end0 = __7.0; - let __temp0 = __action328( + let __temp0 = __action333( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1128( + __action1131( source_code, mode, __0, @@ -58998,7 +59161,7 @@ fn __action1137< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1138< +fn __action1141< >( source_code: &str, mode: Mode, @@ -59014,7 +59177,7 @@ fn __action1138< { let __start0 = __4.0; let __end0 = __6.2; - let __temp0 = __action1134( + let __temp0 = __action1137( source_code, mode, __4, @@ -59022,7 +59185,7 @@ fn __action1138< __6, ); let __temp0 = (__start0, __temp0, __end0); - __action1129( + __action1132( source_code, mode, __0, @@ -59036,7 +59199,7 @@ fn __action1138< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1139< +fn __action1142< >( source_code: &str, mode: Mode, @@ -59049,14 +59212,14 @@ fn __action1139< { let __start0 = __3.2; let __end0 = __4.0; - let __temp0 = __action328( + let __temp0 = __action333( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1129( + __action1132( source_code, mode, __0, @@ -59070,7 +59233,7 @@ fn __action1139< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1140< +fn __action1143< >( source_code: &str, mode: Mode, @@ -59089,7 +59252,7 @@ fn __action1140< { let __start0 = __7.0; let __end0 = __9.2; - let __temp0 = __action1134( + let __temp0 = __action1137( source_code, mode, __7, @@ -59097,7 +59260,7 @@ fn __action1140< __9, ); let __temp0 = (__start0, __temp0, __end0); - __action1130( + __action1133( source_code, mode, __0, @@ -59114,7 +59277,7 @@ fn __action1140< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1141< +fn __action1144< >( source_code: &str, mode: Mode, @@ -59130,14 +59293,14 @@ fn __action1141< { let __start0 = __6.2; let __end0 = __7.0; - let __temp0 = __action328( + let __temp0 = __action333( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1130( + __action1133( source_code, mode, __0, @@ -59154,7 +59317,7 @@ fn __action1141< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1142< +fn __action1145< >( source_code: &str, mode: Mode, @@ -59170,7 +59333,7 @@ fn __action1142< { let __start0 = __4.0; let __end0 = __6.2; - let __temp0 = __action1134( + let __temp0 = __action1137( source_code, mode, __4, @@ -59178,7 +59341,7 @@ fn __action1142< __6, ); let __temp0 = (__start0, __temp0, __end0); - __action1131( + __action1134( source_code, mode, __0, @@ -59192,7 +59355,7 @@ fn __action1142< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1143< +fn __action1146< >( source_code: &str, mode: Mode, @@ -59205,14 +59368,14 @@ fn __action1143< { let __start0 = __3.2; let __end0 = __4.0; - let __temp0 = __action328( + let __temp0 = __action333( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1131( + __action1134( source_code, mode, __0, @@ -59226,7 +59389,7 @@ fn __action1143< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1144< +fn __action1147< >( source_code: &str, mode: Mode, @@ -59236,14 +59399,14 @@ fn __action1144< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action395( + let __temp0 = __action398( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action393( + __action396( source_code, mode, __temp0, @@ -59252,7 +59415,7 @@ fn __action1144< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1145< +fn __action1148< >( source_code: &str, mode: Mode, @@ -59265,14 +59428,14 @@ fn __action1145< { let __start0 = __2.0; let __end0 = __3.2; - let __temp0 = __action1144( + let __temp0 = __action1147( source_code, mode, __2, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action918( + __action919( source_code, mode, __0, @@ -59284,7 +59447,7 @@ fn __action1145< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1146< +fn __action1149< >( source_code: &str, mode: Mode, @@ -59295,14 +59458,14 @@ fn __action1146< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action394( + let __temp0 = __action397( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action918( + __action919( source_code, mode, __0, @@ -59314,7 +59477,7 @@ fn __action1146< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1147< +fn __action1150< >( source_code: &str, mode: Mode, @@ -59326,7 +59489,7 @@ fn __action1147< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action720( + let __temp0 = __action723( source_code, mode, __0, @@ -59335,7 +59498,7 @@ fn __action1147< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action430( + __action433( source_code, mode, __temp0, @@ -59344,7 +59507,7 @@ fn __action1147< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1148< +fn __action1151< >( source_code: &str, mode: Mode, @@ -59357,7 +59520,7 @@ fn __action1148< { let __start0 = __1.0; let __end0 = __4.2; - let __temp0 = __action720( + let __temp0 = __action723( source_code, mode, __1, @@ -59366,7 +59529,7 @@ fn __action1148< __4, ); let __temp0 = (__start0, __temp0, __end0); - __action431( + __action434( source_code, mode, __0, @@ -59376,7 +59539,7 @@ fn __action1148< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1149< +fn __action1152< >( source_code: &str, mode: Mode, @@ -59389,14 +59552,14 @@ fn __action1149< { let __start0 = __3.2; let __end0 = __4.0; - let __temp0 = __action340( + let __temp0 = __action345( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action826( + __action827( source_code, mode, __0, @@ -59410,7 +59573,7 @@ fn __action1149< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1150< +fn __action1153< >( source_code: &str, mode: Mode, @@ -59424,13 +59587,13 @@ fn __action1150< { let __start0 = __4.0; let __end0 = __4.2; - let __temp0 = __action341( + let __temp0 = __action346( source_code, mode, __4, ); let __temp0 = (__start0, __temp0, __end0); - __action826( + __action827( source_code, mode, __0, @@ -59444,7 +59607,7 @@ fn __action1150< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1151< +fn __action1154< >( source_code: &str, mode: Mode, @@ -59455,7 +59618,7 @@ fn __action1151< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action721( + let __temp0 = __action724( source_code, mode, __0, @@ -59463,7 +59626,7 @@ fn __action1151< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action337( + __action342( source_code, mode, __temp0, @@ -59472,7 +59635,7 @@ fn __action1151< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1152< +fn __action1155< >( source_code: &str, mode: Mode, @@ -59487,7 +59650,7 @@ fn __action1152< { let __start0 = __4.0; let __end0 = __6.2; - let __temp0 = __action1151( + let __temp0 = __action1154( source_code, mode, __4, @@ -59495,7 +59658,7 @@ fn __action1152< __6, ); let __temp0 = (__start0, __temp0, __end0); - __action1149( + __action1152( source_code, mode, __0, @@ -59508,7 +59671,7 @@ fn __action1152< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1153< +fn __action1156< >( source_code: &str, mode: Mode, @@ -59520,14 +59683,14 @@ fn __action1153< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action338( + let __temp0 = __action343( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1149( + __action1152( source_code, mode, __0, @@ -59540,7 +59703,7 @@ fn __action1153< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1154< +fn __action1157< >( source_code: &str, mode: Mode, @@ -59556,7 +59719,7 @@ fn __action1154< { let __start0 = __5.0; let __end0 = __7.2; - let __temp0 = __action1151( + let __temp0 = __action1154( source_code, mode, __5, @@ -59564,7 +59727,7 @@ fn __action1154< __7, ); let __temp0 = (__start0, __temp0, __end0); - __action1150( + __action1153( source_code, mode, __0, @@ -59578,7 +59741,7 @@ fn __action1154< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1155< +fn __action1158< >( source_code: &str, mode: Mode, @@ -59591,14 +59754,14 @@ fn __action1155< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action338( + let __temp0 = __action343( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1150( + __action1153( source_code, mode, __0, @@ -59612,7 +59775,7 @@ fn __action1155< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1156< +fn __action1159< >( source_code: &str, mode: Mode, @@ -59622,14 +59785,14 @@ fn __action1156< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action459( + let __temp0 = __action462( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action457( + __action460( source_code, mode, __temp0, @@ -59638,7 +59801,7 @@ fn __action1156< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1157< +fn __action1160< >( source_code: &str, mode: Mode, @@ -59649,14 +59812,14 @@ fn __action1157< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action459( + let __temp0 = __action462( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action458( + __action461( source_code, mode, __0, @@ -59666,7 +59829,7 @@ fn __action1157< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1158< +fn __action1161< >( source_code: &str, mode: Mode, @@ -59676,14 +59839,14 @@ fn __action1158< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action468( + let __temp0 = __action471( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action469( + __action472( source_code, mode, __temp0, @@ -59692,7 +59855,7 @@ fn __action1158< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1159< +fn __action1162< >( source_code: &str, mode: Mode, @@ -59703,14 +59866,14 @@ fn __action1159< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action468( + let __temp0 = __action471( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action470( + __action473( source_code, mode, __0, @@ -59720,7 +59883,7 @@ fn __action1159< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1160< +fn __action1163< >( source_code: &str, mode: Mode, @@ -59729,14 +59892,14 @@ fn __action1160< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action466( + let __temp0 = __action469( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action249( + __action252( source_code, mode, __temp0, @@ -59746,7 +59909,7 @@ fn __action1160< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1161< +fn __action1164< >( source_code: &str, mode: Mode, @@ -59756,13 +59919,13 @@ fn __action1161< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action467( + let __temp0 = __action470( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action249( + __action252( source_code, mode, __temp0, @@ -59772,7 +59935,7 @@ fn __action1161< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1162< +fn __action1165< >( source_code: &str, mode: Mode, @@ -59782,14 +59945,14 @@ fn __action1162< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action473( + let __temp0 = __action476( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action471( + __action474( source_code, mode, __temp0, @@ -59798,7 +59961,7 @@ fn __action1162< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1163< +fn __action1166< >( source_code: &str, mode: Mode, @@ -59809,14 +59972,14 @@ fn __action1163< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action473( + let __temp0 = __action476( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action472( + __action475( source_code, mode, __0, @@ -59826,7 +59989,7 @@ fn __action1163< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1164< +fn __action1167< >( source_code: &str, mode: Mode, @@ -59836,14 +59999,14 @@ fn __action1164< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action571( + let __temp0 = __action574( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action569( + __action572( source_code, mode, __temp0, @@ -59852,7 +60015,7 @@ fn __action1164< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1165< +fn __action1168< >( source_code: &str, mode: Mode, @@ -59867,14 +60030,14 @@ fn __action1165< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1164( + let __temp0 = __action1167( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1081( + __action1084( source_code, mode, __0, @@ -59888,7 +60051,7 @@ fn __action1165< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1166< +fn __action1169< >( source_code: &str, mode: Mode, @@ -59901,14 +60064,14 @@ fn __action1166< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action570( + let __temp0 = __action573( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1081( + __action1084( source_code, mode, __0, @@ -59922,7 +60085,7 @@ fn __action1166< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1167< +fn __action1170< >( source_code: &str, mode: Mode, @@ -59938,14 +60101,14 @@ fn __action1167< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1164( + let __temp0 = __action1167( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1082( + __action1085( source_code, mode, __0, @@ -59960,7 +60123,7 @@ fn __action1167< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1168< +fn __action1171< >( source_code: &str, mode: Mode, @@ -59974,14 +60137,14 @@ fn __action1168< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action570( + let __temp0 = __action573( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1082( + __action1085( source_code, mode, __0, @@ -59996,7 +60159,7 @@ fn __action1168< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1169< +fn __action1172< >( source_code: &str, mode: Mode, @@ -60010,14 +60173,14 @@ fn __action1169< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1164( + let __temp0 = __action1167( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1083( + __action1086( source_code, mode, __0, @@ -60030,7 +60193,7 @@ fn __action1169< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1170< +fn __action1173< >( source_code: &str, mode: Mode, @@ -60042,14 +60205,14 @@ fn __action1170< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action570( + let __temp0 = __action573( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1083( + __action1086( source_code, mode, __0, @@ -60062,7 +60225,7 @@ fn __action1170< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1171< +fn __action1174< >( source_code: &str, mode: Mode, @@ -60077,14 +60240,14 @@ fn __action1171< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1164( + let __temp0 = __action1167( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1084( + __action1087( source_code, mode, __0, @@ -60098,7 +60261,7 @@ fn __action1171< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1172< +fn __action1175< >( source_code: &str, mode: Mode, @@ -60111,14 +60274,14 @@ fn __action1172< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action570( + let __temp0 = __action573( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1084( + __action1087( source_code, mode, __0, @@ -60132,7 +60295,7 @@ fn __action1172< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1173< +fn __action1176< >( source_code: &str, mode: Mode, @@ -60147,14 +60310,14 @@ fn __action1173< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1164( + let __temp0 = __action1167( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1085( + __action1088( source_code, mode, __0, @@ -60168,7 +60331,7 @@ fn __action1173< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1174< +fn __action1177< >( source_code: &str, mode: Mode, @@ -60181,14 +60344,14 @@ fn __action1174< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action570( + let __temp0 = __action573( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1085( + __action1088( source_code, mode, __0, @@ -60202,7 +60365,7 @@ fn __action1174< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1175< +fn __action1178< >( source_code: &str, mode: Mode, @@ -60218,14 +60381,14 @@ fn __action1175< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1164( + let __temp0 = __action1167( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1086( + __action1089( source_code, mode, __0, @@ -60240,7 +60403,7 @@ fn __action1175< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1176< +fn __action1179< >( source_code: &str, mode: Mode, @@ -60254,14 +60417,14 @@ fn __action1176< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action570( + let __temp0 = __action573( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1086( + __action1089( source_code, mode, __0, @@ -60276,7 +60439,7 @@ fn __action1176< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1177< +fn __action1180< >( source_code: &str, mode: Mode, @@ -60290,14 +60453,14 @@ fn __action1177< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1164( + let __temp0 = __action1167( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1087( + __action1090( source_code, mode, __0, @@ -60310,7 +60473,7 @@ fn __action1177< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1178< +fn __action1181< >( source_code: &str, mode: Mode, @@ -60322,14 +60485,14 @@ fn __action1178< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action570( + let __temp0 = __action573( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1087( + __action1090( source_code, mode, __0, @@ -60342,7 +60505,7 @@ fn __action1178< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1179< +fn __action1182< >( source_code: &str, mode: Mode, @@ -60357,14 +60520,14 @@ fn __action1179< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1164( + let __temp0 = __action1167( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1088( + __action1091( source_code, mode, __0, @@ -60378,7 +60541,7 @@ fn __action1179< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1180< +fn __action1183< >( source_code: &str, mode: Mode, @@ -60391,14 +60554,14 @@ fn __action1180< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action570( + let __temp0 = __action573( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1088( + __action1091( source_code, mode, __0, @@ -60412,7 +60575,7 @@ fn __action1180< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1181< +fn __action1184< >( source_code: &str, mode: Mode, @@ -60422,14 +60585,14 @@ fn __action1181< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action356( + let __temp0 = __action359( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action354( + __action357( source_code, mode, __temp0, @@ -60438,7 +60601,7 @@ fn __action1181< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1182< +fn __action1185< >( source_code: &str, mode: Mode, @@ -60449,14 +60612,14 @@ fn __action1182< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action356( + let __temp0 = __action359( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action355( + __action358( source_code, mode, __0, @@ -60466,7 +60629,7 @@ fn __action1182< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1183< +fn __action1186< >( source_code: &str, mode: Mode, @@ -60475,14 +60638,14 @@ fn __action1183< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action428( + let __temp0 = __action431( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action353( + __action356( source_code, mode, __temp0, @@ -60492,7 +60655,7 @@ fn __action1183< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1184< +fn __action1187< >( source_code: &str, mode: Mode, @@ -60502,13 +60665,13 @@ fn __action1184< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action429( + let __temp0 = __action432( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action353( + __action356( source_code, mode, __temp0, @@ -60518,7 +60681,7 @@ fn __action1184< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1185< +fn __action1188< >( source_code: &str, mode: Mode, @@ -60528,14 +60691,14 @@ fn __action1185< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action409( + let __temp0 = __action412( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action417( + __action420( source_code, mode, __temp0, @@ -60544,7 +60707,7 @@ fn __action1185< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1186< +fn __action1189< >( source_code: &str, mode: Mode, @@ -60555,14 +60718,14 @@ fn __action1186< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action409( + let __temp0 = __action412( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action418( + __action421( source_code, mode, __0, @@ -60572,7 +60735,7 @@ fn __action1186< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1187< +fn __action1190< >( source_code: &str, mode: Mode, @@ -60584,14 +60747,14 @@ fn __action1187< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action407( + let __temp0 = __action410( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action668( + __action671( source_code, mode, __0, @@ -60604,7 +60767,7 @@ fn __action1187< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1188< +fn __action1191< >( source_code: &str, mode: Mode, @@ -60617,13 +60780,13 @@ fn __action1188< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action408( + let __temp0 = __action411( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action668( + __action671( source_code, mode, __0, @@ -60636,7 +60799,7 @@ fn __action1188< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1189< +fn __action1192< >( source_code: &str, mode: Mode, @@ -60647,14 +60810,14 @@ fn __action1189< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action407( + let __temp0 = __action410( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action669( + __action672( source_code, mode, __0, @@ -60666,7 +60829,7 @@ fn __action1189< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1190< +fn __action1193< >( source_code: &str, mode: Mode, @@ -60678,13 +60841,13 @@ fn __action1190< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action408( + let __temp0 = __action411( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action669( + __action672( source_code, mode, __0, @@ -60696,7 +60859,7 @@ fn __action1190< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1191< +fn __action1194< >( source_code: &str, mode: Mode, @@ -60707,14 +60870,14 @@ fn __action1191< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action407( + let __temp0 = __action410( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action670( + __action673( source_code, mode, __temp0, @@ -60726,7 +60889,7 @@ fn __action1191< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1192< +fn __action1195< >( source_code: &str, mode: Mode, @@ -60738,13 +60901,13 @@ fn __action1192< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action408( + let __temp0 = __action411( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action670( + __action673( source_code, mode, __temp0, @@ -60756,7 +60919,7 @@ fn __action1192< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1193< +fn __action1196< >( source_code: &str, mode: Mode, @@ -60766,14 +60929,14 @@ fn __action1193< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action407( + let __temp0 = __action410( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action671( + __action674( source_code, mode, __temp0, @@ -60784,7 +60947,7 @@ fn __action1193< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1194< +fn __action1197< >( source_code: &str, mode: Mode, @@ -60795,13 +60958,13 @@ fn __action1194< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action408( + let __temp0 = __action411( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action671( + __action674( source_code, mode, __temp0, @@ -60812,7 +60975,7 @@ fn __action1194< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1195< +fn __action1198< >( source_code: &str, mode: Mode, @@ -60824,14 +60987,14 @@ fn __action1195< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action407( + let __temp0 = __action410( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action672( + __action675( source_code, mode, __0, @@ -60844,7 +61007,7 @@ fn __action1195< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1196< +fn __action1199< >( source_code: &str, mode: Mode, @@ -60857,13 +61020,13 @@ fn __action1196< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action408( + let __temp0 = __action411( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action672( + __action675( source_code, mode, __0, @@ -60876,7 +61039,7 @@ fn __action1196< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1197< +fn __action1200< >( source_code: &str, mode: Mode, @@ -60887,14 +61050,14 @@ fn __action1197< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action407( + let __temp0 = __action410( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action673( + __action676( source_code, mode, __0, @@ -60906,7 +61069,7 @@ fn __action1197< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1198< +fn __action1201< >( source_code: &str, mode: Mode, @@ -60918,13 +61081,13 @@ fn __action1198< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action408( + let __temp0 = __action411( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action673( + __action676( source_code, mode, __0, @@ -60936,7 +61099,7 @@ fn __action1198< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1199< +fn __action1202< >( source_code: &str, mode: Mode, @@ -60947,14 +61110,14 @@ fn __action1199< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action407( + let __temp0 = __action410( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action674( + __action677( source_code, mode, __temp0, @@ -60966,7 +61129,7 @@ fn __action1199< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1200< +fn __action1203< >( source_code: &str, mode: Mode, @@ -60978,13 +61141,13 @@ fn __action1200< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action408( + let __temp0 = __action411( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action674( + __action677( source_code, mode, __temp0, @@ -60996,7 +61159,7 @@ fn __action1200< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1201< +fn __action1204< >( source_code: &str, mode: Mode, @@ -61006,14 +61169,14 @@ fn __action1201< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action407( + let __temp0 = __action410( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action675( + __action678( source_code, mode, __temp0, @@ -61024,7 +61187,7 @@ fn __action1201< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1202< +fn __action1205< >( source_code: &str, mode: Mode, @@ -61035,13 +61198,13 @@ fn __action1202< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action408( + let __temp0 = __action411( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action675( + __action678( source_code, mode, __temp0, @@ -61052,7 +61215,7 @@ fn __action1202< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1203< +fn __action1206< >( source_code: &str, mode: Mode, @@ -61066,7 +61229,7 @@ fn __action1203< { let __start0 = __1.0; let __end0 = __3.2; - let __temp0 = __action324( + let __temp0 = __action329( source_code, mode, __1, @@ -61074,7 +61237,7 @@ fn __action1203< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action792( + __action793( source_code, mode, __0, @@ -61086,7 +61249,7 @@ fn __action1203< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1204< +fn __action1207< >( source_code: &str, mode: Mode, @@ -61101,7 +61264,7 @@ fn __action1204< { let __start0 = __2.0; let __end0 = __4.2; - let __temp0 = __action324( + let __temp0 = __action329( source_code, mode, __2, @@ -61109,7 +61272,7 @@ fn __action1204< __4, ); let __temp0 = (__start0, __temp0, __end0); - __action794( + __action795( source_code, mode, __0, @@ -61122,7 +61285,7 @@ fn __action1204< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1205< +fn __action1208< >( source_code: &str, mode: Mode, @@ -61132,13 +61295,13 @@ fn __action1205< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action160( + let __temp0 = __action161( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action321( + __action326( source_code, mode, __temp0, @@ -61148,7 +61311,7 @@ fn __action1205< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1206< +fn __action1209< >( source_code: &str, mode: Mode, @@ -61160,13 +61323,13 @@ fn __action1206< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action160( + let __temp0 = __action161( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action664( + __action667( source_code, mode, __0, @@ -61178,7 +61341,7 @@ fn __action1206< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1207< +fn __action1210< >( source_code: &str, mode: Mode, @@ -61189,13 +61352,13 @@ fn __action1207< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action160( + let __temp0 = __action161( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action665( + __action668( source_code, mode, __0, @@ -61206,7 +61369,7 @@ fn __action1207< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1208< +fn __action1211< >( source_code: &str, mode: Mode, @@ -61216,14 +61379,14 @@ fn __action1208< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action1205( + let __temp0 = __action1208( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action319( + __action324( source_code, mode, __temp0, @@ -61232,7 +61395,7 @@ fn __action1208< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1209< +fn __action1212< >( source_code: &str, mode: Mode, @@ -61246,14 +61409,14 @@ fn __action1209< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1208( + let __temp0 = __action1211( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1091( + __action1094( source_code, mode, __0, @@ -61266,7 +61429,7 @@ fn __action1209< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1210< +fn __action1213< >( source_code: &str, mode: Mode, @@ -61278,14 +61441,14 @@ fn __action1210< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action320( + let __temp0 = __action325( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1091( + __action1094( source_code, mode, __0, @@ -61298,7 +61461,7 @@ fn __action1210< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1211< +fn __action1214< >( source_code: &str, mode: Mode, @@ -61313,14 +61476,14 @@ fn __action1211< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1208( + let __temp0 = __action1211( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1092( + __action1095( source_code, mode, __0, @@ -61334,7 +61497,7 @@ fn __action1211< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1212< +fn __action1215< >( source_code: &str, mode: Mode, @@ -61347,14 +61510,14 @@ fn __action1212< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action320( + let __temp0 = __action325( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1092( + __action1095( source_code, mode, __0, @@ -61368,7 +61531,7 @@ fn __action1212< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1213< +fn __action1216< >( source_code: &str, mode: Mode, @@ -61381,14 +61544,14 @@ fn __action1213< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1208( + let __temp0 = __action1211( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1093( + __action1096( source_code, mode, __0, @@ -61400,7 +61563,7 @@ fn __action1213< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1214< +fn __action1217< >( source_code: &str, mode: Mode, @@ -61411,14 +61574,14 @@ fn __action1214< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action320( + let __temp0 = __action325( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1093( + __action1096( source_code, mode, __0, @@ -61430,7 +61593,7 @@ fn __action1214< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1215< +fn __action1218< >( source_code: &str, mode: Mode, @@ -61444,14 +61607,14 @@ fn __action1215< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1208( + let __temp0 = __action1211( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1094( + __action1097( source_code, mode, __0, @@ -61464,7 +61627,7 @@ fn __action1215< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1216< +fn __action1219< >( source_code: &str, mode: Mode, @@ -61476,14 +61639,14 @@ fn __action1216< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action320( + let __temp0 = __action325( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1094( + __action1097( source_code, mode, __0, @@ -61496,7 +61659,7 @@ fn __action1216< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1217< +fn __action1220< >( source_code: &str, mode: Mode, @@ -61506,14 +61669,14 @@ fn __action1217< { let __start0 = __0.0; let __end0 = __1.2; - let __temp0 = __action516( + let __temp0 = __action519( source_code, mode, __0, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action514( + __action517( source_code, mode, __temp0, @@ -61522,7 +61685,7 @@ fn __action1217< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1218< +fn __action1221< >( source_code: &str, mode: Mode, @@ -61533,14 +61696,14 @@ fn __action1218< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action516( + let __temp0 = __action519( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action515( + __action518( source_code, mode, __0, @@ -61550,7 +61713,7 @@ fn __action1218< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1219< +fn __action1222< >( source_code: &str, mode: Mode, @@ -61559,13 +61722,13 @@ fn __action1219< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action363( + let __temp0 = __action366( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action361( + __action364( source_code, mode, __temp0, @@ -61574,7 +61737,7 @@ fn __action1219< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1220< +fn __action1223< >( source_code: &str, mode: Mode, @@ -61587,13 +61750,13 @@ fn __action1220< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action1219( + let __temp0 = __action1222( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action856( + __action857( source_code, mode, __0, @@ -61606,7 +61769,7 @@ fn __action1220< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1221< +fn __action1224< >( source_code: &str, mode: Mode, @@ -61618,14 +61781,14 @@ fn __action1221< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action362( + let __temp0 = __action365( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action856( + __action857( source_code, mode, __0, @@ -61638,7 +61801,7 @@ fn __action1221< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1222< +fn __action1225< >( source_code: &str, mode: Mode, @@ -61647,13 +61810,13 @@ fn __action1222< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action296( + let __temp0 = __action301( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action294( + __action299( source_code, mode, __temp0, @@ -61662,7 +61825,7 @@ fn __action1222< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1223< +fn __action1226< >( source_code: &str, mode: Mode, @@ -61674,13 +61837,13 @@ fn __action1223< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action1222( + let __temp0 = __action1225( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action903( + __action904( source_code, mode, __0, @@ -61692,7 +61855,7 @@ fn __action1223< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1224< +fn __action1227< >( source_code: &str, mode: Mode, @@ -61703,14 +61866,14 @@ fn __action1224< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action295( + let __temp0 = __action300( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action903( + __action904( source_code, mode, __0, @@ -61722,7 +61885,7 @@ fn __action1224< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1225< +fn __action1228< >( source_code: &str, mode: Mode, @@ -61733,14 +61896,14 @@ fn __action1225< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action722( + __action725( source_code, mode, __0, @@ -61752,7 +61915,7 @@ fn __action1225< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1226< +fn __action1229< >( source_code: &str, mode: Mode, @@ -61763,14 +61926,14 @@ fn __action1226< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action723( + __action726( source_code, mode, __0, @@ -61782,7 +61945,7 @@ fn __action1226< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1227< +fn __action1230< >( source_code: &str, mode: Mode, @@ -61793,14 +61956,14 @@ fn __action1227< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action724( + __action727( source_code, mode, __0, @@ -61812,7 +61975,7 @@ fn __action1227< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1228< +fn __action1231< >( source_code: &str, mode: Mode, @@ -61822,14 +61985,14 @@ fn __action1228< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action725( + __action728( source_code, mode, __0, @@ -61840,7 +62003,7 @@ fn __action1228< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1229< +fn __action1232< >( source_code: &str, mode: Mode, @@ -61850,14 +62013,14 @@ fn __action1229< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action726( + __action729( source_code, mode, __0, @@ -61868,7 +62031,7 @@ fn __action1229< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1230< +fn __action1233< >( source_code: &str, mode: Mode, @@ -61879,14 +62042,14 @@ fn __action1230< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action727( + __action730( source_code, mode, __0, @@ -61898,7 +62061,7 @@ fn __action1230< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1231< +fn __action1234< >( source_code: &str, mode: Mode, @@ -61909,14 +62072,14 @@ fn __action1231< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action728( + __action731( source_code, mode, __0, @@ -61928,7 +62091,7 @@ fn __action1231< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1232< +fn __action1235< >( source_code: &str, mode: Mode, @@ -61939,14 +62102,14 @@ fn __action1232< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action729( + __action732( source_code, mode, __0, @@ -61958,7 +62121,7 @@ fn __action1232< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1233< +fn __action1236< >( source_code: &str, mode: Mode, @@ -61969,14 +62132,14 @@ fn __action1233< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action730( + __action733( source_code, mode, __0, @@ -61988,7 +62151,7 @@ fn __action1233< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1234< +fn __action1237< >( source_code: &str, mode: Mode, @@ -62000,14 +62163,14 @@ fn __action1234< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1077( + __action1080( source_code, mode, __0, @@ -62020,7 +62183,7 @@ fn __action1234< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1235< +fn __action1238< >( source_code: &str, mode: Mode, @@ -62030,14 +62193,14 @@ fn __action1235< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1078( + __action1081( source_code, mode, __0, @@ -62048,33 +62211,7 @@ fn __action1235< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1236< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), -) -> Result> -{ - let __start0 = __0.2; - let __end0 = __0.2; - let __temp0 = __action413( - source_code, - mode, - &__start0, - &__end0, - ); - let __temp0 = (__start0, __temp0, __end0); - __action732( - source_code, - mode, - __0, - __temp0, - ) -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action1237< +fn __action1239< >( source_code: &str, mode: Mode, @@ -62083,14 +62220,14 @@ fn __action1237< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action733( + __action735( source_code, mode, __0, @@ -62100,7 +62237,7 @@ fn __action1237< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1238< +fn __action1240< >( source_code: &str, mode: Mode, @@ -62109,14 +62246,14 @@ fn __action1238< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action734( + __action736( source_code, mode, __0, @@ -62126,7 +62263,7 @@ fn __action1238< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1239< +fn __action1241< >( source_code: &str, mode: Mode, @@ -62137,14 +62274,14 @@ fn __action1239< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action735( + __action737( source_code, mode, __0, @@ -62156,7 +62293,7 @@ fn __action1239< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1240< +fn __action1242< >( source_code: &str, mode: Mode, @@ -62168,14 +62305,14 @@ fn __action1240< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action736( + __action738( source_code, mode, __0, @@ -62188,7 +62325,7 @@ fn __action1240< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1241< +fn __action1243< >( source_code: &str, mode: Mode, @@ -62200,14 +62337,14 @@ fn __action1241< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action737( + __action739( source_code, mode, __0, @@ -62220,7 +62357,7 @@ fn __action1241< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1242< +fn __action1244< >( source_code: &str, mode: Mode, @@ -62231,14 +62368,14 @@ fn __action1242< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action738( + __action740( source_code, mode, __0, @@ -62250,7 +62387,7 @@ fn __action1242< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1243< +fn __action1245< >( source_code: &str, mode: Mode, @@ -62264,14 +62401,14 @@ fn __action1243< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1165( + __action1168( source_code, mode, __0, @@ -62286,7 +62423,7 @@ fn __action1243< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1244< +fn __action1246< >( source_code: &str, mode: Mode, @@ -62298,14 +62435,14 @@ fn __action1244< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1166( + __action1169( source_code, mode, __0, @@ -62318,7 +62455,7 @@ fn __action1244< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1245< +fn __action1247< >( source_code: &str, mode: Mode, @@ -62333,14 +62470,14 @@ fn __action1245< { let __start0 = __6.2; let __end0 = __6.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1167( + __action1170( source_code, mode, __0, @@ -62356,7 +62493,7 @@ fn __action1245< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1246< +fn __action1248< >( source_code: &str, mode: Mode, @@ -62369,14 +62506,14 @@ fn __action1246< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1168( + __action1171( source_code, mode, __0, @@ -62390,7 +62527,7 @@ fn __action1246< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1247< +fn __action1249< >( source_code: &str, mode: Mode, @@ -62403,14 +62540,14 @@ fn __action1247< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1169( + __action1172( source_code, mode, __0, @@ -62424,7 +62561,7 @@ fn __action1247< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1248< +fn __action1250< >( source_code: &str, mode: Mode, @@ -62435,14 +62572,14 @@ fn __action1248< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1170( + __action1173( source_code, mode, __0, @@ -62454,7 +62591,7 @@ fn __action1248< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1249< +fn __action1251< >( source_code: &str, mode: Mode, @@ -62468,14 +62605,14 @@ fn __action1249< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1171( + __action1174( source_code, mode, __0, @@ -62490,7 +62627,7 @@ fn __action1249< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1250< +fn __action1252< >( source_code: &str, mode: Mode, @@ -62502,14 +62639,14 @@ fn __action1250< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1172( + __action1175( source_code, mode, __0, @@ -62522,7 +62659,7 @@ fn __action1250< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1251< +fn __action1253< >( source_code: &str, mode: Mode, @@ -62532,14 +62669,14 @@ fn __action1251< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action741( + __action743( source_code, mode, __0, @@ -62550,7 +62687,7 @@ fn __action1251< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1252< +fn __action1254< >( source_code: &str, mode: Mode, @@ -62561,14 +62698,14 @@ fn __action1252< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action742( + __action744( source_code, mode, __0, @@ -62580,7 +62717,7 @@ fn __action1252< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1253< +fn __action1255< >( source_code: &str, mode: Mode, @@ -62592,14 +62729,14 @@ fn __action1253< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action743( + __action745( source_code, mode, __0, @@ -62612,7 +62749,7 @@ fn __action1253< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1254< +fn __action1256< >( source_code: &str, mode: Mode, @@ -62624,14 +62761,14 @@ fn __action1254< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action744( + __action746( source_code, mode, __0, @@ -62644,7 +62781,7 @@ fn __action1254< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1255< +fn __action1257< >( source_code: &str, mode: Mode, @@ -62655,14 +62792,14 @@ fn __action1255< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action745( + __action747( source_code, mode, __0, @@ -62674,7 +62811,7 @@ fn __action1255< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1256< +fn __action1258< >( source_code: &str, mode: Mode, @@ -62686,14 +62823,14 @@ fn __action1256< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action746( + __action748( source_code, mode, __0, @@ -62706,7 +62843,7 @@ fn __action1256< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1257< +fn __action1259< >( source_code: &str, mode: Mode, @@ -62717,14 +62854,14 @@ fn __action1257< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action747( + __action749( source_code, mode, __0, @@ -62736,7 +62873,7 @@ fn __action1257< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1258< +fn __action1260< >( source_code: &str, mode: Mode, @@ -62748,14 +62885,14 @@ fn __action1258< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action748( + __action750( source_code, mode, __0, @@ -62768,7 +62905,7 @@ fn __action1258< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1259< +fn __action1261< >( source_code: &str, mode: Mode, @@ -62777,14 +62914,14 @@ fn __action1259< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action749( + __action751( source_code, mode, __0, @@ -62794,7 +62931,7 @@ fn __action1259< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1260< +fn __action1262< >( source_code: &str, mode: Mode, @@ -62803,14 +62940,14 @@ fn __action1260< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action750( + __action752( source_code, mode, __0, @@ -62820,7 +62957,7 @@ fn __action1260< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1261< +fn __action1263< >( source_code: &str, mode: Mode, @@ -62829,14 +62966,14 @@ fn __action1261< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action751( + __action753( source_code, mode, __0, @@ -62846,7 +62983,7 @@ fn __action1261< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1262< +fn __action1264< >( source_code: &str, mode: Mode, @@ -62855,40 +62992,14 @@ fn __action1262< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( - source_code, - mode, - &__start0, - &__end0, - ); - let __temp0 = (__start0, __temp0, __end0); - __action752( - source_code, - mode, - __0, - __temp0, - ) -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action1263< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), -) -> Result> -{ - let __start0 = __0.2; - let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action753( + __action754( source_code, mode, __0, @@ -62898,7 +63009,7 @@ fn __action1263< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1264< +fn __action1265< >( source_code: &str, mode: Mode, @@ -62907,14 +63018,14 @@ fn __action1264< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action754( + __action755( source_code, mode, __0, @@ -62924,7 +63035,7 @@ fn __action1264< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1265< +fn __action1266< >( source_code: &str, mode: Mode, @@ -62933,14 +63044,14 @@ fn __action1265< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action755( + __action756( source_code, mode, __0, @@ -62950,7 +63061,7 @@ fn __action1265< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1266< +fn __action1267< >( source_code: &str, mode: Mode, @@ -62961,14 +63072,14 @@ fn __action1266< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action756( + __action757( source_code, mode, __0, @@ -62980,7 +63091,7 @@ fn __action1266< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1267< +fn __action1268< >( source_code: &str, mode: Mode, @@ -62992,14 +63103,14 @@ fn __action1267< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action757( + __action758( source_code, mode, __0, @@ -63012,7 +63123,7 @@ fn __action1267< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1268< +fn __action1269< >( source_code: &str, mode: Mode, @@ -63026,14 +63137,14 @@ fn __action1268< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1173( + __action1176( source_code, mode, __0, @@ -63048,7 +63159,7 @@ fn __action1268< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1269< +fn __action1270< >( source_code: &str, mode: Mode, @@ -63060,14 +63171,14 @@ fn __action1269< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1174( + __action1177( source_code, mode, __0, @@ -63080,7 +63191,7 @@ fn __action1269< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1270< +fn __action1271< >( source_code: &str, mode: Mode, @@ -63095,14 +63206,14 @@ fn __action1270< { let __start0 = __6.2; let __end0 = __6.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1175( + __action1178( source_code, mode, __0, @@ -63118,7 +63229,7 @@ fn __action1270< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1271< +fn __action1272< >( source_code: &str, mode: Mode, @@ -63131,14 +63242,14 @@ fn __action1271< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1176( + __action1179( source_code, mode, __0, @@ -63152,7 +63263,7 @@ fn __action1271< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1272< +fn __action1273< >( source_code: &str, mode: Mode, @@ -63165,14 +63276,14 @@ fn __action1272< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1177( + __action1180( source_code, mode, __0, @@ -63186,7 +63297,7 @@ fn __action1272< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1273< +fn __action1274< >( source_code: &str, mode: Mode, @@ -63197,14 +63308,14 @@ fn __action1273< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1178( + __action1181( source_code, mode, __0, @@ -63216,7 +63327,7 @@ fn __action1273< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1274< +fn __action1275< >( source_code: &str, mode: Mode, @@ -63230,14 +63341,14 @@ fn __action1274< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1179( + __action1182( source_code, mode, __0, @@ -63252,7 +63363,7 @@ fn __action1274< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1275< +fn __action1276< >( source_code: &str, mode: Mode, @@ -63264,14 +63375,14 @@ fn __action1275< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1180( + __action1183( source_code, mode, __0, @@ -63284,7 +63395,7 @@ fn __action1275< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1276< +fn __action1277< >( source_code: &str, mode: Mode, @@ -63294,14 +63405,14 @@ fn __action1276< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action760( + __action761( source_code, mode, __0, @@ -63312,7 +63423,7 @@ fn __action1276< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1277< +fn __action1278< >( source_code: &str, mode: Mode, @@ -63323,14 +63434,14 @@ fn __action1277< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action761( + __action762( source_code, mode, __0, @@ -63342,7 +63453,7 @@ fn __action1277< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1278< +fn __action1279< >( source_code: &str, mode: Mode, @@ -63354,14 +63465,14 @@ fn __action1278< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action762( + __action763( source_code, mode, __0, @@ -63374,7 +63485,7 @@ fn __action1278< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1279< +fn __action1280< >( source_code: &str, mode: Mode, @@ -63386,14 +63497,14 @@ fn __action1279< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action763( + __action764( source_code, mode, __0, @@ -63406,7 +63517,7 @@ fn __action1279< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1280< +fn __action1281< >( source_code: &str, mode: Mode, @@ -63417,14 +63528,14 @@ fn __action1280< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action764( + __action765( source_code, mode, __0, @@ -63436,7 +63547,7 @@ fn __action1280< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1281< +fn __action1282< >( source_code: &str, mode: Mode, @@ -63448,14 +63559,14 @@ fn __action1281< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action765( + __action766( source_code, mode, __0, @@ -63468,7 +63579,7 @@ fn __action1281< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1282< +fn __action1283< >( source_code: &str, mode: Mode, @@ -63479,14 +63590,14 @@ fn __action1282< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action766( + __action767( source_code, mode, __0, @@ -63498,7 +63609,7 @@ fn __action1282< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1283< +fn __action1284< >( source_code: &str, mode: Mode, @@ -63510,14 +63621,14 @@ fn __action1283< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action767( + __action768( source_code, mode, __0, @@ -63528,32 +63639,6 @@ fn __action1283< ) } -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action1284< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr -{ - let __start0 = __0.2; - let __end0 = __0.2; - let __temp0 = __action413( - source_code, - mode, - &__start0, - &__end0, - ); - let __temp0 = (__start0, __temp0, __end0); - __action768( - source_code, - mode, - __0, - __temp0, - ) -} - #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] fn __action1285< @@ -63565,7 +63650,7 @@ fn __action1285< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, @@ -63591,7 +63676,7 @@ fn __action1286< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, @@ -63617,7 +63702,7 @@ fn __action1287< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, @@ -63635,6 +63720,32 @@ fn __action1287< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] fn __action1288< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, token::Tok, TextSize), +) -> ast::ParenthesizedExpr +{ + let __start0 = __0.2; + let __end0 = __0.2; + let __temp0 = __action416( + source_code, + mode, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action772( + source_code, + mode, + __0, + __temp0, + ) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action1289< >( source_code: &str, mode: Mode, @@ -63644,14 +63755,14 @@ fn __action1288< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action772( + __action773( source_code, mode, __0, @@ -63662,7 +63773,7 @@ fn __action1288< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1289< +fn __action1290< >( source_code: &str, mode: Mode, @@ -63674,14 +63785,14 @@ fn __action1289< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action773( + __action774( source_code, mode, __0, @@ -63694,7 +63805,7 @@ fn __action1289< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1290< +fn __action1291< >( source_code: &str, mode: Mode, @@ -63705,14 +63816,14 @@ fn __action1290< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action774( + __action775( source_code, mode, __0, @@ -63724,7 +63835,7 @@ fn __action1290< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1291< +fn __action1292< >( source_code: &str, mode: Mode, @@ -63734,14 +63845,14 @@ fn __action1291< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action775( + __action776( source_code, mode, __0, @@ -63752,7 +63863,7 @@ fn __action1291< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1292< +fn __action1293< >( source_code: &str, mode: Mode, @@ -63764,14 +63875,14 @@ fn __action1292< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action776( + __action777( source_code, mode, __0, @@ -63784,7 +63895,7 @@ fn __action1292< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1293< +fn __action1294< >( source_code: &str, mode: Mode, @@ -63795,14 +63906,14 @@ fn __action1293< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action777( + __action778( source_code, mode, __0, @@ -63814,7 +63925,7 @@ fn __action1293< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1294< +fn __action1295< >( source_code: &str, mode: Mode, @@ -63824,14 +63935,14 @@ fn __action1294< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action778( + __action779( source_code, mode, __0, @@ -63842,7 +63953,7 @@ fn __action1294< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1295< +fn __action1296< >( source_code: &str, mode: Mode, @@ -63852,14 +63963,14 @@ fn __action1295< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action779( + __action780( source_code, mode, __0, @@ -63870,7 +63981,7 @@ fn __action1295< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1296< +fn __action1297< >( source_code: &str, mode: Mode, @@ -63879,14 +63990,14 @@ fn __action1296< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action780( + __action781( source_code, mode, __0, @@ -63896,7 +64007,7 @@ fn __action1296< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1297< +fn __action1298< >( source_code: &str, mode: Mode, @@ -63906,14 +64017,14 @@ fn __action1297< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action782( + __action783( source_code, mode, __0, @@ -63924,7 +64035,7 @@ fn __action1297< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1298< +fn __action1299< >( source_code: &str, mode: Mode, @@ -63934,14 +64045,14 @@ fn __action1298< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action783( + __action784( source_code, mode, __0, @@ -63952,7 +64063,7 @@ fn __action1298< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1299< +fn __action1300< >( source_code: &str, mode: Mode, @@ -63962,14 +64073,14 @@ fn __action1299< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action784( + __action785( source_code, mode, __0, @@ -63980,7 +64091,7 @@ fn __action1299< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1300< +fn __action1301< >( source_code: &str, mode: Mode, @@ -63990,14 +64101,14 @@ fn __action1300< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action785( + __action786( source_code, mode, __0, @@ -64008,7 +64119,7 @@ fn __action1300< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1301< +fn __action1302< >( source_code: &str, mode: Mode, @@ -64019,14 +64130,14 @@ fn __action1301< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action786( + __action787( source_code, mode, __0, @@ -64038,7 +64149,7 @@ fn __action1301< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1302< +fn __action1303< >( source_code: &str, mode: Mode, @@ -64048,14 +64159,14 @@ fn __action1302< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action787( + __action788( source_code, mode, __0, @@ -64066,7 +64177,7 @@ fn __action1302< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1303< +fn __action1304< >( source_code: &str, mode: Mode, @@ -64075,14 +64186,14 @@ fn __action1303< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action788( + __action789( source_code, mode, __0, @@ -64092,7 +64203,7 @@ fn __action1303< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1304< +fn __action1305< >( source_code: &str, mode: Mode, @@ -64102,14 +64213,14 @@ fn __action1304< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action789( + __action790( source_code, mode, __0, @@ -64120,7 +64231,7 @@ fn __action1304< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1305< +fn __action1306< >( source_code: &str, mode: Mode, @@ -64131,14 +64242,14 @@ fn __action1305< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1103( + __action1106( source_code, mode, __0, @@ -64150,7 +64261,7 @@ fn __action1305< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1306< +fn __action1307< >( source_code: &str, mode: Mode, @@ -64159,14 +64270,14 @@ fn __action1306< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1104( + __action1107( source_code, mode, __0, @@ -64176,7 +64287,7 @@ fn __action1306< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1307< +fn __action1308< >( source_code: &str, mode: Mode, @@ -64187,14 +64298,14 @@ fn __action1307< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action795( + __action796( source_code, mode, __0, @@ -64206,7 +64317,7 @@ fn __action1307< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1308< +fn __action1309< >( source_code: &str, mode: Mode, @@ -64217,14 +64328,14 @@ fn __action1308< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action796( + __action797( source_code, mode, __0, @@ -64236,7 +64347,7 @@ fn __action1308< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1309< +fn __action1310< >( source_code: &str, mode: Mode, @@ -64246,14 +64357,14 @@ fn __action1309< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action797( + __action798( source_code, mode, __0, @@ -64264,7 +64375,7 @@ fn __action1309< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1310< +fn __action1311< >( source_code: &str, mode: Mode, @@ -64275,14 +64386,14 @@ fn __action1310< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action798( + __action799( source_code, mode, __0, @@ -64294,7 +64405,7 @@ fn __action1310< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1311< +fn __action1312< >( source_code: &str, mode: Mode, @@ -64306,14 +64417,14 @@ fn __action1311< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action799( + __action800( source_code, mode, __0, @@ -64326,7 +64437,7 @@ fn __action1311< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1312< +fn __action1313< >( source_code: &str, mode: Mode, @@ -64337,14 +64448,14 @@ fn __action1312< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action801( + __action802( source_code, mode, __0, @@ -64356,7 +64467,7 @@ fn __action1312< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1313< +fn __action1314< >( source_code: &str, mode: Mode, @@ -64365,14 +64476,14 @@ fn __action1313< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action802( + __action803( source_code, mode, __0, @@ -64382,7 +64493,33 @@ fn __action1313< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1314< +fn __action1315< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, (String, bool), TextSize), +) -> Result> +{ + let __start0 = __0.2; + let __end0 = __0.2; + let __temp0 = __action416( + source_code, + mode, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action804( + source_code, + mode, + __0, + __temp0, + ) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action1316< >( source_code: &str, mode: Mode, @@ -64396,14 +64533,14 @@ fn __action1314< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action804( + __action805( source_code, mode, __0, @@ -64418,7 +64555,7 @@ fn __action1314< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1315< +fn __action1317< >( source_code: &str, mode: Mode, @@ -64431,14 +64568,14 @@ fn __action1315< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action805( + __action806( source_code, mode, __0, @@ -64452,7 +64589,7 @@ fn __action1315< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1316< +fn __action1318< >( source_code: &str, mode: Mode, @@ -64462,14 +64599,14 @@ fn __action1316< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action806( + __action807( source_code, mode, __0, @@ -64480,7 +64617,7 @@ fn __action1316< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1317< +fn __action1319< >( source_code: &str, mode: Mode, @@ -64490,14 +64627,14 @@ fn __action1317< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action807( + __action808( source_code, mode, __0, @@ -64508,7 +64645,7 @@ fn __action1317< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1318< +fn __action1320< >( source_code: &str, mode: Mode, @@ -64517,14 +64654,14 @@ fn __action1318< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action808( + __action809( source_code, mode, __0, @@ -64534,7 +64671,7 @@ fn __action1318< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1319< +fn __action1321< >( source_code: &str, mode: Mode, @@ -64543,14 +64680,14 @@ fn __action1319< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action809( + __action810( source_code, mode, __0, @@ -64560,7 +64697,7 @@ fn __action1319< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1320< +fn __action1322< >( source_code: &str, mode: Mode, @@ -64570,14 +64707,14 @@ fn __action1320< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action810( + __action811( source_code, mode, __0, @@ -64588,7 +64725,7 @@ fn __action1320< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1321< +fn __action1323< >( source_code: &str, mode: Mode, @@ -64597,14 +64734,14 @@ fn __action1321< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action811( + __action812( source_code, mode, __0, @@ -64614,7 +64751,7 @@ fn __action1321< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1322< +fn __action1324< >( source_code: &str, mode: Mode, @@ -64624,14 +64761,14 @@ fn __action1322< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action816( + __action817( source_code, mode, __0, @@ -64642,7 +64779,7 @@ fn __action1322< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1323< +fn __action1325< >( source_code: &str, mode: Mode, @@ -64653,14 +64790,14 @@ fn __action1323< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action817( + __action818( source_code, mode, __0, @@ -64672,7 +64809,7 @@ fn __action1323< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1324< +fn __action1326< >( source_code: &str, mode: Mode, @@ -64682,14 +64819,14 @@ fn __action1324< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action818( + __action819( source_code, mode, __0, @@ -64700,7 +64837,7 @@ fn __action1324< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1325< +fn __action1327< >( source_code: &str, mode: Mode, @@ -64710,14 +64847,14 @@ fn __action1325< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action819( + __action820( source_code, mode, __0, @@ -64728,7 +64865,7 @@ fn __action1325< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1326< +fn __action1328< >( source_code: &str, mode: Mode, @@ -64738,14 +64875,14 @@ fn __action1326< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action820( + __action821( source_code, mode, __0, @@ -64756,7 +64893,7 @@ fn __action1326< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1327< +fn __action1329< >( source_code: &str, mode: Mode, @@ -64765,14 +64902,14 @@ fn __action1327< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action821( + __action822( source_code, mode, __0, @@ -64782,7 +64919,7 @@ fn __action1327< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1328< +fn __action1330< >( source_code: &str, mode: Mode, @@ -64792,14 +64929,14 @@ fn __action1328< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action822( + __action823( source_code, mode, __0, @@ -64810,7 +64947,7 @@ fn __action1328< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1329< +fn __action1331< >( source_code: &str, mode: Mode, @@ -64819,14 +64956,14 @@ fn __action1329< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action823( + __action824( source_code, mode, __0, @@ -64836,7 +64973,7 @@ fn __action1329< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1330< +fn __action1332< >( source_code: &str, mode: Mode, @@ -64846,14 +64983,14 @@ fn __action1330< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action824( + __action825( source_code, mode, __0, @@ -64864,7 +65001,7 @@ fn __action1330< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1331< +fn __action1333< >( source_code: &str, mode: Mode, @@ -64873,14 +65010,14 @@ fn __action1331< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action825( + __action826( source_code, mode, __0, @@ -64890,7 +65027,7 @@ fn __action1331< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1332< +fn __action1334< >( source_code: &str, mode: Mode, @@ -64901,14 +65038,14 @@ fn __action1332< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1119( + __action1122( source_code, mode, __0, @@ -64920,7 +65057,7 @@ fn __action1332< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1333< +fn __action1335< >( source_code: &str, mode: Mode, @@ -64929,14 +65066,14 @@ fn __action1333< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1120( + __action1123( source_code, mode, __0, @@ -64946,7 +65083,7 @@ fn __action1333< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1334< +fn __action1336< >( source_code: &str, mode: Mode, @@ -64957,14 +65094,14 @@ fn __action1334< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1121( + __action1124( source_code, mode, __0, @@ -64976,7 +65113,7 @@ fn __action1334< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1335< +fn __action1337< >( source_code: &str, mode: Mode, @@ -64985,14 +65122,14 @@ fn __action1335< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1122( + __action1125( source_code, mode, __0, @@ -65002,7 +65139,7 @@ fn __action1335< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1336< +fn __action1338< >( source_code: &str, mode: Mode, @@ -65011,14 +65148,14 @@ fn __action1336< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action829( + __action830( source_code, mode, __0, @@ -65028,7 +65165,7 @@ fn __action1336< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1337< +fn __action1339< >( source_code: &str, mode: Mode, @@ -65040,14 +65177,14 @@ fn __action1337< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action830( + __action831( source_code, mode, __0, @@ -65060,7 +65197,7 @@ fn __action1337< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1338< +fn __action1340< >( source_code: &str, mode: Mode, @@ -65071,14 +65208,14 @@ fn __action1338< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action831( + __action832( source_code, mode, __0, @@ -65090,7 +65227,7 @@ fn __action1338< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1339< +fn __action1341< >( source_code: &str, mode: Mode, @@ -65099,14 +65236,14 @@ fn __action1339< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action832( + __action833( source_code, mode, __0, @@ -65116,7 +65253,7 @@ fn __action1339< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1340< +fn __action1342< >( source_code: &str, mode: Mode, @@ -65126,14 +65263,14 @@ fn __action1340< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action833( + __action834( source_code, mode, __0, @@ -65144,7 +65281,7 @@ fn __action1340< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1341< +fn __action1343< >( source_code: &str, mode: Mode, @@ -65156,14 +65293,14 @@ fn __action1341< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action834( + __action835( source_code, mode, __0, @@ -65176,7 +65313,7 @@ fn __action1341< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1342< +fn __action1344< >( source_code: &str, mode: Mode, @@ -65185,14 +65322,14 @@ fn __action1342< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action835( + __action836( source_code, mode, __0, @@ -65202,7 +65339,7 @@ fn __action1342< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1343< +fn __action1345< >( source_code: &str, mode: Mode, @@ -65211,14 +65348,14 @@ fn __action1343< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action836( + __action837( source_code, mode, __0, @@ -65228,7 +65365,7 @@ fn __action1343< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1344< +fn __action1346< >( source_code: &str, mode: Mode, @@ -65238,14 +65375,14 @@ fn __action1344< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action837( + __action838( source_code, mode, __0, @@ -65256,7 +65393,7 @@ fn __action1344< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1345< +fn __action1347< >( source_code: &str, mode: Mode, @@ -65271,21 +65408,21 @@ fn __action1345< let __end0 = __2.0; let __start1 = __4.2; let __end1 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - let __temp1 = __action413( + let __temp1 = __action416( source_code, mode, &__start1, &__end1, ); let __temp1 = (__start1, __temp1, __end1); - __action838( + __action839( source_code, mode, __0, @@ -65300,7 +65437,7 @@ fn __action1345< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1346< +fn __action1348< >( source_code: &str, mode: Mode, @@ -65309,14 +65446,14 @@ fn __action1346< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action839( + __action840( source_code, mode, __0, @@ -65326,7 +65463,7 @@ fn __action1346< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1347< +fn __action1349< >( source_code: &str, mode: Mode, @@ -65335,14 +65472,14 @@ fn __action1347< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action840( + __action841( source_code, mode, __0, @@ -65352,7 +65489,7 @@ fn __action1347< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1348< +fn __action1350< >( source_code: &str, mode: Mode, @@ -65361,14 +65498,14 @@ fn __action1348< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action841( + __action842( source_code, mode, __0, @@ -65378,7 +65515,7 @@ fn __action1348< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1349< +fn __action1351< >( source_code: &str, mode: Mode, @@ -65387,14 +65524,14 @@ fn __action1349< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action842( + __action843( source_code, mode, __0, @@ -65404,7 +65541,7 @@ fn __action1349< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1350< +fn __action1352< >( source_code: &str, mode: Mode, @@ -65413,14 +65550,14 @@ fn __action1350< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action843( + __action844( source_code, mode, __0, @@ -65430,23 +65567,23 @@ fn __action1350< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1351< +fn __action1353< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), -) -> Result> + __0: (TextSize, StringType, TextSize), +) -> ast::Pattern { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action844( + __action845( source_code, mode, __0, @@ -65456,23 +65593,23 @@ fn __action1351< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1352< +fn __action1354< >( source_code: &str, mode: Mode, - __0: (TextSize, token::Tok, TextSize), -) -> ast::Expr + __0: (TextSize, Vec, TextSize), +) -> Result> { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action845( + __action846( source_code, mode, __0, @@ -65482,7 +65619,7 @@ fn __action1352< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1353< +fn __action1355< >( source_code: &str, mode: Mode, @@ -65491,14 +65628,14 @@ fn __action1353< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action846( + __action847( source_code, mode, __0, @@ -65508,7 +65645,7 @@ fn __action1353< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1354< +fn __action1356< >( source_code: &str, mode: Mode, @@ -65517,14 +65654,14 @@ fn __action1354< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action847( + __action848( source_code, mode, __0, @@ -65534,23 +65671,23 @@ fn __action1354< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1355< +fn __action1357< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), -) -> Result> + __0: (TextSize, token::Tok, TextSize), +) -> ast::Expr { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action848( + __action849( source_code, mode, __0, @@ -65560,7 +65697,7 @@ fn __action1355< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1356< +fn __action1358< >( source_code: &str, mode: Mode, @@ -65570,14 +65707,14 @@ fn __action1356< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action849( + __action850( source_code, mode, __0, @@ -65588,7 +65725,7 @@ fn __action1356< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1357< +fn __action1359< >( source_code: &str, mode: Mode, @@ -65600,14 +65737,14 @@ fn __action1357< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action850( + __action851( source_code, mode, __0, @@ -65620,7 +65757,7 @@ fn __action1357< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1358< +fn __action1360< >( source_code: &str, mode: Mode, @@ -65631,14 +65768,14 @@ fn __action1358< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action851( + __action852( source_code, mode, __0, @@ -65650,7 +65787,7 @@ fn __action1358< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1359< +fn __action1361< >( source_code: &str, mode: Mode, @@ -65663,14 +65800,14 @@ fn __action1359< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action852( + __action853( source_code, mode, __0, @@ -65684,7 +65821,7 @@ fn __action1359< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1360< +fn __action1362< >( source_code: &str, mode: Mode, @@ -65696,14 +65833,14 @@ fn __action1360< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action853( + __action854( source_code, mode, __0, @@ -65716,7 +65853,7 @@ fn __action1360< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1361< +fn __action1363< >( source_code: &str, mode: Mode, @@ -65731,14 +65868,14 @@ fn __action1361< { let __start0 = __6.2; let __end0 = __6.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action854( + __action855( source_code, mode, __0, @@ -65754,7 +65891,7 @@ fn __action1361< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1362< +fn __action1364< >( source_code: &str, mode: Mode, @@ -65768,14 +65905,14 @@ fn __action1362< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action855( + __action856( source_code, mode, __0, @@ -65790,7 +65927,7 @@ fn __action1362< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1363< +fn __action1365< >( source_code: &str, mode: Mode, @@ -65801,14 +65938,14 @@ fn __action1363< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action857( + __action858( source_code, mode, __0, @@ -65820,7 +65957,7 @@ fn __action1363< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1364< +fn __action1366< >( source_code: &str, mode: Mode, @@ -65829,14 +65966,14 @@ fn __action1364< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action858( + __action859( source_code, mode, __0, @@ -65846,7 +65983,7 @@ fn __action1364< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1365< +fn __action1367< >( source_code: &str, mode: Mode, @@ -65857,14 +65994,14 @@ fn __action1365< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action859( + __action860( source_code, mode, __0, @@ -65876,7 +66013,7 @@ fn __action1365< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1366< +fn __action1368< >( source_code: &str, mode: Mode, @@ -65887,14 +66024,14 @@ fn __action1366< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action860( + __action861( source_code, mode, __0, @@ -65906,7 +66043,7 @@ fn __action1366< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1367< +fn __action1369< >( source_code: &str, mode: Mode, @@ -65922,14 +66059,14 @@ fn __action1367< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action862( + __action863( source_code, mode, __0, @@ -65946,7 +66083,7 @@ fn __action1367< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1368< +fn __action1370< >( source_code: &str, mode: Mode, @@ -65962,14 +66099,14 @@ fn __action1368< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action863( + __action864( source_code, mode, __0, @@ -65986,7 +66123,7 @@ fn __action1368< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1369< +fn __action1371< >( source_code: &str, mode: Mode, @@ -66001,14 +66138,14 @@ fn __action1369< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action864( + __action865( source_code, mode, __0, @@ -66024,7 +66161,7 @@ fn __action1369< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1370< +fn __action1372< >( source_code: &str, mode: Mode, @@ -66035,14 +66172,14 @@ fn __action1370< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action865( + __action866( source_code, mode, __0, @@ -66054,7 +66191,7 @@ fn __action1370< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1371< +fn __action1373< >( source_code: &str, mode: Mode, @@ -66063,14 +66200,14 @@ fn __action1371< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action866( + __action867( source_code, mode, __0, @@ -66080,7 +66217,7 @@ fn __action1371< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1372< +fn __action1374< >( source_code: &str, mode: Mode, @@ -66090,14 +66227,14 @@ fn __action1372< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action867( + __action868( source_code, mode, __0, @@ -66108,7 +66245,7 @@ fn __action1372< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1373< +fn __action1375< >( source_code: &str, mode: Mode, @@ -66118,14 +66255,14 @@ fn __action1373< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action868( + __action869( source_code, mode, __0, @@ -66136,7 +66273,7 @@ fn __action1373< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1374< +fn __action1376< >( source_code: &str, mode: Mode, @@ -66146,14 +66283,14 @@ fn __action1374< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action869( + __action870( source_code, mode, __0, @@ -66164,7 +66301,7 @@ fn __action1374< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1375< +fn __action1377< >( source_code: &str, mode: Mode, @@ -66173,14 +66310,14 @@ fn __action1375< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action870( + __action871( source_code, mode, __0, @@ -66190,7 +66327,7 @@ fn __action1375< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1376< +fn __action1378< >( source_code: &str, mode: Mode, @@ -66200,14 +66337,14 @@ fn __action1376< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action871( + __action872( source_code, mode, __0, @@ -66218,7 +66355,7 @@ fn __action1376< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1377< +fn __action1379< >( source_code: &str, mode: Mode, @@ -66227,14 +66364,14 @@ fn __action1377< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action872( + __action873( source_code, mode, __0, @@ -66244,7 +66381,7 @@ fn __action1377< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1378< +fn __action1380< >( source_code: &str, mode: Mode, @@ -66254,14 +66391,14 @@ fn __action1378< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action873( + __action874( source_code, mode, __0, @@ -66272,7 +66409,7 @@ fn __action1378< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1379< +fn __action1381< >( source_code: &str, mode: Mode, @@ -66282,14 +66419,14 @@ fn __action1379< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action874( + __action875( source_code, mode, __0, @@ -66300,7 +66437,7 @@ fn __action1379< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1380< +fn __action1382< >( source_code: &str, mode: Mode, @@ -66311,14 +66448,14 @@ fn __action1380< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action495( + __action498( source_code, mode, __0, @@ -66330,7 +66467,7 @@ fn __action1380< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1381< +fn __action1383< >( source_code: &str, mode: Mode, @@ -66341,14 +66478,14 @@ fn __action1381< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action484( + __action487( source_code, mode, __0, @@ -66360,7 +66497,7 @@ fn __action1381< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1382< +fn __action1384< >( source_code: &str, mode: Mode, @@ -66375,14 +66512,14 @@ fn __action1382< { let __start0 = __6.2; let __end0 = __6.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action998( + __action1001( source_code, mode, __0, @@ -66398,7 +66535,7 @@ fn __action1382< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1383< +fn __action1385< >( source_code: &str, mode: Mode, @@ -66412,14 +66549,14 @@ fn __action1383< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action999( + __action1002( source_code, mode, __0, @@ -66434,7 +66571,7 @@ fn __action1383< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1384< +fn __action1386< >( source_code: &str, mode: Mode, @@ -66450,14 +66587,14 @@ fn __action1384< { let __start0 = __7.2; let __end0 = __7.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1000( + __action1003( source_code, mode, __0, @@ -66474,7 +66611,7 @@ fn __action1384< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1385< +fn __action1387< >( source_code: &str, mode: Mode, @@ -66489,14 +66626,14 @@ fn __action1385< { let __start0 = __6.2; let __end0 = __6.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1001( + __action1004( source_code, mode, __0, @@ -66512,7 +66649,7 @@ fn __action1385< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1386< +fn __action1388< >( source_code: &str, mode: Mode, @@ -66525,14 +66662,14 @@ fn __action1386< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1002( + __action1005( source_code, mode, __0, @@ -66546,7 +66683,7 @@ fn __action1386< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1387< +fn __action1389< >( source_code: &str, mode: Mode, @@ -66558,14 +66695,14 @@ fn __action1387< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1003( + __action1006( source_code, mode, __0, @@ -66578,7 +66715,7 @@ fn __action1387< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1388< +fn __action1390< >( source_code: &str, mode: Mode, @@ -66592,14 +66729,14 @@ fn __action1388< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1004( + __action1007( source_code, mode, __0, @@ -66614,7 +66751,7 @@ fn __action1388< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1389< +fn __action1391< >( source_code: &str, mode: Mode, @@ -66627,14 +66764,14 @@ fn __action1389< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1005( + __action1008( source_code, mode, __0, @@ -66648,7 +66785,7 @@ fn __action1389< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1390< +fn __action1392< >( source_code: &str, mode: Mode, @@ -66658,14 +66795,14 @@ fn __action1390< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1006( + __action1009( source_code, mode, __0, @@ -66676,7 +66813,7 @@ fn __action1390< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1391< +fn __action1393< >( source_code: &str, mode: Mode, @@ -66690,14 +66827,14 @@ fn __action1391< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1007( + __action1010( source_code, mode, __0, @@ -66712,7 +66849,7 @@ fn __action1391< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1392< +fn __action1394< >( source_code: &str, mode: Mode, @@ -66725,14 +66862,14 @@ fn __action1392< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1008( + __action1011( source_code, mode, __0, @@ -66746,7 +66883,7 @@ fn __action1392< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1393< +fn __action1395< >( source_code: &str, mode: Mode, @@ -66761,14 +66898,14 @@ fn __action1393< { let __start0 = __6.2; let __end0 = __6.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1009( + __action1012( source_code, mode, __0, @@ -66784,7 +66921,7 @@ fn __action1393< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1394< +fn __action1396< >( source_code: &str, mode: Mode, @@ -66798,14 +66935,14 @@ fn __action1394< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1010( + __action1013( source_code, mode, __0, @@ -66820,7 +66957,7 @@ fn __action1394< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1395< +fn __action1397< >( source_code: &str, mode: Mode, @@ -66832,14 +66969,14 @@ fn __action1395< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1011( + __action1014( source_code, mode, __0, @@ -66852,7 +66989,7 @@ fn __action1395< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1396< +fn __action1398< >( source_code: &str, mode: Mode, @@ -66863,14 +67000,14 @@ fn __action1396< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1012( + __action1015( source_code, mode, __0, @@ -66882,7 +67019,7 @@ fn __action1396< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1397< +fn __action1399< >( source_code: &str, mode: Mode, @@ -66895,14 +67032,14 @@ fn __action1397< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1013( + __action1016( source_code, mode, __0, @@ -66916,7 +67053,7 @@ fn __action1397< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1398< +fn __action1400< >( source_code: &str, mode: Mode, @@ -66928,14 +67065,14 @@ fn __action1398< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1014( + __action1017( source_code, mode, __0, @@ -66948,7 +67085,7 @@ fn __action1398< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1399< +fn __action1401< >( source_code: &str, mode: Mode, @@ -66957,14 +67094,14 @@ fn __action1399< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1015( + __action1018( source_code, mode, __0, @@ -66974,7 +67111,7 @@ fn __action1399< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1400< +fn __action1402< >( source_code: &str, mode: Mode, @@ -66986,14 +67123,14 @@ fn __action1400< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action877( + __action878( source_code, mode, __0, @@ -67006,7 +67143,7 @@ fn __action1400< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1401< +fn __action1403< >( source_code: &str, mode: Mode, @@ -67017,14 +67154,14 @@ fn __action1401< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action878( + __action879( source_code, mode, __0, @@ -67036,7 +67173,7 @@ fn __action1401< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1402< +fn __action1404< >( source_code: &str, mode: Mode, @@ -67049,14 +67186,14 @@ fn __action1402< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action974( + __action977( source_code, mode, __0, @@ -67070,7 +67207,7 @@ fn __action1402< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1403< +fn __action1405< >( source_code: &str, mode: Mode, @@ -67082,14 +67219,14 @@ fn __action1403< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action975( + __action978( source_code, mode, __0, @@ -67102,7 +67239,7 @@ fn __action1403< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1404< +fn __action1406< >( source_code: &str, mode: Mode, @@ -67116,14 +67253,14 @@ fn __action1404< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action976( + __action979( source_code, mode, __0, @@ -67138,7 +67275,7 @@ fn __action1404< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1405< +fn __action1407< >( source_code: &str, mode: Mode, @@ -67151,14 +67288,14 @@ fn __action1405< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action977( + __action980( source_code, mode, __0, @@ -67172,7 +67309,7 @@ fn __action1405< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1406< +fn __action1408< >( source_code: &str, mode: Mode, @@ -67183,14 +67320,14 @@ fn __action1406< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action978( + __action981( source_code, mode, __0, @@ -67202,7 +67339,7 @@ fn __action1406< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1407< +fn __action1409< >( source_code: &str, mode: Mode, @@ -67212,14 +67349,14 @@ fn __action1407< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action979( + __action982( source_code, mode, __0, @@ -67230,7 +67367,7 @@ fn __action1407< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1408< +fn __action1410< >( source_code: &str, mode: Mode, @@ -67242,14 +67379,14 @@ fn __action1408< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action980( + __action983( source_code, mode, __0, @@ -67262,7 +67399,7 @@ fn __action1408< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1409< +fn __action1411< >( source_code: &str, mode: Mode, @@ -67273,14 +67410,14 @@ fn __action1409< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action981( + __action984( source_code, mode, __0, @@ -67292,7 +67429,7 @@ fn __action1409< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1410< +fn __action1412< >( source_code: &str, mode: Mode, @@ -67304,14 +67441,14 @@ fn __action1410< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action982( + __action985( source_code, mode, __0, @@ -67324,7 +67461,7 @@ fn __action1410< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1411< +fn __action1413< >( source_code: &str, mode: Mode, @@ -67335,14 +67472,14 @@ fn __action1411< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action983( + __action986( source_code, mode, __0, @@ -67354,7 +67491,7 @@ fn __action1411< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1412< +fn __action1414< >( source_code: &str, mode: Mode, @@ -67367,14 +67504,14 @@ fn __action1412< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action984( + __action987( source_code, mode, __0, @@ -67388,7 +67525,7 @@ fn __action1412< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1413< +fn __action1415< >( source_code: &str, mode: Mode, @@ -67400,14 +67537,14 @@ fn __action1413< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action985( + __action988( source_code, mode, __0, @@ -67420,7 +67557,7 @@ fn __action1413< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1414< +fn __action1416< >( source_code: &str, mode: Mode, @@ -67430,14 +67567,14 @@ fn __action1414< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action986( + __action989( source_code, mode, __0, @@ -67448,7 +67585,7 @@ fn __action1414< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1415< +fn __action1417< >( source_code: &str, mode: Mode, @@ -67457,14 +67594,14 @@ fn __action1415< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action987( + __action990( source_code, mode, __0, @@ -67474,7 +67611,7 @@ fn __action1415< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1416< +fn __action1418< >( source_code: &str, mode: Mode, @@ -67485,14 +67622,14 @@ fn __action1416< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action988( + __action991( source_code, mode, __0, @@ -67504,7 +67641,7 @@ fn __action1416< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1417< +fn __action1419< >( source_code: &str, mode: Mode, @@ -67514,14 +67651,14 @@ fn __action1417< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action989( + __action992( source_code, mode, __0, @@ -67532,7 +67669,7 @@ fn __action1417< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1418< +fn __action1420< >( source_code: &str, mode: Mode, @@ -67542,14 +67679,14 @@ fn __action1418< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action881( + __action882( source_code, mode, __0, @@ -67560,7 +67697,7 @@ fn __action1418< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1419< +fn __action1421< >( source_code: &str, mode: Mode, @@ -67569,14 +67706,14 @@ fn __action1419< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action882( + __action883( source_code, mode, __0, @@ -67586,7 +67723,7 @@ fn __action1419< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1420< +fn __action1422< >( source_code: &str, mode: Mode, @@ -67601,14 +67738,14 @@ fn __action1420< { let __start0 = __6.2; let __end0 = __6.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1058( + __action1061( source_code, mode, __0, @@ -67624,7 +67761,7 @@ fn __action1420< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1421< +fn __action1423< >( source_code: &str, mode: Mode, @@ -67638,14 +67775,14 @@ fn __action1421< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1059( + __action1062( source_code, mode, __0, @@ -67660,7 +67797,7 @@ fn __action1421< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1422< +fn __action1424< >( source_code: &str, mode: Mode, @@ -67676,14 +67813,14 @@ fn __action1422< { let __start0 = __7.2; let __end0 = __7.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1060( + __action1063( source_code, mode, __0, @@ -67700,7 +67837,7 @@ fn __action1422< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1423< +fn __action1425< >( source_code: &str, mode: Mode, @@ -67715,14 +67852,14 @@ fn __action1423< { let __start0 = __6.2; let __end0 = __6.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1061( + __action1064( source_code, mode, __0, @@ -67738,7 +67875,7 @@ fn __action1423< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1424< +fn __action1426< >( source_code: &str, mode: Mode, @@ -67751,14 +67888,14 @@ fn __action1424< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1062( + __action1065( source_code, mode, __0, @@ -67772,7 +67909,7 @@ fn __action1424< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1425< +fn __action1427< >( source_code: &str, mode: Mode, @@ -67784,14 +67921,14 @@ fn __action1425< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1063( + __action1066( source_code, mode, __0, @@ -67804,7 +67941,7 @@ fn __action1425< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1426< +fn __action1428< >( source_code: &str, mode: Mode, @@ -67818,14 +67955,14 @@ fn __action1426< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1064( + __action1067( source_code, mode, __0, @@ -67840,7 +67977,7 @@ fn __action1426< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1427< +fn __action1429< >( source_code: &str, mode: Mode, @@ -67853,14 +67990,14 @@ fn __action1427< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1065( + __action1068( source_code, mode, __0, @@ -67874,7 +68011,7 @@ fn __action1427< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1428< +fn __action1430< >( source_code: &str, mode: Mode, @@ -67884,14 +68021,14 @@ fn __action1428< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1066( + __action1069( source_code, mode, __0, @@ -67902,7 +68039,7 @@ fn __action1428< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1429< +fn __action1431< >( source_code: &str, mode: Mode, @@ -67916,14 +68053,14 @@ fn __action1429< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1067( + __action1070( source_code, mode, __0, @@ -67938,7 +68075,7 @@ fn __action1429< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1430< +fn __action1432< >( source_code: &str, mode: Mode, @@ -67951,14 +68088,14 @@ fn __action1430< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1068( + __action1071( source_code, mode, __0, @@ -67972,7 +68109,7 @@ fn __action1430< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1431< +fn __action1433< >( source_code: &str, mode: Mode, @@ -67987,14 +68124,14 @@ fn __action1431< { let __start0 = __6.2; let __end0 = __6.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1069( + __action1072( source_code, mode, __0, @@ -68010,7 +68147,7 @@ fn __action1431< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1432< +fn __action1434< >( source_code: &str, mode: Mode, @@ -68024,14 +68161,14 @@ fn __action1432< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1070( + __action1073( source_code, mode, __0, @@ -68046,7 +68183,7 @@ fn __action1432< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1433< +fn __action1435< >( source_code: &str, mode: Mode, @@ -68058,14 +68195,14 @@ fn __action1433< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1071( + __action1074( source_code, mode, __0, @@ -68078,7 +68215,7 @@ fn __action1433< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1434< +fn __action1436< >( source_code: &str, mode: Mode, @@ -68089,14 +68226,14 @@ fn __action1434< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1072( + __action1075( source_code, mode, __0, @@ -68108,7 +68245,7 @@ fn __action1434< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1435< +fn __action1437< >( source_code: &str, mode: Mode, @@ -68121,14 +68258,14 @@ fn __action1435< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1073( + __action1076( source_code, mode, __0, @@ -68142,7 +68279,7 @@ fn __action1435< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1436< +fn __action1438< >( source_code: &str, mode: Mode, @@ -68154,14 +68291,14 @@ fn __action1436< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1074( + __action1077( source_code, mode, __0, @@ -68174,7 +68311,7 @@ fn __action1436< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1437< +fn __action1439< >( source_code: &str, mode: Mode, @@ -68183,14 +68320,14 @@ fn __action1437< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1075( + __action1078( source_code, mode, __0, @@ -68200,7 +68337,7 @@ fn __action1437< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1438< +fn __action1440< >( source_code: &str, mode: Mode, @@ -68212,14 +68349,14 @@ fn __action1438< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action885( + __action886( source_code, mode, __0, @@ -68232,7 +68369,7 @@ fn __action1438< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1439< +fn __action1441< >( source_code: &str, mode: Mode, @@ -68243,14 +68380,14 @@ fn __action1439< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action886( + __action887( source_code, mode, __0, @@ -68262,7 +68399,7 @@ fn __action1439< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1440< +fn __action1442< >( source_code: &str, mode: Mode, @@ -68275,14 +68412,14 @@ fn __action1440< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1034( + __action1037( source_code, mode, __0, @@ -68296,7 +68433,7 @@ fn __action1440< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1441< +fn __action1443< >( source_code: &str, mode: Mode, @@ -68308,14 +68445,14 @@ fn __action1441< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1035( + __action1038( source_code, mode, __0, @@ -68328,7 +68465,7 @@ fn __action1441< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1442< +fn __action1444< >( source_code: &str, mode: Mode, @@ -68342,14 +68479,14 @@ fn __action1442< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1036( + __action1039( source_code, mode, __0, @@ -68364,7 +68501,7 @@ fn __action1442< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1443< +fn __action1445< >( source_code: &str, mode: Mode, @@ -68377,14 +68514,14 @@ fn __action1443< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1037( + __action1040( source_code, mode, __0, @@ -68398,7 +68535,7 @@ fn __action1443< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1444< +fn __action1446< >( source_code: &str, mode: Mode, @@ -68409,14 +68546,14 @@ fn __action1444< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1038( + __action1041( source_code, mode, __0, @@ -68428,7 +68565,7 @@ fn __action1444< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1445< +fn __action1447< >( source_code: &str, mode: Mode, @@ -68438,14 +68575,14 @@ fn __action1445< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1039( + __action1042( source_code, mode, __0, @@ -68456,7 +68593,7 @@ fn __action1445< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1446< +fn __action1448< >( source_code: &str, mode: Mode, @@ -68468,14 +68605,14 @@ fn __action1446< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1040( + __action1043( source_code, mode, __0, @@ -68488,7 +68625,7 @@ fn __action1446< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1447< +fn __action1449< >( source_code: &str, mode: Mode, @@ -68499,14 +68636,14 @@ fn __action1447< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1041( + __action1044( source_code, mode, __0, @@ -68518,7 +68655,7 @@ fn __action1447< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1448< +fn __action1450< >( source_code: &str, mode: Mode, @@ -68530,14 +68667,14 @@ fn __action1448< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1042( + __action1045( source_code, mode, __0, @@ -68550,7 +68687,7 @@ fn __action1448< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1449< +fn __action1451< >( source_code: &str, mode: Mode, @@ -68561,14 +68698,14 @@ fn __action1449< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1043( + __action1046( source_code, mode, __0, @@ -68580,7 +68717,7 @@ fn __action1449< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1450< +fn __action1452< >( source_code: &str, mode: Mode, @@ -68593,14 +68730,14 @@ fn __action1450< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1044( + __action1047( source_code, mode, __0, @@ -68614,7 +68751,7 @@ fn __action1450< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1451< +fn __action1453< >( source_code: &str, mode: Mode, @@ -68626,14 +68763,14 @@ fn __action1451< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1045( + __action1048( source_code, mode, __0, @@ -68646,7 +68783,7 @@ fn __action1451< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1452< +fn __action1454< >( source_code: &str, mode: Mode, @@ -68656,14 +68793,14 @@ fn __action1452< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1046( + __action1049( source_code, mode, __0, @@ -68674,7 +68811,7 @@ fn __action1452< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1453< +fn __action1455< >( source_code: &str, mode: Mode, @@ -68683,14 +68820,14 @@ fn __action1453< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1047( + __action1050( source_code, mode, __0, @@ -68700,7 +68837,7 @@ fn __action1453< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1454< +fn __action1456< >( source_code: &str, mode: Mode, @@ -68711,14 +68848,14 @@ fn __action1454< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1048( + __action1051( source_code, mode, __0, @@ -68730,7 +68867,7 @@ fn __action1454< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1455< +fn __action1457< >( source_code: &str, mode: Mode, @@ -68740,14 +68877,14 @@ fn __action1455< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1049( + __action1052( source_code, mode, __0, @@ -68758,7 +68895,7 @@ fn __action1455< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1456< +fn __action1458< >( source_code: &str, mode: Mode, @@ -68768,14 +68905,14 @@ fn __action1456< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action889( + __action890( source_code, mode, __0, @@ -68786,7 +68923,7 @@ fn __action1456< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1457< +fn __action1459< >( source_code: &str, mode: Mode, @@ -68795,14 +68932,14 @@ fn __action1457< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action890( + __action891( source_code, mode, __0, @@ -68812,7 +68949,7 @@ fn __action1457< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1458< +fn __action1460< >( source_code: &str, mode: Mode, @@ -68823,14 +68960,14 @@ fn __action1458< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1223( + __action1226( source_code, mode, __0, @@ -68842,7 +68979,7 @@ fn __action1458< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1459< +fn __action1461< >( source_code: &str, mode: Mode, @@ -68852,14 +68989,14 @@ fn __action1459< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1224( + __action1227( source_code, mode, __0, @@ -68870,7 +69007,7 @@ fn __action1459< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1460< +fn __action1462< >( source_code: &str, mode: Mode, @@ -68879,14 +69016,14 @@ fn __action1460< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action904( + __action905( source_code, mode, __0, @@ -68896,7 +69033,7 @@ fn __action1460< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1461< +fn __action1463< >( source_code: &str, mode: Mode, @@ -68910,14 +69047,14 @@ fn __action1461< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action905( + __action906( source_code, mode, __0, @@ -68932,7 +69069,7 @@ fn __action1461< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1462< +fn __action1464< >( source_code: &str, mode: Mode, @@ -68945,14 +69082,14 @@ fn __action1462< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action906( + __action907( source_code, mode, __0, @@ -68966,7 +69103,7 @@ fn __action1462< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1463< +fn __action1465< >( source_code: &str, mode: Mode, @@ -68978,14 +69115,14 @@ fn __action1463< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action907( + __action908( source_code, mode, __0, @@ -68998,7 +69135,7 @@ fn __action1463< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1464< +fn __action1466< >( source_code: &str, mode: Mode, @@ -69009,14 +69146,14 @@ fn __action1464< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action908( + __action909( source_code, mode, __0, @@ -69028,7 +69165,7 @@ fn __action1464< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1465< +fn __action1467< >( source_code: &str, mode: Mode, @@ -69040,14 +69177,14 @@ fn __action1465< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action909( + __action910( source_code, mode, __0, @@ -69060,7 +69197,7 @@ fn __action1465< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1466< +fn __action1468< >( source_code: &str, mode: Mode, @@ -69071,14 +69208,14 @@ fn __action1466< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action910( + __action911( source_code, mode, __0, @@ -69090,7 +69227,7 @@ fn __action1466< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1467< +fn __action1469< >( source_code: &str, mode: Mode, @@ -69100,14 +69237,14 @@ fn __action1467< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action911( + __action912( source_code, mode, __0, @@ -69118,7 +69255,7 @@ fn __action1467< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1468< +fn __action1470< >( source_code: &str, mode: Mode, @@ -69128,14 +69265,14 @@ fn __action1468< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action912( + __action913( source_code, mode, __0, @@ -69146,7 +69283,7 @@ fn __action1468< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1469< +fn __action1471< >( source_code: &str, mode: Mode, @@ -69156,14 +69293,14 @@ fn __action1469< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action913( + __action914( source_code, mode, __0, @@ -69174,7 +69311,7 @@ fn __action1469< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1470< +fn __action1472< >( source_code: &str, mode: Mode, @@ -69183,14 +69320,14 @@ fn __action1470< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action914( + __action915( source_code, mode, __0, @@ -69200,7 +69337,7 @@ fn __action1470< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1471< +fn __action1473< >( source_code: &str, mode: Mode, @@ -69211,14 +69348,14 @@ fn __action1471< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action915( + __action916( source_code, mode, __0, @@ -69230,7 +69367,7 @@ fn __action1471< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1472< +fn __action1474< >( source_code: &str, mode: Mode, @@ -69241,14 +69378,14 @@ fn __action1472< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action916( + __action917( source_code, mode, __0, @@ -69260,7 +69397,7 @@ fn __action1472< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1473< +fn __action1475< >( source_code: &str, mode: Mode, @@ -69269,14 +69406,14 @@ fn __action1473< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action917( + __action918( source_code, mode, __0, @@ -69286,7 +69423,7 @@ fn __action1473< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1474< +fn __action1476< >( source_code: &str, mode: Mode, @@ -69298,14 +69435,14 @@ fn __action1474< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1145( + __action1148( source_code, mode, __0, @@ -69318,7 +69455,7 @@ fn __action1474< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1475< +fn __action1477< >( source_code: &str, mode: Mode, @@ -69328,14 +69465,14 @@ fn __action1475< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1146( + __action1149( source_code, mode, __0, @@ -69346,7 +69483,7 @@ fn __action1475< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1476< +fn __action1478< >( source_code: &str, mode: Mode, @@ -69357,14 +69494,14 @@ fn __action1476< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action919( + __action920( source_code, mode, __0, @@ -69376,7 +69513,7 @@ fn __action1476< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1477< +fn __action1479< >( source_code: &str, mode: Mode, @@ -69386,14 +69523,14 @@ fn __action1477< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action920( + __action921( source_code, mode, __0, @@ -69404,7 +69541,7 @@ fn __action1477< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1478< +fn __action1480< >( source_code: &str, mode: Mode, @@ -69416,14 +69553,14 @@ fn __action1478< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action921( + __action922( source_code, mode, __0, @@ -69436,7 +69573,7 @@ fn __action1478< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1479< +fn __action1481< >( source_code: &str, mode: Mode, @@ -69449,14 +69586,14 @@ fn __action1479< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action922( + __action923( source_code, mode, __0, @@ -69470,7 +69607,7 @@ fn __action1479< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1480< +fn __action1482< >( source_code: &str, mode: Mode, @@ -69482,14 +69619,14 @@ fn __action1480< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action923( + __action924( source_code, mode, __0, @@ -69502,7 +69639,7 @@ fn __action1480< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1481< +fn __action1483< >( source_code: &str, mode: Mode, @@ -69513,14 +69650,14 @@ fn __action1481< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action924( + __action925( source_code, mode, __0, @@ -69532,7 +69669,7 @@ fn __action1481< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1482< +fn __action1484< >( source_code: &str, mode: Mode, @@ -69543,14 +69680,14 @@ fn __action1482< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action925( + __action926( source_code, mode, __0, @@ -69562,7 +69699,7 @@ fn __action1482< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1483< +fn __action1485< >( source_code: &str, mode: Mode, @@ -69573,14 +69710,14 @@ fn __action1483< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action926( + __action927( source_code, mode, __0, @@ -69592,7 +69729,7 @@ fn __action1483< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1484< +fn __action1486< >( source_code: &str, mode: Mode, @@ -69606,14 +69743,14 @@ fn __action1484< { let __start0 = __5.2; let __end0 = __5.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action927( + __action928( source_code, mode, __0, @@ -69628,7 +69765,7 @@ fn __action1484< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1485< +fn __action1487< >( source_code: &str, mode: Mode, @@ -69641,14 +69778,14 @@ fn __action1485< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action928( + __action929( source_code, mode, __0, @@ -69662,7 +69799,7 @@ fn __action1485< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1486< +fn __action1488< >( source_code: &str, mode: Mode, @@ -69672,14 +69809,14 @@ fn __action1486< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action930( + __action931( source_code, mode, __0, @@ -69690,7 +69827,7 @@ fn __action1486< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1487< +fn __action1489< >( source_code: &str, mode: Mode, @@ -69700,14 +69837,14 @@ fn __action1487< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action931( + __action932( source_code, mode, __0, @@ -69718,7 +69855,7 @@ fn __action1487< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1488< +fn __action1490< >( source_code: &str, mode: Mode, @@ -69729,14 +69866,14 @@ fn __action1488< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1110( + __action1113( source_code, mode, __0, @@ -69748,7 +69885,7 @@ fn __action1488< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1489< +fn __action1491< >( source_code: &str, mode: Mode, @@ -69757,14 +69894,14 @@ fn __action1489< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1111( + __action1114( source_code, mode, __0, @@ -69774,7 +69911,7 @@ fn __action1489< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1490< +fn __action1492< >( source_code: &str, mode: Mode, @@ -69783,14 +69920,14 @@ fn __action1490< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action933( + __action934( source_code, mode, __0, @@ -69800,7 +69937,59 @@ fn __action1490< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1491< +fn __action1493< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, Vec, TextSize), +) -> Result> +{ + let __start0 = __0.2; + let __end0 = __0.2; + let __temp0 = __action416( + source_code, + mode, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action936( + source_code, + mode, + __0, + __temp0, + ) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action1494< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, (String, StringKind, bool), TextSize), +) -> Result> +{ + let __start0 = __0.2; + let __end0 = __0.2; + let __temp0 = __action416( + source_code, + mode, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action937( + source_code, + mode, + __0, + __temp0, + ) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action1495< >( source_code: &str, mode: Mode, @@ -69812,14 +70001,14 @@ fn __action1491< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action935( + __action938( source_code, mode, __0, @@ -69832,7 +70021,7 @@ fn __action1491< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1492< +fn __action1496< >( source_code: &str, mode: Mode, @@ -69842,14 +70031,14 @@ fn __action1492< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action936( + __action939( source_code, mode, __0, @@ -69860,7 +70049,7 @@ fn __action1492< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1493< +fn __action1497< >( source_code: &str, mode: Mode, @@ -69870,14 +70059,14 @@ fn __action1493< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action937( + __action940( source_code, mode, __0, @@ -69888,7 +70077,7 @@ fn __action1493< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1494< +fn __action1498< >( source_code: &str, mode: Mode, @@ -69897,14 +70086,14 @@ fn __action1494< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action938( + __action941( source_code, mode, __0, @@ -69914,7 +70103,7 @@ fn __action1494< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1495< +fn __action1499< >( source_code: &str, mode: Mode, @@ -69925,14 +70114,14 @@ fn __action1495< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action939( + __action942( source_code, mode, __0, @@ -69944,7 +70133,7 @@ fn __action1495< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1496< +fn __action1500< >( source_code: &str, mode: Mode, @@ -69955,14 +70144,14 @@ fn __action1496< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action940( + __action943( source_code, mode, __0, @@ -69974,7 +70163,7 @@ fn __action1496< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1497< +fn __action1501< >( source_code: &str, mode: Mode, @@ -69987,14 +70176,14 @@ fn __action1497< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action941( + __action944( source_code, mode, __0, @@ -70008,7 +70197,7 @@ fn __action1497< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1498< +fn __action1502< >( source_code: &str, mode: Mode, @@ -70021,14 +70210,14 @@ fn __action1498< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action942( + __action945( source_code, mode, __0, @@ -70042,7 +70231,7 @@ fn __action1498< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1499< +fn __action1503< >( source_code: &str, mode: Mode, @@ -70052,14 +70241,14 @@ fn __action1499< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action943( + __action946( source_code, mode, __0, @@ -70070,7 +70259,7 @@ fn __action1499< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1500< +fn __action1504< >( source_code: &str, mode: Mode, @@ -70080,14 +70269,14 @@ fn __action1500< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1116( + __action1119( source_code, mode, __0, @@ -70098,7 +70287,7 @@ fn __action1500< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1501< +fn __action1505< >( source_code: &str, mode: Mode, @@ -70109,171 +70298,19 @@ fn __action1501< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( - source_code, - mode, - &__start0, - &__end0, - ); - let __temp0 = (__start0, __temp0, __end0); - __action1117( - source_code, - mode, - __0, - __1, - __2, - __temp0, - ) -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action1502< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::Suite, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), - __4: (TextSize, token::Tok, TextSize), - __5: (TextSize, token::Tok, TextSize), - __6: (TextSize, ast::Suite, TextSize), - __7: (TextSize, token::Tok, TextSize), - __8: (TextSize, token::Tok, TextSize), - __9: (TextSize, ast::Suite, TextSize), -) -> ast::Stmt -{ - let __start0 = __9.2; - let __end0 = __9.2; - let __temp0 = __action413( - source_code, - mode, - &__start0, - &__end0, - ); - let __temp0 = (__start0, __temp0, __end0); - __action1136( - source_code, - mode, - __0, - __1, - __2, - __3, - __4, - __5, - __6, - __7, - __8, - __9, - __temp0, - ) -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action1503< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::Suite, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), - __4: (TextSize, token::Tok, TextSize), - __5: (TextSize, token::Tok, TextSize), - __6: (TextSize, ast::Suite, TextSize), -) -> ast::Stmt -{ - let __start0 = __6.2; - let __end0 = __6.2; - let __temp0 = __action413( - source_code, - mode, - &__start0, - &__end0, - ); - let __temp0 = (__start0, __temp0, __end0); - __action1137( - source_code, - mode, - __0, - __1, - __2, - __3, - __4, - __5, - __6, - __temp0, - ) -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action1504< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::Suite, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), - __4: (TextSize, token::Tok, TextSize), - __5: (TextSize, token::Tok, TextSize), - __6: (TextSize, ast::Suite, TextSize), -) -> ast::Stmt -{ - let __start0 = __6.2; - let __end0 = __6.2; - let __temp0 = __action413( - source_code, - mode, - &__start0, - &__end0, - ); - let __temp0 = (__start0, __temp0, __end0); - __action1138( - source_code, - mode, - __0, - __1, - __2, - __3, - __4, - __5, - __6, - __temp0, - ) -} - -#[allow(unused_variables)] -#[allow(clippy::too_many_arguments)] -fn __action1505< ->( - source_code: &str, - mode: Mode, - __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::Suite, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), -) -> ast::Stmt -{ - let __start0 = __3.2; - let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1139( + __action1120( source_code, mode, __0, __1, __2, - __3, __temp0, ) } @@ -70298,14 +70335,14 @@ fn __action1506< { let __start0 = __9.2; let __end0 = __9.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1140( + __action1139( source_code, mode, __0, @@ -70339,14 +70376,14 @@ fn __action1507< { let __start0 = __6.2; let __end0 = __6.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1141( + __action1140( source_code, mode, __0, @@ -70377,14 +70414,14 @@ fn __action1508< { let __start0 = __6.2; let __end0 = __6.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1142( + __action1141( source_code, mode, __0, @@ -70412,14 +70449,14 @@ fn __action1509< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1143( + __action1142( source_code, mode, __0, @@ -70433,6 +70470,158 @@ fn __action1509< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] fn __action1510< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, token::Tok, TextSize), + __1: (TextSize, token::Tok, TextSize), + __2: (TextSize, ast::Suite, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), + __4: (TextSize, token::Tok, TextSize), + __5: (TextSize, token::Tok, TextSize), + __6: (TextSize, ast::Suite, TextSize), + __7: (TextSize, token::Tok, TextSize), + __8: (TextSize, token::Tok, TextSize), + __9: (TextSize, ast::Suite, TextSize), +) -> ast::Stmt +{ + let __start0 = __9.2; + let __end0 = __9.2; + let __temp0 = __action416( + source_code, + mode, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action1143( + source_code, + mode, + __0, + __1, + __2, + __3, + __4, + __5, + __6, + __7, + __8, + __9, + __temp0, + ) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action1511< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, token::Tok, TextSize), + __1: (TextSize, token::Tok, TextSize), + __2: (TextSize, ast::Suite, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), + __4: (TextSize, token::Tok, TextSize), + __5: (TextSize, token::Tok, TextSize), + __6: (TextSize, ast::Suite, TextSize), +) -> ast::Stmt +{ + let __start0 = __6.2; + let __end0 = __6.2; + let __temp0 = __action416( + source_code, + mode, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action1144( + source_code, + mode, + __0, + __1, + __2, + __3, + __4, + __5, + __6, + __temp0, + ) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action1512< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, token::Tok, TextSize), + __1: (TextSize, token::Tok, TextSize), + __2: (TextSize, ast::Suite, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), + __4: (TextSize, token::Tok, TextSize), + __5: (TextSize, token::Tok, TextSize), + __6: (TextSize, ast::Suite, TextSize), +) -> ast::Stmt +{ + let __start0 = __6.2; + let __end0 = __6.2; + let __temp0 = __action416( + source_code, + mode, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action1145( + source_code, + mode, + __0, + __1, + __2, + __3, + __4, + __5, + __6, + __temp0, + ) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action1513< +>( + source_code: &str, + mode: Mode, + __0: (TextSize, token::Tok, TextSize), + __1: (TextSize, token::Tok, TextSize), + __2: (TextSize, ast::Suite, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), +) -> ast::Stmt +{ + let __start0 = __3.2; + let __end0 = __3.2; + let __temp0 = __action416( + source_code, + mode, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action1146( + source_code, + mode, + __0, + __1, + __2, + __3, + __temp0, + ) +} + +#[allow(unused_variables)] +#[allow(clippy::too_many_arguments)] +fn __action1514< >( source_code: &str, mode: Mode, @@ -70441,14 +70630,14 @@ fn __action1510< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action948( + __action951( source_code, mode, __0, @@ -70458,7 +70647,7 @@ fn __action1510< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1511< +fn __action1515< >( source_code: &str, mode: Mode, @@ -70471,14 +70660,14 @@ fn __action1511< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action949( + __action952( source_code, mode, __0, @@ -70492,7 +70681,7 @@ fn __action1511< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1512< +fn __action1516< >( source_code: &str, mode: Mode, @@ -70503,14 +70692,14 @@ fn __action1512< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1105( + __action1108( source_code, mode, __0, @@ -70522,7 +70711,7 @@ fn __action1512< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1513< +fn __action1517< >( source_code: &str, mode: Mode, @@ -70531,14 +70720,14 @@ fn __action1513< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1106( + __action1109( source_code, mode, __0, @@ -70548,7 +70737,7 @@ fn __action1513< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1514< +fn __action1518< >( source_code: &str, mode: Mode, @@ -70558,14 +70747,14 @@ fn __action1514< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action951( + __action954( source_code, mode, __0, @@ -70576,7 +70765,7 @@ fn __action1514< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1515< +fn __action1519< >( source_code: &str, mode: Mode, @@ -70586,14 +70775,14 @@ fn __action1515< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action952( + __action955( source_code, mode, __0, @@ -70604,7 +70793,7 @@ fn __action1515< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1516< +fn __action1520< >( source_code: &str, mode: Mode, @@ -70616,14 +70805,14 @@ fn __action1516< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action953( + __action956( source_code, mode, __0, @@ -70636,7 +70825,7 @@ fn __action1516< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1517< +fn __action1521< >( source_code: &str, mode: Mode, @@ -70647,14 +70836,14 @@ fn __action1517< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action954( + __action957( source_code, mode, __0, @@ -70666,7 +70855,7 @@ fn __action1517< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1518< +fn __action1522< >( source_code: &str, mode: Mode, @@ -70677,14 +70866,14 @@ fn __action1518< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1107( + __action1110( source_code, mode, __0, @@ -70696,7 +70885,7 @@ fn __action1518< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1519< +fn __action1523< >( source_code: &str, mode: Mode, @@ -70705,14 +70894,14 @@ fn __action1519< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1108( + __action1111( source_code, mode, __0, @@ -70722,7 +70911,7 @@ fn __action1519< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1520< +fn __action1524< >( source_code: &str, mode: Mode, @@ -70731,14 +70920,14 @@ fn __action1520< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action956( + __action959( source_code, mode, __0, @@ -70748,7 +70937,7 @@ fn __action1520< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1521< +fn __action1525< >( source_code: &str, mode: Mode, @@ -70757,14 +70946,14 @@ fn __action1521< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action957( + __action960( source_code, mode, __0, @@ -70774,7 +70963,7 @@ fn __action1521< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1522< +fn __action1526< >( source_code: &str, mode: Mode, @@ -70785,14 +70974,14 @@ fn __action1522< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action959( + __action962( source_code, mode, __0, @@ -70804,7 +70993,7 @@ fn __action1522< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1523< +fn __action1527< >( source_code: &str, mode: Mode, @@ -70815,14 +71004,14 @@ fn __action1523< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action962( + __action965( source_code, mode, __0, @@ -70834,7 +71023,7 @@ fn __action1523< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1524< +fn __action1528< >( source_code: &str, mode: Mode, @@ -70845,14 +71034,14 @@ fn __action1524< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action963( + __action966( source_code, mode, __0, @@ -70864,7 +71053,7 @@ fn __action1524< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1525< +fn __action1529< >( source_code: &str, mode: Mode, @@ -70874,14 +71063,14 @@ fn __action1525< { let __start0 = __1.2; let __end0 = __1.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action964( + __action967( source_code, mode, __0, @@ -70892,7 +71081,7 @@ fn __action1525< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1526< +fn __action1530< >( source_code: &str, mode: Mode, @@ -70903,14 +71092,14 @@ fn __action1526< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action413( + let __temp0 = __action416( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action965( + __action968( source_code, mode, __0, @@ -70922,7 +71111,7 @@ fn __action1526< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1527< +fn __action1531< >( source_code: &str, mode: Mode, @@ -70937,13 +71126,13 @@ fn __action1527< { let __start0 = __4.0; let __end0 = __4.2; - let __temp0 = __action286( + let __temp0 = __action291( source_code, mode, __4, ); let __temp0 = (__start0, __temp0, __end0); - __action781( + __action782( source_code, mode, __0, @@ -70958,7 +71147,7 @@ fn __action1527< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1528< +fn __action1532< >( source_code: &str, mode: Mode, @@ -70972,14 +71161,14 @@ fn __action1528< { let __start0 = __3.2; let __end0 = __4.0; - let __temp0 = __action287( + let __temp0 = __action292( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action781( + __action782( source_code, mode, __0, @@ -70994,7 +71183,7 @@ fn __action1528< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1529< +fn __action1533< >( source_code: &str, mode: Mode, @@ -71003,14 +71192,14 @@ fn __action1529< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action403( + let __temp0 = __action406( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1309( + __action1310( source_code, mode, __0, @@ -71020,7 +71209,7 @@ fn __action1529< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1530< +fn __action1534< >( source_code: &str, mode: Mode, @@ -71030,13 +71219,13 @@ fn __action1530< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action404( + let __temp0 = __action407( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1309( + __action1310( source_code, mode, __0, @@ -71046,7 +71235,7 @@ fn __action1530< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1531< +fn __action1535< >( source_code: &str, mode: Mode, @@ -71058,13 +71247,13 @@ fn __action1531< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action398( + let __temp0 = __action401( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1311( + __action1312( source_code, mode, __0, @@ -71076,7 +71265,7 @@ fn __action1531< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1532< +fn __action1536< >( source_code: &str, mode: Mode, @@ -71087,14 +71276,14 @@ fn __action1532< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action399( + let __temp0 = __action402( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1311( + __action1312( source_code, mode, __0, @@ -71106,7 +71295,7 @@ fn __action1532< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1533< +fn __action1537< >( source_code: &str, mode: Mode, @@ -71115,13 +71304,13 @@ fn __action1533< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action464( + let __temp0 = __action467( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1160( + __action1163( source_code, mode, __temp0, @@ -71130,7 +71319,7 @@ fn __action1533< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1534< +fn __action1538< >( source_code: &str, mode: Mode, @@ -71140,14 +71329,14 @@ fn __action1534< { let __start0 = *__lookbehind; let __end0 = *__lookahead; - let __temp0 = __action465( + let __temp0 = __action468( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1160( + __action1163( source_code, mode, __temp0, @@ -71156,7 +71345,7 @@ fn __action1534< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1535< +fn __action1539< >( source_code: &str, mode: Mode, @@ -71166,13 +71355,13 @@ fn __action1535< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action464( + let __temp0 = __action467( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1161( + __action1164( source_code, mode, __0, @@ -71182,7 +71371,7 @@ fn __action1535< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1536< +fn __action1540< >( source_code: &str, mode: Mode, @@ -71191,14 +71380,14 @@ fn __action1536< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action465( + let __temp0 = __action468( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1161( + __action1164( source_code, mode, __0, @@ -71208,7 +71397,7 @@ fn __action1536< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1537< +fn __action1541< >( source_code: &str, mode: Mode, @@ -71219,13 +71408,13 @@ fn __action1537< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action1533( + let __temp0 = __action1537( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1230( + __action1233( source_code, mode, __0, @@ -71236,7 +71425,7 @@ fn __action1537< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1538< +fn __action1542< >( source_code: &str, mode: Mode, @@ -71246,14 +71435,14 @@ fn __action1538< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action1534( + let __temp0 = __action1538( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1230( + __action1233( source_code, mode, __0, @@ -71264,7 +71453,7 @@ fn __action1538< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1539< +fn __action1543< >( source_code: &str, mode: Mode, @@ -71276,14 +71465,14 @@ fn __action1539< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1535( + let __temp0 = __action1539( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1230( + __action1233( source_code, mode, __0, @@ -71294,7 +71483,7 @@ fn __action1539< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1540< +fn __action1544< >( source_code: &str, mode: Mode, @@ -71305,13 +71494,13 @@ fn __action1540< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action1536( + let __temp0 = __action1540( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1230( + __action1233( source_code, mode, __0, @@ -71322,7 +71511,7 @@ fn __action1540< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1541< +fn __action1545< >( source_code: &str, mode: Mode, @@ -71331,13 +71520,13 @@ fn __action1541< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action426( + let __temp0 = __action429( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1183( + __action1186( source_code, mode, __temp0, @@ -71346,7 +71535,7 @@ fn __action1541< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1542< +fn __action1546< >( source_code: &str, mode: Mode, @@ -71356,14 +71545,14 @@ fn __action1542< { let __start0 = *__lookbehind; let __end0 = *__lookahead; - let __temp0 = __action427( + let __temp0 = __action430( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1183( + __action1186( source_code, mode, __temp0, @@ -71372,7 +71561,7 @@ fn __action1542< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1543< +fn __action1547< >( source_code: &str, mode: Mode, @@ -71382,13 +71571,13 @@ fn __action1543< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action426( + let __temp0 = __action429( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1184( + __action1187( source_code, mode, __0, @@ -71398,7 +71587,7 @@ fn __action1543< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1544< +fn __action1548< >( source_code: &str, mode: Mode, @@ -71407,14 +71596,14 @@ fn __action1544< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action427( + let __temp0 = __action430( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1184( + __action1187( source_code, mode, __0, @@ -71424,7 +71613,7 @@ fn __action1544< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1545< +fn __action1549< >( source_code: &str, mode: Mode, @@ -71435,13 +71624,13 @@ fn __action1545< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action1541( + let __temp0 = __action1545( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1481( + __action1483( source_code, mode, __0, @@ -71452,7 +71641,7 @@ fn __action1545< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1546< +fn __action1550< >( source_code: &str, mode: Mode, @@ -71462,14 +71651,14 @@ fn __action1546< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action1542( + let __temp0 = __action1546( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1481( + __action1483( source_code, mode, __0, @@ -71480,7 +71669,7 @@ fn __action1546< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1547< +fn __action1551< >( source_code: &str, mode: Mode, @@ -71492,14 +71681,14 @@ fn __action1547< { let __start0 = __1.0; let __end0 = __2.2; - let __temp0 = __action1543( + let __temp0 = __action1547( source_code, mode, __1, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1481( + __action1483( source_code, mode, __0, @@ -71510,7 +71699,7 @@ fn __action1547< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1548< +fn __action1552< >( source_code: &str, mode: Mode, @@ -71521,13 +71710,13 @@ fn __action1548< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action1544( + let __temp0 = __action1548( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1481( + __action1483( source_code, mode, __0, @@ -71538,7 +71727,7 @@ fn __action1548< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1549< +fn __action1553< >( source_code: &str, mode: Mode, @@ -71548,13 +71737,13 @@ fn __action1549< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action247( + let __temp0 = __action250( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1322( + __action1324( source_code, mode, __0, @@ -71564,7 +71753,7 @@ fn __action1549< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1550< +fn __action1554< >( source_code: &str, mode: Mode, @@ -71573,14 +71762,14 @@ fn __action1550< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action248( + let __temp0 = __action251( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1322( + __action1324( source_code, mode, __0, @@ -71590,7 +71779,7 @@ fn __action1550< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1551< +fn __action1555< >( source_code: &str, mode: Mode, @@ -71603,14 +71792,14 @@ fn __action1551< { let __start0 = __4.2; let __end0 = __4.2; - let __temp0 = __action250( + let __temp0 = __action253( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1484( + __action1486( source_code, mode, __0, @@ -71624,7 +71813,7 @@ fn __action1551< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1552< +fn __action1556< >( source_code: &str, mode: Mode, @@ -71638,13 +71827,13 @@ fn __action1552< { let __start0 = __5.0; let __end0 = __5.2; - let __temp0 = __action251( + let __temp0 = __action254( source_code, mode, __5, ); let __temp0 = (__start0, __temp0, __end0); - __action1484( + __action1486( source_code, mode, __0, @@ -71658,7 +71847,7 @@ fn __action1552< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1553< +fn __action1557< >( source_code: &str, mode: Mode, @@ -71670,14 +71859,14 @@ fn __action1553< { let __start0 = __3.2; let __end0 = __3.2; - let __temp0 = __action250( + let __temp0 = __action253( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1485( + __action1487( source_code, mode, __0, @@ -71690,7 +71879,7 @@ fn __action1553< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1554< +fn __action1558< >( source_code: &str, mode: Mode, @@ -71703,13 +71892,13 @@ fn __action1554< { let __start0 = __4.0; let __end0 = __4.2; - let __temp0 = __action251( + let __temp0 = __action254( source_code, mode, __4, ); let __temp0 = (__start0, __temp0, __end0); - __action1485( + __action1487( source_code, mode, __0, @@ -71722,7 +71911,7 @@ fn __action1554< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1555< +fn __action1559< >( source_code: &str, mode: Mode, @@ -71736,14 +71925,14 @@ fn __action1555< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action306( + let __temp0 = __action311( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1527( + __action1531( source_code, mode, __temp0, @@ -71758,7 +71947,7 @@ fn __action1555< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1556< +fn __action1560< >( source_code: &str, mode: Mode, @@ -71773,13 +71962,13 @@ fn __action1556< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action307( + let __temp0 = __action312( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1527( + __action1531( source_code, mode, __temp0, @@ -71794,7 +71983,7 @@ fn __action1556< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1557< +fn __action1561< >( source_code: &str, mode: Mode, @@ -71807,14 +71996,14 @@ fn __action1557< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action306( + let __temp0 = __action311( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1528( + __action1532( source_code, mode, __temp0, @@ -71828,7 +72017,7 @@ fn __action1557< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1558< +fn __action1562< >( source_code: &str, mode: Mode, @@ -71842,13 +72031,13 @@ fn __action1558< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action307( + let __temp0 = __action312( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1528( + __action1532( source_code, mode, __temp0, @@ -71862,7 +72051,7 @@ fn __action1558< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1559< +fn __action1563< >( source_code: &str, mode: Mode, @@ -71879,14 +72068,14 @@ fn __action1559< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action306( + let __temp0 = __action311( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1096( + __action1099( source_code, mode, __temp0, @@ -71904,7 +72093,7 @@ fn __action1559< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1560< +fn __action1564< >( source_code: &str, mode: Mode, @@ -71922,13 +72111,13 @@ fn __action1560< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action307( + let __temp0 = __action312( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1096( + __action1099( source_code, mode, __temp0, @@ -71946,7 +72135,7 @@ fn __action1560< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1561< +fn __action1565< >( source_code: &str, mode: Mode, @@ -71961,14 +72150,14 @@ fn __action1561< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action306( + let __temp0 = __action311( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1097( + __action1100( source_code, mode, __temp0, @@ -71984,7 +72173,7 @@ fn __action1561< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1562< +fn __action1566< >( source_code: &str, mode: Mode, @@ -72000,13 +72189,13 @@ fn __action1562< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action307( + let __temp0 = __action312( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1097( + __action1100( source_code, mode, __temp0, @@ -72022,7 +72211,7 @@ fn __action1562< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1563< +fn __action1567< >( source_code: &str, mode: Mode, @@ -72038,14 +72227,14 @@ fn __action1563< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action306( + let __temp0 = __action311( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1098( + __action1101( source_code, mode, __temp0, @@ -72062,7 +72251,7 @@ fn __action1563< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1564< +fn __action1568< >( source_code: &str, mode: Mode, @@ -72079,13 +72268,13 @@ fn __action1564< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action307( + let __temp0 = __action312( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1098( + __action1101( source_code, mode, __temp0, @@ -72102,7 +72291,7 @@ fn __action1564< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1565< +fn __action1569< >( source_code: &str, mode: Mode, @@ -72116,14 +72305,14 @@ fn __action1565< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action306( + let __temp0 = __action311( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1099( + __action1102( source_code, mode, __temp0, @@ -72138,7 +72327,7 @@ fn __action1565< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1566< +fn __action1570< >( source_code: &str, mode: Mode, @@ -72153,13 +72342,13 @@ fn __action1566< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action307( + let __temp0 = __action312( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1099( + __action1102( source_code, mode, __temp0, @@ -72174,7 +72363,7 @@ fn __action1566< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1567< +fn __action1571< >( source_code: &str, mode: Mode, @@ -72185,13 +72374,13 @@ fn __action1567< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action564( + let __temp0 = __action567( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1255( + __action1257( source_code, mode, __0, @@ -72202,7 +72391,7 @@ fn __action1567< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1568< +fn __action1572< >( source_code: &str, mode: Mode, @@ -72212,14 +72401,14 @@ fn __action1568< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action565( + let __temp0 = __action568( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1255( + __action1257( source_code, mode, __0, @@ -72230,7 +72419,7 @@ fn __action1568< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1569< +fn __action1573< >( source_code: &str, mode: Mode, @@ -72241,13 +72430,13 @@ fn __action1569< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action564( + let __temp0 = __action567( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1280( + __action1281( source_code, mode, __0, @@ -72258,7 +72447,7 @@ fn __action1569< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1570< +fn __action1574< >( source_code: &str, mode: Mode, @@ -72268,14 +72457,14 @@ fn __action1570< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action565( + let __temp0 = __action568( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1280( + __action1281( source_code, mode, __0, @@ -72286,7 +72475,7 @@ fn __action1570< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1571< +fn __action1575< >( source_code: &str, mode: Mode, @@ -72296,13 +72485,13 @@ fn __action1571< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action498( + let __temp0 = __action501( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action438( + __action441( source_code, mode, __0, @@ -72312,7 +72501,7 @@ fn __action1571< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1572< +fn __action1576< >( source_code: &str, mode: Mode, @@ -72321,14 +72510,14 @@ fn __action1572< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action499( + let __temp0 = __action502( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action438( + __action441( source_code, mode, __0, @@ -72338,7 +72527,7 @@ fn __action1572< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1573< +fn __action1577< >( source_code: &str, mode: Mode, @@ -72352,13 +72541,13 @@ fn __action1573< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action266( + let __temp0 = __action269( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1314( + __action1316( source_code, mode, __0, @@ -72372,7 +72561,7 @@ fn __action1573< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1574< +fn __action1578< >( source_code: &str, mode: Mode, @@ -72385,14 +72574,14 @@ fn __action1574< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action267( + let __temp0 = __action270( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1314( + __action1316( source_code, mode, __0, @@ -72406,7 +72595,7 @@ fn __action1574< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1575< +fn __action1579< >( source_code: &str, mode: Mode, @@ -72419,13 +72608,13 @@ fn __action1575< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action266( + let __temp0 = __action269( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1315( + __action1317( source_code, mode, __0, @@ -72438,7 +72627,7 @@ fn __action1575< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1576< +fn __action1580< >( source_code: &str, mode: Mode, @@ -72450,14 +72639,14 @@ fn __action1576< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action267( + let __temp0 = __action270( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1315( + __action1317( source_code, mode, __0, @@ -72470,7 +72659,7 @@ fn __action1576< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1577< +fn __action1581< >( source_code: &str, mode: Mode, @@ -72484,13 +72673,13 @@ fn __action1577< { let __start0 = __4.0; let __end0 = __4.2; - let __temp0 = __action264( + let __temp0 = __action267( source_code, mode, __4, ); let __temp0 = (__start0, __temp0, __end0); - __action1573( + __action1577( source_code, mode, __0, @@ -72504,7 +72693,7 @@ fn __action1577< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1578< +fn __action1582< >( source_code: &str, mode: Mode, @@ -72517,14 +72706,14 @@ fn __action1578< { let __start0 = __3.2; let __end0 = __4.0; - let __temp0 = __action265( + let __temp0 = __action268( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1573( + __action1577( source_code, mode, __0, @@ -72538,7 +72727,7 @@ fn __action1578< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1579< +fn __action1583< >( source_code: &str, mode: Mode, @@ -72551,13 +72740,13 @@ fn __action1579< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action264( + let __temp0 = __action267( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1574( + __action1578( source_code, mode, __0, @@ -72570,7 +72759,7 @@ fn __action1579< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1580< +fn __action1584< >( source_code: &str, mode: Mode, @@ -72582,14 +72771,14 @@ fn __action1580< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action265( + let __temp0 = __action268( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1574( + __action1578( source_code, mode, __0, @@ -72602,7 +72791,7 @@ fn __action1580< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1581< +fn __action1585< >( source_code: &str, mode: Mode, @@ -72615,13 +72804,13 @@ fn __action1581< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action264( + let __temp0 = __action267( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1575( + __action1579( source_code, mode, __0, @@ -72634,7 +72823,7 @@ fn __action1581< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1582< +fn __action1586< >( source_code: &str, mode: Mode, @@ -72646,14 +72835,14 @@ fn __action1582< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action265( + let __temp0 = __action268( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1575( + __action1579( source_code, mode, __0, @@ -72666,7 +72855,7 @@ fn __action1582< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1583< +fn __action1587< >( source_code: &str, mode: Mode, @@ -72678,13 +72867,13 @@ fn __action1583< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action264( + let __temp0 = __action267( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1576( + __action1580( source_code, mode, __0, @@ -72696,7 +72885,7 @@ fn __action1583< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1584< +fn __action1588< >( source_code: &str, mode: Mode, @@ -72707,14 +72896,14 @@ fn __action1584< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action265( + let __temp0 = __action268( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1576( + __action1580( source_code, mode, __0, @@ -72726,7 +72915,7 @@ fn __action1584< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1585< +fn __action1589< >( source_code: &str, mode: Mode, @@ -72736,14 +72925,14 @@ fn __action1585< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action270( + let __temp0 = __action273( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1312( + __action1313( source_code, mode, __0, @@ -72754,7 +72943,7 @@ fn __action1585< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1586< +fn __action1590< >( source_code: &str, mode: Mode, @@ -72765,13 +72954,13 @@ fn __action1586< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action271( + let __temp0 = __action274( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1312( + __action1313( source_code, mode, __0, @@ -72782,7 +72971,7 @@ fn __action1586< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1587< +fn __action1591< >( source_code: &str, mode: Mode, @@ -72792,14 +72981,14 @@ fn __action1587< { let __start0 = *__lookbehind; let __end0 = *__lookahead; - let __temp0 = __action270( + let __temp0 = __action273( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1313( + __action1314( source_code, mode, __temp0, @@ -72808,7 +72997,7 @@ fn __action1587< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1588< +fn __action1592< >( source_code: &str, mode: Mode, @@ -72817,13 +73006,13 @@ fn __action1588< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action271( + let __temp0 = __action274( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1313( + __action1314( source_code, mode, __temp0, @@ -72832,7 +73021,7 @@ fn __action1588< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1589< +fn __action1593< >( source_code: &str, mode: Mode, @@ -72843,7 +73032,7 @@ fn __action1589< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action1332( + let __temp0 = __action1334( source_code, mode, __0, @@ -72851,7 +73040,7 @@ fn __action1589< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action390( + __action393( source_code, mode, __temp0, @@ -72860,7 +73049,7 @@ fn __action1589< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1590< +fn __action1594< >( source_code: &str, mode: Mode, @@ -72869,13 +73058,13 @@ fn __action1590< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action1333( + let __temp0 = __action1335( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action390( + __action393( source_code, mode, __temp0, @@ -72884,7 +73073,7 @@ fn __action1590< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1591< +fn __action1595< >( source_code: &str, mode: Mode, @@ -72897,7 +73086,7 @@ fn __action1591< { let __start0 = __2.0; let __end0 = __4.2; - let __temp0 = __action1332( + let __temp0 = __action1334( source_code, mode, __2, @@ -72905,7 +73094,7 @@ fn __action1591< __4, ); let __temp0 = (__start0, __temp0, __end0); - __action391( + __action394( source_code, mode, __0, @@ -72916,7 +73105,7 @@ fn __action1591< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1592< +fn __action1596< >( source_code: &str, mode: Mode, @@ -72927,13 +73116,13 @@ fn __action1592< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action1333( + let __temp0 = __action1335( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action391( + __action394( source_code, mode, __0, @@ -72944,7 +73133,7 @@ fn __action1592< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1593< +fn __action1597< >( source_code: &str, mode: Mode, @@ -72955,7 +73144,7 @@ fn __action1593< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action1334( + let __temp0 = __action1336( source_code, mode, __0, @@ -72963,7 +73152,7 @@ fn __action1593< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action383( + __action386( source_code, mode, __temp0, @@ -72972,7 +73161,7 @@ fn __action1593< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1594< +fn __action1598< >( source_code: &str, mode: Mode, @@ -72981,13 +73170,13 @@ fn __action1594< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action1335( + let __temp0 = __action1337( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action383( + __action386( source_code, mode, __temp0, @@ -72996,7 +73185,7 @@ fn __action1594< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1595< +fn __action1599< >( source_code: &str, mode: Mode, @@ -73009,7 +73198,7 @@ fn __action1595< { let __start0 = __2.0; let __end0 = __4.2; - let __temp0 = __action1334( + let __temp0 = __action1336( source_code, mode, __2, @@ -73017,7 +73206,7 @@ fn __action1595< __4, ); let __temp0 = (__start0, __temp0, __end0); - __action384( + __action387( source_code, mode, __0, @@ -73028,7 +73217,7 @@ fn __action1595< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1596< +fn __action1600< >( source_code: &str, mode: Mode, @@ -73039,13 +73228,13 @@ fn __action1596< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action1335( + let __temp0 = __action1337( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action384( + __action387( source_code, mode, __0, @@ -73056,7 +73245,7 @@ fn __action1596< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1597< +fn __action1601< >( source_code: &str, mode: Mode, @@ -73065,7 +73254,7 @@ fn __action1597< { let __start0 = __0.0; let __end0 = __0.0; - let __temp0 = __action388( + let __temp0 = __action391( source_code, mode, &__start0, @@ -73082,7 +73271,7 @@ fn __action1597< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1598< +fn __action1602< >( source_code: &str, mode: Mode, @@ -73092,7 +73281,7 @@ fn __action1598< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action389( + let __temp0 = __action392( source_code, mode, __0, @@ -73108,7 +73297,7 @@ fn __action1598< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1599< +fn __action1603< >( source_code: &str, mode: Mode, @@ -73119,13 +73308,13 @@ fn __action1599< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action572( + let __temp0 = __action575( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1239( + __action1241( source_code, mode, __0, @@ -73136,7 +73325,7 @@ fn __action1599< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1600< +fn __action1604< >( source_code: &str, mode: Mode, @@ -73146,14 +73335,14 @@ fn __action1600< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action573( + let __temp0 = __action576( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1239( + __action1241( source_code, mode, __0, @@ -73164,7 +73353,7 @@ fn __action1600< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1601< +fn __action1605< >( source_code: &str, mode: Mode, @@ -73175,13 +73364,13 @@ fn __action1601< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action572( + let __temp0 = __action575( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1266( + __action1267( source_code, mode, __0, @@ -73192,7 +73381,7 @@ fn __action1601< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1602< +fn __action1606< >( source_code: &str, mode: Mode, @@ -73202,14 +73391,14 @@ fn __action1602< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action573( + let __temp0 = __action576( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1266( + __action1267( source_code, mode, __0, @@ -73220,7 +73409,7 @@ fn __action1602< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1603< +fn __action1607< >( source_code: &str, mode: Mode, @@ -73235,13 +73424,13 @@ fn __action1603< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1382( + __action1384( source_code, mode, __temp0, @@ -73256,7 +73445,7 @@ fn __action1603< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1604< +fn __action1608< >( source_code: &str, mode: Mode, @@ -73273,7 +73462,7 @@ fn __action1604< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -73281,7 +73470,7 @@ fn __action1604< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1382( + __action1384( source_code, mode, __temp0, @@ -73296,7 +73485,7 @@ fn __action1604< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1605< +fn __action1609< >( source_code: &str, mode: Mode, @@ -73314,7 +73503,7 @@ fn __action1605< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -73323,7 +73512,7 @@ fn __action1605< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1382( + __action1384( source_code, mode, __temp0, @@ -73338,7 +73527,7 @@ fn __action1605< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1606< +fn __action1610< >( source_code: &str, mode: Mode, @@ -73352,13 +73541,13 @@ fn __action1606< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1383( + __action1385( source_code, mode, __temp0, @@ -73372,7 +73561,7 @@ fn __action1606< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1607< +fn __action1611< >( source_code: &str, mode: Mode, @@ -73388,7 +73577,7 @@ fn __action1607< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -73396,7 +73585,7 @@ fn __action1607< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1383( + __action1385( source_code, mode, __temp0, @@ -73410,7 +73599,7 @@ fn __action1607< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1608< +fn __action1612< >( source_code: &str, mode: Mode, @@ -73427,7 +73616,7 @@ fn __action1608< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -73436,7 +73625,7 @@ fn __action1608< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1383( + __action1385( source_code, mode, __temp0, @@ -73450,7 +73639,7 @@ fn __action1608< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1609< +fn __action1613< >( source_code: &str, mode: Mode, @@ -73466,13 +73655,13 @@ fn __action1609< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1384( + __action1386( source_code, mode, __temp0, @@ -73488,7 +73677,7 @@ fn __action1609< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1610< +fn __action1614< >( source_code: &str, mode: Mode, @@ -73506,7 +73695,7 @@ fn __action1610< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -73514,7 +73703,7 @@ fn __action1610< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1384( + __action1386( source_code, mode, __temp0, @@ -73530,7 +73719,7 @@ fn __action1610< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1611< +fn __action1615< >( source_code: &str, mode: Mode, @@ -73549,7 +73738,7 @@ fn __action1611< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -73558,7 +73747,7 @@ fn __action1611< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1384( + __action1386( source_code, mode, __temp0, @@ -73574,7 +73763,7 @@ fn __action1611< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1612< +fn __action1616< >( source_code: &str, mode: Mode, @@ -73589,13 +73778,13 @@ fn __action1612< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1385( + __action1387( source_code, mode, __temp0, @@ -73610,7 +73799,7 @@ fn __action1612< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1613< +fn __action1617< >( source_code: &str, mode: Mode, @@ -73627,7 +73816,7 @@ fn __action1613< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -73635,7 +73824,7 @@ fn __action1613< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1385( + __action1387( source_code, mode, __temp0, @@ -73650,7 +73839,7 @@ fn __action1613< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1614< +fn __action1618< >( source_code: &str, mode: Mode, @@ -73668,7 +73857,7 @@ fn __action1614< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -73677,7 +73866,7 @@ fn __action1614< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1385( + __action1387( source_code, mode, __temp0, @@ -73692,7 +73881,7 @@ fn __action1614< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1615< +fn __action1619< >( source_code: &str, mode: Mode, @@ -73705,13 +73894,13 @@ fn __action1615< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1386( + __action1388( source_code, mode, __temp0, @@ -73724,7 +73913,7 @@ fn __action1615< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1616< +fn __action1620< >( source_code: &str, mode: Mode, @@ -73739,7 +73928,7 @@ fn __action1616< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -73747,7 +73936,7 @@ fn __action1616< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1386( + __action1388( source_code, mode, __temp0, @@ -73760,7 +73949,7 @@ fn __action1616< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1617< +fn __action1621< >( source_code: &str, mode: Mode, @@ -73776,7 +73965,7 @@ fn __action1617< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -73785,7 +73974,7 @@ fn __action1617< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1386( + __action1388( source_code, mode, __temp0, @@ -73798,7 +73987,7 @@ fn __action1617< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1618< +fn __action1622< >( source_code: &str, mode: Mode, @@ -73810,13 +73999,13 @@ fn __action1618< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1387( + __action1389( source_code, mode, __temp0, @@ -73828,7 +74017,7 @@ fn __action1618< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1619< +fn __action1623< >( source_code: &str, mode: Mode, @@ -73842,7 +74031,7 @@ fn __action1619< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -73850,7 +74039,7 @@ fn __action1619< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1387( + __action1389( source_code, mode, __temp0, @@ -73862,7 +74051,7 @@ fn __action1619< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1620< +fn __action1624< >( source_code: &str, mode: Mode, @@ -73877,7 +74066,7 @@ fn __action1620< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -73886,7 +74075,7 @@ fn __action1620< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1387( + __action1389( source_code, mode, __temp0, @@ -73898,7 +74087,7 @@ fn __action1620< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1621< +fn __action1625< >( source_code: &str, mode: Mode, @@ -73912,13 +74101,13 @@ fn __action1621< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1388( + __action1390( source_code, mode, __temp0, @@ -73932,7 +74121,7 @@ fn __action1621< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1622< +fn __action1626< >( source_code: &str, mode: Mode, @@ -73948,7 +74137,7 @@ fn __action1622< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -73956,7 +74145,7 @@ fn __action1622< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1388( + __action1390( source_code, mode, __temp0, @@ -73970,7 +74159,7 @@ fn __action1622< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1623< +fn __action1627< >( source_code: &str, mode: Mode, @@ -73987,7 +74176,7 @@ fn __action1623< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -73996,7 +74185,7 @@ fn __action1623< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1388( + __action1390( source_code, mode, __temp0, @@ -74010,7 +74199,7 @@ fn __action1623< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1624< +fn __action1628< >( source_code: &str, mode: Mode, @@ -74023,13 +74212,13 @@ fn __action1624< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1389( + __action1391( source_code, mode, __temp0, @@ -74042,7 +74231,7 @@ fn __action1624< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1625< +fn __action1629< >( source_code: &str, mode: Mode, @@ -74057,7 +74246,7 @@ fn __action1625< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -74065,7 +74254,7 @@ fn __action1625< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1389( + __action1391( source_code, mode, __temp0, @@ -74078,7 +74267,7 @@ fn __action1625< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1626< +fn __action1630< >( source_code: &str, mode: Mode, @@ -74094,7 +74283,7 @@ fn __action1626< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -74103,7 +74292,7 @@ fn __action1626< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1389( + __action1391( source_code, mode, __temp0, @@ -74116,7 +74305,7 @@ fn __action1626< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1627< +fn __action1631< >( source_code: &str, mode: Mode, @@ -74126,13 +74315,13 @@ fn __action1627< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1390( + __action1392( source_code, mode, __temp0, @@ -74142,7 +74331,7 @@ fn __action1627< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1628< +fn __action1632< >( source_code: &str, mode: Mode, @@ -74154,7 +74343,7 @@ fn __action1628< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -74162,7 +74351,7 @@ fn __action1628< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1390( + __action1392( source_code, mode, __temp0, @@ -74172,7 +74361,7 @@ fn __action1628< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1629< +fn __action1633< >( source_code: &str, mode: Mode, @@ -74185,7 +74374,7 @@ fn __action1629< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -74194,7 +74383,7 @@ fn __action1629< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1390( + __action1392( source_code, mode, __temp0, @@ -74204,7 +74393,7 @@ fn __action1629< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1630< +fn __action1634< >( source_code: &str, mode: Mode, @@ -74218,13 +74407,13 @@ fn __action1630< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1391( + __action1393( source_code, mode, __temp0, @@ -74238,7 +74427,7 @@ fn __action1630< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1631< +fn __action1635< >( source_code: &str, mode: Mode, @@ -74254,7 +74443,7 @@ fn __action1631< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -74262,7 +74451,7 @@ fn __action1631< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1391( + __action1393( source_code, mode, __temp0, @@ -74276,7 +74465,7 @@ fn __action1631< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1632< +fn __action1636< >( source_code: &str, mode: Mode, @@ -74293,7 +74482,7 @@ fn __action1632< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -74302,7 +74491,7 @@ fn __action1632< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1391( + __action1393( source_code, mode, __temp0, @@ -74316,7 +74505,7 @@ fn __action1632< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1633< +fn __action1637< >( source_code: &str, mode: Mode, @@ -74329,13 +74518,13 @@ fn __action1633< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1392( + __action1394( source_code, mode, __temp0, @@ -74348,7 +74537,7 @@ fn __action1633< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1634< +fn __action1638< >( source_code: &str, mode: Mode, @@ -74363,7 +74552,7 @@ fn __action1634< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -74371,7 +74560,7 @@ fn __action1634< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1392( + __action1394( source_code, mode, __temp0, @@ -74384,7 +74573,7 @@ fn __action1634< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1635< +fn __action1639< >( source_code: &str, mode: Mode, @@ -74400,7 +74589,7 @@ fn __action1635< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -74409,7 +74598,7 @@ fn __action1635< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1392( + __action1394( source_code, mode, __temp0, @@ -74422,7 +74611,7 @@ fn __action1635< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1636< +fn __action1640< >( source_code: &str, mode: Mode, @@ -74437,13 +74626,13 @@ fn __action1636< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1393( + __action1395( source_code, mode, __temp0, @@ -74458,7 +74647,7 @@ fn __action1636< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1637< +fn __action1641< >( source_code: &str, mode: Mode, @@ -74475,7 +74664,7 @@ fn __action1637< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -74483,7 +74672,7 @@ fn __action1637< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1393( + __action1395( source_code, mode, __temp0, @@ -74498,7 +74687,7 @@ fn __action1637< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1638< +fn __action1642< >( source_code: &str, mode: Mode, @@ -74516,7 +74705,7 @@ fn __action1638< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -74525,7 +74714,7 @@ fn __action1638< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1393( + __action1395( source_code, mode, __temp0, @@ -74540,7 +74729,7 @@ fn __action1638< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1639< +fn __action1643< >( source_code: &str, mode: Mode, @@ -74554,13 +74743,13 @@ fn __action1639< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1394( + __action1396( source_code, mode, __temp0, @@ -74574,7 +74763,7 @@ fn __action1639< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1640< +fn __action1644< >( source_code: &str, mode: Mode, @@ -74590,7 +74779,7 @@ fn __action1640< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -74598,7 +74787,7 @@ fn __action1640< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1394( + __action1396( source_code, mode, __temp0, @@ -74612,7 +74801,7 @@ fn __action1640< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1641< +fn __action1645< >( source_code: &str, mode: Mode, @@ -74629,7 +74818,7 @@ fn __action1641< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -74638,7 +74827,7 @@ fn __action1641< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1394( + __action1396( source_code, mode, __temp0, @@ -74652,7 +74841,7 @@ fn __action1641< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1642< +fn __action1646< >( source_code: &str, mode: Mode, @@ -74664,13 +74853,13 @@ fn __action1642< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1395( + __action1397( source_code, mode, __temp0, @@ -74682,7 +74871,7 @@ fn __action1642< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1643< +fn __action1647< >( source_code: &str, mode: Mode, @@ -74696,7 +74885,7 @@ fn __action1643< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -74704,7 +74893,7 @@ fn __action1643< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1395( + __action1397( source_code, mode, __temp0, @@ -74716,7 +74905,7 @@ fn __action1643< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1644< +fn __action1648< >( source_code: &str, mode: Mode, @@ -74731,7 +74920,7 @@ fn __action1644< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -74740,7 +74929,7 @@ fn __action1644< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1395( + __action1397( source_code, mode, __temp0, @@ -74752,7 +74941,7 @@ fn __action1644< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1645< +fn __action1649< >( source_code: &str, mode: Mode, @@ -74763,13 +74952,13 @@ fn __action1645< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1396( + __action1398( source_code, mode, __temp0, @@ -74780,7 +74969,7 @@ fn __action1645< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1646< +fn __action1650< >( source_code: &str, mode: Mode, @@ -74793,7 +74982,7 @@ fn __action1646< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -74801,7 +74990,7 @@ fn __action1646< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1396( + __action1398( source_code, mode, __temp0, @@ -74812,7 +75001,7 @@ fn __action1646< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1647< +fn __action1651< >( source_code: &str, mode: Mode, @@ -74826,7 +75015,7 @@ fn __action1647< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -74835,7 +75024,7 @@ fn __action1647< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1396( + __action1398( source_code, mode, __temp0, @@ -74846,7 +75035,7 @@ fn __action1647< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1648< +fn __action1652< >( source_code: &str, mode: Mode, @@ -74859,13 +75048,13 @@ fn __action1648< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1397( + __action1399( source_code, mode, __temp0, @@ -74878,7 +75067,7 @@ fn __action1648< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1649< +fn __action1653< >( source_code: &str, mode: Mode, @@ -74893,7 +75082,7 @@ fn __action1649< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -74901,7 +75090,7 @@ fn __action1649< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1397( + __action1399( source_code, mode, __temp0, @@ -74914,7 +75103,7 @@ fn __action1649< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1650< +fn __action1654< >( source_code: &str, mode: Mode, @@ -74930,7 +75119,7 @@ fn __action1650< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -74939,7 +75128,7 @@ fn __action1650< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1397( + __action1399( source_code, mode, __temp0, @@ -74952,7 +75141,7 @@ fn __action1650< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1651< +fn __action1655< >( source_code: &str, mode: Mode, @@ -74964,13 +75153,13 @@ fn __action1651< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1398( + __action1400( source_code, mode, __temp0, @@ -74982,7 +75171,7 @@ fn __action1651< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1652< +fn __action1656< >( source_code: &str, mode: Mode, @@ -74996,7 +75185,7 @@ fn __action1652< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -75004,7 +75193,7 @@ fn __action1652< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1398( + __action1400( source_code, mode, __temp0, @@ -75016,7 +75205,7 @@ fn __action1652< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1653< +fn __action1657< >( source_code: &str, mode: Mode, @@ -75031,7 +75220,7 @@ fn __action1653< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -75040,7 +75229,7 @@ fn __action1653< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1398( + __action1400( source_code, mode, __temp0, @@ -75052,7 +75241,7 @@ fn __action1653< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1654< +fn __action1658< >( source_code: &str, mode: Mode, @@ -75061,13 +75250,13 @@ fn __action1654< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1399( + __action1401( source_code, mode, __temp0, @@ -75076,7 +75265,7 @@ fn __action1654< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1655< +fn __action1659< >( source_code: &str, mode: Mode, @@ -75087,7 +75276,7 @@ fn __action1655< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -75095,7 +75284,7 @@ fn __action1655< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1399( + __action1401( source_code, mode, __temp0, @@ -75104,7 +75293,7 @@ fn __action1655< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1656< +fn __action1660< >( source_code: &str, mode: Mode, @@ -75116,7 +75305,7 @@ fn __action1656< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -75125,7 +75314,7 @@ fn __action1656< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1399( + __action1401( source_code, mode, __temp0, @@ -75134,7 +75323,7 @@ fn __action1656< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1657< +fn __action1661< >( source_code: &str, mode: Mode, @@ -75146,13 +75335,13 @@ fn __action1657< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1400( + __action1402( source_code, mode, __temp0, @@ -75164,7 +75353,7 @@ fn __action1657< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1658< +fn __action1662< >( source_code: &str, mode: Mode, @@ -75178,7 +75367,7 @@ fn __action1658< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -75186,7 +75375,7 @@ fn __action1658< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1400( + __action1402( source_code, mode, __temp0, @@ -75198,7 +75387,7 @@ fn __action1658< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1659< +fn __action1663< >( source_code: &str, mode: Mode, @@ -75213,7 +75402,7 @@ fn __action1659< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -75222,7 +75411,7 @@ fn __action1659< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1400( + __action1402( source_code, mode, __temp0, @@ -75234,7 +75423,7 @@ fn __action1659< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1660< +fn __action1664< >( source_code: &str, mode: Mode, @@ -75245,13 +75434,13 @@ fn __action1660< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action443( + let __temp0 = __action446( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1401( + __action1403( source_code, mode, __temp0, @@ -75262,7 +75451,7 @@ fn __action1660< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1661< +fn __action1665< >( source_code: &str, mode: Mode, @@ -75275,7 +75464,7 @@ fn __action1661< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action698( + let __temp0 = __action701( source_code, mode, __0, @@ -75283,7 +75472,7 @@ fn __action1661< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1401( + __action1403( source_code, mode, __temp0, @@ -75294,7 +75483,7 @@ fn __action1661< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1662< +fn __action1666< >( source_code: &str, mode: Mode, @@ -75308,7 +75497,7 @@ fn __action1662< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action699( + let __temp0 = __action702( source_code, mode, __0, @@ -75317,7 +75506,7 @@ fn __action1662< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1401( + __action1403( source_code, mode, __temp0, @@ -75328,7 +75517,7 @@ fn __action1662< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1663< +fn __action1667< >( source_code: &str, mode: Mode, @@ -75343,13 +75532,13 @@ fn __action1663< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1420( + __action1422( source_code, mode, __temp0, @@ -75364,7 +75553,7 @@ fn __action1663< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1664< +fn __action1668< >( source_code: &str, mode: Mode, @@ -75381,7 +75570,7 @@ fn __action1664< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -75389,7 +75578,7 @@ fn __action1664< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1420( + __action1422( source_code, mode, __temp0, @@ -75404,7 +75593,7 @@ fn __action1664< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1665< +fn __action1669< >( source_code: &str, mode: Mode, @@ -75422,7 +75611,7 @@ fn __action1665< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -75431,7 +75620,7 @@ fn __action1665< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1420( + __action1422( source_code, mode, __temp0, @@ -75446,7 +75635,7 @@ fn __action1665< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1666< +fn __action1670< >( source_code: &str, mode: Mode, @@ -75460,13 +75649,13 @@ fn __action1666< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1421( + __action1423( source_code, mode, __temp0, @@ -75480,7 +75669,7 @@ fn __action1666< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1667< +fn __action1671< >( source_code: &str, mode: Mode, @@ -75496,7 +75685,7 @@ fn __action1667< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -75504,7 +75693,7 @@ fn __action1667< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1421( + __action1423( source_code, mode, __temp0, @@ -75518,7 +75707,7 @@ fn __action1667< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1668< +fn __action1672< >( source_code: &str, mode: Mode, @@ -75535,7 +75724,7 @@ fn __action1668< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -75544,7 +75733,7 @@ fn __action1668< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1421( + __action1423( source_code, mode, __temp0, @@ -75558,7 +75747,7 @@ fn __action1668< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1669< +fn __action1673< >( source_code: &str, mode: Mode, @@ -75574,13 +75763,13 @@ fn __action1669< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1422( + __action1424( source_code, mode, __temp0, @@ -75596,7 +75785,7 @@ fn __action1669< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1670< +fn __action1674< >( source_code: &str, mode: Mode, @@ -75614,7 +75803,7 @@ fn __action1670< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -75622,7 +75811,7 @@ fn __action1670< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1422( + __action1424( source_code, mode, __temp0, @@ -75638,7 +75827,7 @@ fn __action1670< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1671< +fn __action1675< >( source_code: &str, mode: Mode, @@ -75657,7 +75846,7 @@ fn __action1671< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -75666,7 +75855,7 @@ fn __action1671< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1422( + __action1424( source_code, mode, __temp0, @@ -75682,7 +75871,7 @@ fn __action1671< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1672< +fn __action1676< >( source_code: &str, mode: Mode, @@ -75697,13 +75886,13 @@ fn __action1672< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1423( + __action1425( source_code, mode, __temp0, @@ -75718,7 +75907,7 @@ fn __action1672< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1673< +fn __action1677< >( source_code: &str, mode: Mode, @@ -75735,7 +75924,7 @@ fn __action1673< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -75743,7 +75932,7 @@ fn __action1673< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1423( + __action1425( source_code, mode, __temp0, @@ -75758,7 +75947,7 @@ fn __action1673< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1674< +fn __action1678< >( source_code: &str, mode: Mode, @@ -75776,7 +75965,7 @@ fn __action1674< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -75785,7 +75974,7 @@ fn __action1674< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1423( + __action1425( source_code, mode, __temp0, @@ -75800,7 +75989,7 @@ fn __action1674< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1675< +fn __action1679< >( source_code: &str, mode: Mode, @@ -75813,13 +76002,13 @@ fn __action1675< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1424( + __action1426( source_code, mode, __temp0, @@ -75832,7 +76021,7 @@ fn __action1675< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1676< +fn __action1680< >( source_code: &str, mode: Mode, @@ -75847,7 +76036,7 @@ fn __action1676< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -75855,7 +76044,7 @@ fn __action1676< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1424( + __action1426( source_code, mode, __temp0, @@ -75868,7 +76057,7 @@ fn __action1676< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1677< +fn __action1681< >( source_code: &str, mode: Mode, @@ -75884,7 +76073,7 @@ fn __action1677< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -75893,7 +76082,7 @@ fn __action1677< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1424( + __action1426( source_code, mode, __temp0, @@ -75906,7 +76095,7 @@ fn __action1677< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1678< +fn __action1682< >( source_code: &str, mode: Mode, @@ -75918,13 +76107,13 @@ fn __action1678< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1425( + __action1427( source_code, mode, __temp0, @@ -75936,7 +76125,7 @@ fn __action1678< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1679< +fn __action1683< >( source_code: &str, mode: Mode, @@ -75950,7 +76139,7 @@ fn __action1679< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -75958,7 +76147,7 @@ fn __action1679< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1425( + __action1427( source_code, mode, __temp0, @@ -75970,7 +76159,7 @@ fn __action1679< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1680< +fn __action1684< >( source_code: &str, mode: Mode, @@ -75985,7 +76174,7 @@ fn __action1680< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -75994,7 +76183,7 @@ fn __action1680< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1425( + __action1427( source_code, mode, __temp0, @@ -76006,7 +76195,7 @@ fn __action1680< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1681< +fn __action1685< >( source_code: &str, mode: Mode, @@ -76020,13 +76209,13 @@ fn __action1681< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1426( + __action1428( source_code, mode, __temp0, @@ -76040,7 +76229,7 @@ fn __action1681< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1682< +fn __action1686< >( source_code: &str, mode: Mode, @@ -76056,7 +76245,7 @@ fn __action1682< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -76064,7 +76253,7 @@ fn __action1682< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1426( + __action1428( source_code, mode, __temp0, @@ -76078,7 +76267,7 @@ fn __action1682< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1683< +fn __action1687< >( source_code: &str, mode: Mode, @@ -76095,7 +76284,7 @@ fn __action1683< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -76104,7 +76293,7 @@ fn __action1683< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1426( + __action1428( source_code, mode, __temp0, @@ -76118,7 +76307,7 @@ fn __action1683< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1684< +fn __action1688< >( source_code: &str, mode: Mode, @@ -76131,13 +76320,13 @@ fn __action1684< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1427( + __action1429( source_code, mode, __temp0, @@ -76150,7 +76339,7 @@ fn __action1684< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1685< +fn __action1689< >( source_code: &str, mode: Mode, @@ -76165,7 +76354,7 @@ fn __action1685< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -76173,7 +76362,7 @@ fn __action1685< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1427( + __action1429( source_code, mode, __temp0, @@ -76186,7 +76375,7 @@ fn __action1685< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1686< +fn __action1690< >( source_code: &str, mode: Mode, @@ -76202,7 +76391,7 @@ fn __action1686< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -76211,7 +76400,7 @@ fn __action1686< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1427( + __action1429( source_code, mode, __temp0, @@ -76224,7 +76413,7 @@ fn __action1686< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1687< +fn __action1691< >( source_code: &str, mode: Mode, @@ -76234,13 +76423,13 @@ fn __action1687< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1428( + __action1430( source_code, mode, __temp0, @@ -76250,7 +76439,7 @@ fn __action1687< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1688< +fn __action1692< >( source_code: &str, mode: Mode, @@ -76262,7 +76451,7 @@ fn __action1688< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -76270,7 +76459,7 @@ fn __action1688< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1428( + __action1430( source_code, mode, __temp0, @@ -76280,7 +76469,7 @@ fn __action1688< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1689< +fn __action1693< >( source_code: &str, mode: Mode, @@ -76293,7 +76482,7 @@ fn __action1689< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -76302,7 +76491,7 @@ fn __action1689< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1428( + __action1430( source_code, mode, __temp0, @@ -76312,7 +76501,7 @@ fn __action1689< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1690< +fn __action1694< >( source_code: &str, mode: Mode, @@ -76326,13 +76515,13 @@ fn __action1690< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1429( + __action1431( source_code, mode, __temp0, @@ -76346,7 +76535,7 @@ fn __action1690< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1691< +fn __action1695< >( source_code: &str, mode: Mode, @@ -76362,7 +76551,7 @@ fn __action1691< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -76370,7 +76559,7 @@ fn __action1691< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1429( + __action1431( source_code, mode, __temp0, @@ -76384,7 +76573,7 @@ fn __action1691< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1692< +fn __action1696< >( source_code: &str, mode: Mode, @@ -76401,7 +76590,7 @@ fn __action1692< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -76410,7 +76599,7 @@ fn __action1692< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1429( + __action1431( source_code, mode, __temp0, @@ -76424,7 +76613,7 @@ fn __action1692< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1693< +fn __action1697< >( source_code: &str, mode: Mode, @@ -76437,13 +76626,13 @@ fn __action1693< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1430( + __action1432( source_code, mode, __temp0, @@ -76456,7 +76645,7 @@ fn __action1693< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1694< +fn __action1698< >( source_code: &str, mode: Mode, @@ -76471,7 +76660,7 @@ fn __action1694< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -76479,7 +76668,7 @@ fn __action1694< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1430( + __action1432( source_code, mode, __temp0, @@ -76492,7 +76681,7 @@ fn __action1694< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1695< +fn __action1699< >( source_code: &str, mode: Mode, @@ -76508,7 +76697,7 @@ fn __action1695< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -76517,7 +76706,7 @@ fn __action1695< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1430( + __action1432( source_code, mode, __temp0, @@ -76530,7 +76719,7 @@ fn __action1695< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1696< +fn __action1700< >( source_code: &str, mode: Mode, @@ -76545,13 +76734,13 @@ fn __action1696< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1431( + __action1433( source_code, mode, __temp0, @@ -76566,7 +76755,7 @@ fn __action1696< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1697< +fn __action1701< >( source_code: &str, mode: Mode, @@ -76583,7 +76772,7 @@ fn __action1697< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -76591,7 +76780,7 @@ fn __action1697< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1431( + __action1433( source_code, mode, __temp0, @@ -76606,7 +76795,7 @@ fn __action1697< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1698< +fn __action1702< >( source_code: &str, mode: Mode, @@ -76624,7 +76813,7 @@ fn __action1698< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -76633,7 +76822,7 @@ fn __action1698< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1431( + __action1433( source_code, mode, __temp0, @@ -76648,7 +76837,7 @@ fn __action1698< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1699< +fn __action1703< >( source_code: &str, mode: Mode, @@ -76662,13 +76851,13 @@ fn __action1699< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1432( + __action1434( source_code, mode, __temp0, @@ -76682,7 +76871,7 @@ fn __action1699< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1700< +fn __action1704< >( source_code: &str, mode: Mode, @@ -76698,7 +76887,7 @@ fn __action1700< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -76706,7 +76895,7 @@ fn __action1700< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1432( + __action1434( source_code, mode, __temp0, @@ -76720,7 +76909,7 @@ fn __action1700< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1701< +fn __action1705< >( source_code: &str, mode: Mode, @@ -76737,7 +76926,7 @@ fn __action1701< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -76746,7 +76935,7 @@ fn __action1701< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1432( + __action1434( source_code, mode, __temp0, @@ -76760,7 +76949,7 @@ fn __action1701< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1702< +fn __action1706< >( source_code: &str, mode: Mode, @@ -76772,13 +76961,13 @@ fn __action1702< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1433( + __action1435( source_code, mode, __temp0, @@ -76790,7 +76979,7 @@ fn __action1702< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1703< +fn __action1707< >( source_code: &str, mode: Mode, @@ -76804,7 +76993,7 @@ fn __action1703< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -76812,7 +77001,7 @@ fn __action1703< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1433( + __action1435( source_code, mode, __temp0, @@ -76824,7 +77013,7 @@ fn __action1703< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1704< +fn __action1708< >( source_code: &str, mode: Mode, @@ -76839,7 +77028,7 @@ fn __action1704< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -76848,7 +77037,7 @@ fn __action1704< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1433( + __action1435( source_code, mode, __temp0, @@ -76860,7 +77049,7 @@ fn __action1704< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1705< +fn __action1709< >( source_code: &str, mode: Mode, @@ -76871,13 +77060,13 @@ fn __action1705< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1434( + __action1436( source_code, mode, __temp0, @@ -76888,7 +77077,7 @@ fn __action1705< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1706< +fn __action1710< >( source_code: &str, mode: Mode, @@ -76901,7 +77090,7 @@ fn __action1706< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -76909,7 +77098,7 @@ fn __action1706< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1434( + __action1436( source_code, mode, __temp0, @@ -76920,7 +77109,7 @@ fn __action1706< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1707< +fn __action1711< >( source_code: &str, mode: Mode, @@ -76934,7 +77123,7 @@ fn __action1707< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -76943,7 +77132,7 @@ fn __action1707< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1434( + __action1436( source_code, mode, __temp0, @@ -76954,7 +77143,7 @@ fn __action1707< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1708< +fn __action1712< >( source_code: &str, mode: Mode, @@ -76967,13 +77156,13 @@ fn __action1708< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1435( + __action1437( source_code, mode, __temp0, @@ -76986,7 +77175,7 @@ fn __action1708< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1709< +fn __action1713< >( source_code: &str, mode: Mode, @@ -77001,7 +77190,7 @@ fn __action1709< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -77009,7 +77198,7 @@ fn __action1709< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1435( + __action1437( source_code, mode, __temp0, @@ -77022,7 +77211,7 @@ fn __action1709< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1710< +fn __action1714< >( source_code: &str, mode: Mode, @@ -77038,7 +77227,7 @@ fn __action1710< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -77047,7 +77236,7 @@ fn __action1710< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1435( + __action1437( source_code, mode, __temp0, @@ -77060,7 +77249,7 @@ fn __action1710< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1711< +fn __action1715< >( source_code: &str, mode: Mode, @@ -77072,13 +77261,13 @@ fn __action1711< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1436( + __action1438( source_code, mode, __temp0, @@ -77090,7 +77279,7 @@ fn __action1711< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1712< +fn __action1716< >( source_code: &str, mode: Mode, @@ -77104,7 +77293,7 @@ fn __action1712< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -77112,7 +77301,7 @@ fn __action1712< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1436( + __action1438( source_code, mode, __temp0, @@ -77124,7 +77313,7 @@ fn __action1712< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1713< +fn __action1717< >( source_code: &str, mode: Mode, @@ -77139,7 +77328,7 @@ fn __action1713< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -77148,7 +77337,7 @@ fn __action1713< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1436( + __action1438( source_code, mode, __temp0, @@ -77160,7 +77349,7 @@ fn __action1713< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1714< +fn __action1718< >( source_code: &str, mode: Mode, @@ -77169,13 +77358,13 @@ fn __action1714< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1437( + __action1439( source_code, mode, __temp0, @@ -77184,7 +77373,7 @@ fn __action1714< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1715< +fn __action1719< >( source_code: &str, mode: Mode, @@ -77195,7 +77384,7 @@ fn __action1715< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -77203,7 +77392,7 @@ fn __action1715< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1437( + __action1439( source_code, mode, __temp0, @@ -77212,7 +77401,7 @@ fn __action1715< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1716< +fn __action1720< >( source_code: &str, mode: Mode, @@ -77224,7 +77413,7 @@ fn __action1716< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -77233,7 +77422,7 @@ fn __action1716< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1437( + __action1439( source_code, mode, __temp0, @@ -77242,7 +77431,7 @@ fn __action1716< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1717< +fn __action1721< >( source_code: &str, mode: Mode, @@ -77254,13 +77443,13 @@ fn __action1717< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1438( + __action1440( source_code, mode, __temp0, @@ -77272,7 +77461,7 @@ fn __action1717< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1718< +fn __action1722< >( source_code: &str, mode: Mode, @@ -77286,7 +77475,7 @@ fn __action1718< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -77294,7 +77483,7 @@ fn __action1718< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1438( + __action1440( source_code, mode, __temp0, @@ -77306,7 +77495,7 @@ fn __action1718< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1719< +fn __action1723< >( source_code: &str, mode: Mode, @@ -77321,7 +77510,7 @@ fn __action1719< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -77330,7 +77519,7 @@ fn __action1719< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1438( + __action1440( source_code, mode, __temp0, @@ -77342,7 +77531,7 @@ fn __action1719< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1720< +fn __action1724< >( source_code: &str, mode: Mode, @@ -77353,13 +77542,13 @@ fn __action1720< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action451( + let __temp0 = __action454( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1439( + __action1441( source_code, mode, __temp0, @@ -77370,7 +77559,7 @@ fn __action1720< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1721< +fn __action1725< >( source_code: &str, mode: Mode, @@ -77383,7 +77572,7 @@ fn __action1721< { let __start0 = __0.0; let __end0 = __2.2; - let __temp0 = __action706( + let __temp0 = __action709( source_code, mode, __0, @@ -77391,7 +77580,7 @@ fn __action1721< __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1439( + __action1441( source_code, mode, __temp0, @@ -77402,7 +77591,7 @@ fn __action1721< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1722< +fn __action1726< >( source_code: &str, mode: Mode, @@ -77416,7 +77605,7 @@ fn __action1722< { let __start0 = __0.0; let __end0 = __3.2; - let __temp0 = __action707( + let __temp0 = __action710( source_code, mode, __0, @@ -77425,7 +77614,7 @@ fn __action1722< __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1439( + __action1441( source_code, mode, __temp0, @@ -77436,7 +77625,7 @@ fn __action1722< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1723< +fn __action1727< >( source_code: &str, mode: Mode, @@ -77449,13 +77638,13 @@ fn __action1723< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action278( + let __temp0 = __action283( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1345( + __action1347( source_code, mode, __0, @@ -77468,7 +77657,7 @@ fn __action1723< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1724< +fn __action1728< >( source_code: &str, mode: Mode, @@ -77480,14 +77669,14 @@ fn __action1724< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action279( + let __temp0 = __action284( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1345( + __action1347( source_code, mode, __0, @@ -77500,7 +77689,7 @@ fn __action1724< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1725< +fn __action1729< >( source_code: &str, mode: Mode, @@ -77512,13 +77701,13 @@ fn __action1725< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action272( + let __temp0 = __action277( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1491( + __action1495( source_code, mode, __0, @@ -77530,7 +77719,7 @@ fn __action1725< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1726< +fn __action1730< >( source_code: &str, mode: Mode, @@ -77541,14 +77730,14 @@ fn __action1726< { let __start0 = __2.2; let __end0 = __2.2; - let __temp0 = __action273( + let __temp0 = __action278( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1491( + __action1495( source_code, mode, __0, @@ -77560,7 +77749,7 @@ fn __action1726< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1727< +fn __action1731< >( source_code: &str, mode: Mode, @@ -77572,13 +77761,13 @@ fn __action1727< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action322( + let __temp0 = __action327( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action791( + __action792( source_code, mode, __0, @@ -77590,7 +77779,7 @@ fn __action1727< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1728< +fn __action1732< >( source_code: &str, mode: Mode, @@ -77601,14 +77790,14 @@ fn __action1728< { let __start0 = __0.2; let __end0 = __1.0; - let __temp0 = __action323( + let __temp0 = __action328( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action791( + __action792( source_code, mode, __0, @@ -77620,7 +77809,7 @@ fn __action1728< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1729< +fn __action1733< >( source_code: &str, mode: Mode, @@ -77630,13 +77819,13 @@ fn __action1729< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action322( + let __temp0 = __action327( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action929( + __action930( source_code, mode, __0, @@ -77646,7 +77835,7 @@ fn __action1729< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1730< +fn __action1734< >( source_code: &str, mode: Mode, @@ -77655,14 +77844,14 @@ fn __action1730< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action323( + let __temp0 = __action328( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action929( + __action930( source_code, mode, __0, @@ -77672,7 +77861,7 @@ fn __action1730< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1731< +fn __action1735< >( source_code: &str, mode: Mode, @@ -77686,19 +77875,19 @@ fn __action1731< let __end0 = __0.2; let __start1 = __2.0; let __end1 = __2.2; - let __temp0 = __action322( + let __temp0 = __action327( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - let __temp1 = __action322( + let __temp1 = __action327( source_code, mode, __2, ); let __temp1 = (__start1, __temp1, __end1); - __action1725( + __action1729( source_code, mode, __temp0, @@ -77710,7 +77899,7 @@ fn __action1731< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1732< +fn __action1736< >( source_code: &str, mode: Mode, @@ -77723,20 +77912,20 @@ fn __action1732< let __end0 = __0.2; let __start1 = __1.2; let __end1 = __2.0; - let __temp0 = __action322( + let __temp0 = __action327( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - let __temp1 = __action323( + let __temp1 = __action328( source_code, mode, &__start1, &__end1, ); let __temp1 = (__start1, __temp1, __end1); - __action1725( + __action1729( source_code, mode, __temp0, @@ -77748,7 +77937,7 @@ fn __action1732< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1733< +fn __action1737< >( source_code: &str, mode: Mode, @@ -77761,20 +77950,20 @@ fn __action1733< let __end0 = __0.0; let __start1 = __1.0; let __end1 = __1.2; - let __temp0 = __action323( + let __temp0 = __action328( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - let __temp1 = __action322( + let __temp1 = __action327( source_code, mode, __1, ); let __temp1 = (__start1, __temp1, __end1); - __action1725( + __action1729( source_code, mode, __temp0, @@ -77786,7 +77975,7 @@ fn __action1733< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1734< +fn __action1738< >( source_code: &str, mode: Mode, @@ -77798,21 +77987,21 @@ fn __action1734< let __end0 = __0.0; let __start1 = __0.2; let __end1 = __1.0; - let __temp0 = __action323( + let __temp0 = __action328( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - let __temp1 = __action323( + let __temp1 = __action328( source_code, mode, &__start1, &__end1, ); let __temp1 = (__start1, __temp1, __end1); - __action1725( + __action1729( source_code, mode, __temp0, @@ -77824,7 +78013,7 @@ fn __action1734< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1735< +fn __action1739< >( source_code: &str, mode: Mode, @@ -77837,19 +78026,19 @@ fn __action1735< let __end0 = __0.2; let __start1 = __2.0; let __end1 = __2.2; - let __temp0 = __action322( + let __temp0 = __action327( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - let __temp1 = __action322( + let __temp1 = __action327( source_code, mode, __2, ); let __temp1 = (__start1, __temp1, __end1); - __action1726( + __action1730( source_code, mode, __temp0, @@ -77860,7 +78049,7 @@ fn __action1735< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1736< +fn __action1740< >( source_code: &str, mode: Mode, @@ -77872,20 +78061,20 @@ fn __action1736< let __end0 = __0.2; let __start1 = __1.2; let __end1 = __1.2; - let __temp0 = __action322( + let __temp0 = __action327( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - let __temp1 = __action323( + let __temp1 = __action328( source_code, mode, &__start1, &__end1, ); let __temp1 = (__start1, __temp1, __end1); - __action1726( + __action1730( source_code, mode, __temp0, @@ -77896,7 +78085,7 @@ fn __action1736< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1737< +fn __action1741< >( source_code: &str, mode: Mode, @@ -77908,20 +78097,20 @@ fn __action1737< let __end0 = __0.0; let __start1 = __1.0; let __end1 = __1.2; - let __temp0 = __action323( + let __temp0 = __action328( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - let __temp1 = __action322( + let __temp1 = __action327( source_code, mode, __1, ); let __temp1 = (__start1, __temp1, __end1); - __action1726( + __action1730( source_code, mode, __temp0, @@ -77932,7 +78121,7 @@ fn __action1737< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1738< +fn __action1742< >( source_code: &str, mode: Mode, @@ -77943,21 +78132,21 @@ fn __action1738< let __end0 = __0.0; let __start1 = __0.2; let __end1 = __0.2; - let __temp0 = __action323( + let __temp0 = __action328( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - let __temp1 = __action323( + let __temp1 = __action328( source_code, mode, &__start1, &__end1, ); let __temp1 = (__start1, __temp1, __end1); - __action1726( + __action1730( source_code, mode, __temp0, @@ -77968,7 +78157,7 @@ fn __action1738< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1739< +fn __action1743< >( source_code: &str, mode: Mode, @@ -77986,13 +78175,13 @@ fn __action1739< { let __start0 = __4.0; let __end0 = __4.2; - let __temp0 = __action232( + let __temp0 = __action235( source_code, mode, __4, ); let __temp0 = (__start0, __temp0, __end0); - __action1124( + __action1127( source_code, mode, __0, @@ -78010,7 +78199,7 @@ fn __action1739< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1740< +fn __action1744< >( source_code: &str, mode: Mode, @@ -78025,13 +78214,13 @@ fn __action1740< { let __start0 = __4.0; let __end0 = __4.2; - let __temp0 = __action232( + let __temp0 = __action235( source_code, mode, __4, ); let __temp0 = (__start0, __temp0, __end0); - __action1125( + __action1128( source_code, mode, __0, @@ -78046,7 +78235,7 @@ fn __action1740< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1741< +fn __action1745< >( source_code: &str, mode: Mode, @@ -78063,13 +78252,13 @@ fn __action1741< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action232( + let __temp0 = __action235( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1126( + __action1129( source_code, mode, __0, @@ -78086,7 +78275,7 @@ fn __action1741< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1742< +fn __action1746< >( source_code: &str, mode: Mode, @@ -78100,13 +78289,13 @@ fn __action1742< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action232( + let __temp0 = __action235( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1127( + __action1130( source_code, mode, __0, @@ -78120,7 +78309,7 @@ fn __action1742< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1743< +fn __action1747< >( source_code: &str, mode: Mode, @@ -78129,13 +78318,13 @@ fn __action1743< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action232( + let __temp0 = __action235( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action396( + __action399( source_code, mode, __temp0, @@ -78144,7 +78333,7 @@ fn __action1743< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1744< +fn __action1748< >( source_code: &str, mode: Mode, @@ -78153,7 +78342,7 @@ fn __action1744< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action232( + let __temp0 = __action235( source_code, mode, __0, @@ -78168,7 +78357,7 @@ fn __action1744< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1745< +fn __action1749< >( source_code: &str, mode: Mode, @@ -78177,7 +78366,7 @@ fn __action1745< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action232( + let __temp0 = __action235( source_code, mode, __0, @@ -78192,7 +78381,7 @@ fn __action1745< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1746< +fn __action1750< >( source_code: &str, mode: Mode, @@ -78202,13 +78391,13 @@ fn __action1746< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action232( + let __temp0 = __action235( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1500( + __action1504( source_code, mode, __0, @@ -78218,7 +78407,7 @@ fn __action1746< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1747< +fn __action1751< >( source_code: &str, mode: Mode, @@ -78229,13 +78418,13 @@ fn __action1747< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action232( + let __temp0 = __action235( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1501( + __action1505( source_code, mode, __0, @@ -78246,7 +78435,7 @@ fn __action1747< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1748< +fn __action1752< >( source_code: &str, mode: Mode, @@ -78256,13 +78445,13 @@ fn __action1748< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action1743( + let __temp0 = __action1747( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1320( + __action1322( source_code, mode, __0, @@ -78272,7 +78461,7 @@ fn __action1748< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1749< +fn __action1753< >( source_code: &str, mode: Mode, @@ -78281,14 +78470,14 @@ fn __action1749< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action397( + let __temp0 = __action400( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1320( + __action1322( source_code, mode, __0, @@ -78298,7 +78487,7 @@ fn __action1749< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1750< +fn __action1754< >( source_code: &str, mode: Mode, @@ -78308,13 +78497,13 @@ fn __action1750< { let __start0 = __1.0; let __end0 = __1.2; - let __temp0 = __action1743( + let __temp0 = __action1747( source_code, mode, __1, ); let __temp0 = (__start0, __temp0, __end0); - __action1525( + __action1529( source_code, mode, __0, @@ -78324,7 +78513,7 @@ fn __action1750< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1751< +fn __action1755< >( source_code: &str, mode: Mode, @@ -78333,14 +78522,14 @@ fn __action1751< { let __start0 = __0.2; let __end0 = __0.2; - let __temp0 = __action397( + let __temp0 = __action400( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1525( + __action1529( source_code, mode, __0, @@ -78350,7 +78539,7 @@ fn __action1751< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1752< +fn __action1756< >( source_code: &str, mode: Mode, @@ -78359,13 +78548,13 @@ fn __action1752< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action1745( + let __temp0 = __action1749( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1529( + __action1533( source_code, mode, __temp0, @@ -78374,7 +78563,7 @@ fn __action1752< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1753< +fn __action1757< >( source_code: &str, mode: Mode, @@ -78384,13 +78573,13 @@ fn __action1753< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action1745( + let __temp0 = __action1749( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1530( + __action1534( source_code, mode, __temp0, @@ -78400,7 +78589,7 @@ fn __action1753< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1754< +fn __action1758< >( source_code: &str, mode: Mode, @@ -78411,13 +78600,13 @@ fn __action1754< { let __start0 = __0.0; let __end0 = __0.2; - let __temp0 = __action1745( + let __temp0 = __action1749( source_code, mode, __0, ); let __temp0 = (__start0, __temp0, __end0); - __action1310( + __action1311( source_code, mode, __temp0, @@ -78428,7 +78617,7 @@ fn __action1754< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1755< +fn __action1759< >( source_code: &str, mode: Mode, @@ -78442,13 +78631,13 @@ fn __action1755< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action304( + let __temp0 = __action309( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1555( + __action1559( source_code, mode, __0, @@ -78462,7 +78651,7 @@ fn __action1755< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1756< +fn __action1760< >( source_code: &str, mode: Mode, @@ -78475,14 +78664,14 @@ fn __action1756< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action305( + let __temp0 = __action310( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1555( + __action1559( source_code, mode, __0, @@ -78496,7 +78685,7 @@ fn __action1756< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1757< +fn __action1761< >( source_code: &str, mode: Mode, @@ -78511,13 +78700,13 @@ fn __action1757< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action304( + let __temp0 = __action309( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1556( + __action1560( source_code, mode, __0, @@ -78532,7 +78721,7 @@ fn __action1757< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1758< +fn __action1762< >( source_code: &str, mode: Mode, @@ -78546,14 +78735,14 @@ fn __action1758< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action305( + let __temp0 = __action310( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1556( + __action1560( source_code, mode, __0, @@ -78568,7 +78757,7 @@ fn __action1758< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1759< +fn __action1763< >( source_code: &str, mode: Mode, @@ -78581,13 +78770,13 @@ fn __action1759< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action304( + let __temp0 = __action309( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1557( + __action1561( source_code, mode, __0, @@ -78600,7 +78789,7 @@ fn __action1759< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1760< +fn __action1764< >( source_code: &str, mode: Mode, @@ -78612,14 +78801,14 @@ fn __action1760< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action305( + let __temp0 = __action310( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1557( + __action1561( source_code, mode, __0, @@ -78632,7 +78821,7 @@ fn __action1760< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1761< +fn __action1765< >( source_code: &str, mode: Mode, @@ -78646,13 +78835,13 @@ fn __action1761< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action304( + let __temp0 = __action309( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1558( + __action1562( source_code, mode, __0, @@ -78666,7 +78855,7 @@ fn __action1761< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1762< +fn __action1766< >( source_code: &str, mode: Mode, @@ -78679,14 +78868,14 @@ fn __action1762< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action305( + let __temp0 = __action310( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1558( + __action1562( source_code, mode, __0, @@ -78700,7 +78889,7 @@ fn __action1762< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1763< +fn __action1767< >( source_code: &str, mode: Mode, @@ -78717,13 +78906,13 @@ fn __action1763< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action304( + let __temp0 = __action309( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1559( + __action1563( source_code, mode, __0, @@ -78740,7 +78929,7 @@ fn __action1763< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1764< +fn __action1768< >( source_code: &str, mode: Mode, @@ -78756,14 +78945,14 @@ fn __action1764< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action305( + let __temp0 = __action310( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1559( + __action1563( source_code, mode, __0, @@ -78780,7 +78969,7 @@ fn __action1764< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1765< +fn __action1769< >( source_code: &str, mode: Mode, @@ -78798,13 +78987,13 @@ fn __action1765< { let __start0 = __4.0; let __end0 = __4.2; - let __temp0 = __action304( + let __temp0 = __action309( source_code, mode, __4, ); let __temp0 = (__start0, __temp0, __end0); - __action1560( + __action1564( source_code, mode, __0, @@ -78822,7 +79011,7 @@ fn __action1765< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1766< +fn __action1770< >( source_code: &str, mode: Mode, @@ -78839,14 +79028,14 @@ fn __action1766< { let __start0 = __3.2; let __end0 = __4.0; - let __temp0 = __action305( + let __temp0 = __action310( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1560( + __action1564( source_code, mode, __0, @@ -78864,7 +79053,7 @@ fn __action1766< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1767< +fn __action1771< >( source_code: &str, mode: Mode, @@ -78879,13 +79068,13 @@ fn __action1767< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action304( + let __temp0 = __action309( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1561( + __action1565( source_code, mode, __0, @@ -78900,7 +79089,7 @@ fn __action1767< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1768< +fn __action1772< >( source_code: &str, mode: Mode, @@ -78914,14 +79103,14 @@ fn __action1768< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action305( + let __temp0 = __action310( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1561( + __action1565( source_code, mode, __0, @@ -78936,7 +79125,7 @@ fn __action1768< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1769< +fn __action1773< >( source_code: &str, mode: Mode, @@ -78952,13 +79141,13 @@ fn __action1769< { let __start0 = __4.0; let __end0 = __4.2; - let __temp0 = __action304( + let __temp0 = __action309( source_code, mode, __4, ); let __temp0 = (__start0, __temp0, __end0); - __action1562( + __action1566( source_code, mode, __0, @@ -78974,7 +79163,7 @@ fn __action1769< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1770< +fn __action1774< >( source_code: &str, mode: Mode, @@ -78989,14 +79178,14 @@ fn __action1770< { let __start0 = __3.2; let __end0 = __4.0; - let __temp0 = __action305( + let __temp0 = __action310( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1562( + __action1566( source_code, mode, __0, @@ -79012,7 +79201,7 @@ fn __action1770< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1771< +fn __action1775< >( source_code: &str, mode: Mode, @@ -79028,13 +79217,13 @@ fn __action1771< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action304( + let __temp0 = __action309( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1563( + __action1567( source_code, mode, __0, @@ -79050,7 +79239,7 @@ fn __action1771< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1772< +fn __action1776< >( source_code: &str, mode: Mode, @@ -79065,14 +79254,14 @@ fn __action1772< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action305( + let __temp0 = __action310( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1563( + __action1567( source_code, mode, __0, @@ -79088,7 +79277,7 @@ fn __action1772< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1773< +fn __action1777< >( source_code: &str, mode: Mode, @@ -79105,13 +79294,13 @@ fn __action1773< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action304( + let __temp0 = __action309( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1564( + __action1568( source_code, mode, __0, @@ -79128,7 +79317,7 @@ fn __action1773< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1774< +fn __action1778< >( source_code: &str, mode: Mode, @@ -79144,14 +79333,14 @@ fn __action1774< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action305( + let __temp0 = __action310( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1564( + __action1568( source_code, mode, __0, @@ -79168,7 +79357,7 @@ fn __action1774< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1775< +fn __action1779< >( source_code: &str, mode: Mode, @@ -79182,13 +79371,13 @@ fn __action1775< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action304( + let __temp0 = __action309( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1565( + __action1569( source_code, mode, __0, @@ -79202,7 +79391,7 @@ fn __action1775< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1776< +fn __action1780< >( source_code: &str, mode: Mode, @@ -79215,14 +79404,14 @@ fn __action1776< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action305( + let __temp0 = __action310( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1565( + __action1569( source_code, mode, __0, @@ -79236,7 +79425,7 @@ fn __action1776< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1777< +fn __action1781< >( source_code: &str, mode: Mode, @@ -79251,13 +79440,13 @@ fn __action1777< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action304( + let __temp0 = __action309( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1566( + __action1570( source_code, mode, __0, @@ -79272,7 +79461,7 @@ fn __action1777< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1778< +fn __action1782< >( source_code: &str, mode: Mode, @@ -79286,14 +79475,14 @@ fn __action1778< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action305( + let __temp0 = __action310( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1566( + __action1570( source_code, mode, __0, @@ -79308,7 +79497,7 @@ fn __action1778< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1779< +fn __action1783< >( source_code: &str, mode: Mode, @@ -79321,13 +79510,13 @@ fn __action1779< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action304( + let __temp0 = __action309( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1511( + __action1515( source_code, mode, __0, @@ -79340,7 +79529,7 @@ fn __action1779< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1780< +fn __action1784< >( source_code: &str, mode: Mode, @@ -79352,14 +79541,14 @@ fn __action1780< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action305( + let __temp0 = __action310( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1511( + __action1515( source_code, mode, __0, @@ -79372,7 +79561,7 @@ fn __action1780< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1781< +fn __action1785< >( source_code: &str, mode: Mode, @@ -79385,13 +79574,13 @@ fn __action1781< { let __start0 = __3.0; let __end0 = __3.2; - let __temp0 = __action276( + let __temp0 = __action281( source_code, mode, __3, ); let __temp0 = (__start0, __temp0, __end0); - __action1723( + __action1727( source_code, mode, __0, @@ -79404,7 +79593,7 @@ fn __action1781< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1782< +fn __action1786< >( source_code: &str, mode: Mode, @@ -79416,14 +79605,14 @@ fn __action1782< { let __start0 = __2.2; let __end0 = __3.0; - let __temp0 = __action277( + let __temp0 = __action282( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1723( + __action1727( source_code, mode, __0, @@ -79436,7 +79625,7 @@ fn __action1782< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1783< +fn __action1787< >( source_code: &str, mode: Mode, @@ -79448,13 +79637,13 @@ fn __action1783< { let __start0 = __2.0; let __end0 = __2.2; - let __temp0 = __action276( + let __temp0 = __action281( source_code, mode, __2, ); let __temp0 = (__start0, __temp0, __end0); - __action1724( + __action1728( source_code, mode, __0, @@ -79466,7 +79655,7 @@ fn __action1783< #[allow(unused_variables)] #[allow(clippy::too_many_arguments)] -fn __action1784< +fn __action1788< >( source_code: &str, mode: Mode, @@ -79477,14 +79666,14 @@ fn __action1784< { let __start0 = __1.2; let __end0 = __2.0; - let __temp0 = __action277( + let __temp0 = __action282( source_code, mode, &__start0, &__end0, ); let __temp0 = (__start0, __temp0, __end0); - __action1724( + __action1728( source_code, mode, __0, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__invalid__tests__ok_attribute_weird.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__invalid__tests__ok_attribute_weird.snap index 8848b18979cd0..a8492db558afb 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__invalid__tests__ok_attribute_weird.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__invalid__tests__ok_attribute_weird.snap @@ -14,9 +14,15 @@ Ok( value: StringLiteral( ExprStringLiteral { range: 0..5, - value: "foo", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 0..5, + value: "foo", + unicode: false, + }, + ), + }, }, ), attr: Identifier { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__dict_unpacking.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__dict_unpacking.snap index 7e5c892feac09..cb0da9427c71a 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__dict_unpacking.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__dict_unpacking.snap @@ -10,9 +10,15 @@ Dict( StringLiteral( ExprStringLiteral { range: 1..4, - value: "a", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 1..4, + value: "a", + unicode: false, + }, + ), + }, }, ), ), @@ -21,9 +27,15 @@ Dict( StringLiteral( ExprStringLiteral { range: 16..19, - value: "d", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 16..19, + value: "d", + unicode: false, + }, + ), + }, }, ), ), @@ -32,9 +44,15 @@ Dict( StringLiteral( ExprStringLiteral { range: 6..9, - value: "b", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 6..9, + value: "b", + unicode: false, + }, + ), + }, }, ), Name( @@ -47,9 +65,15 @@ Dict( StringLiteral( ExprStringLiteral { range: 21..24, - value: "e", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 21..24, + value: "e", + unicode: false, + }, + ), + }, }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings.snap index 7263bb506e71f..b7e99b5722981 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings.snap @@ -9,25 +9,39 @@ expression: parse_ast value: FString( ExprFString { range: 0..9, - values: [ - FormattedValue( - ExprFormattedValue { - range: 2..8, - value: StringLiteral( - ExprStringLiteral { - range: 3..7, - value: " f", - unicode: false, - implicit_concatenated: false, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..9, + values: [ + FormattedValue( + ExprFormattedValue { + range: 2..8, + value: StringLiteral( + ExprStringLiteral { + range: 3..7, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 3..7, + value: " f", + unicode: false, + }, + ), + }, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, @@ -38,24 +52,32 @@ expression: parse_ast value: FString( ExprFString { range: 10..20, - values: [ - FormattedValue( - ExprFormattedValue { - range: 12..19, - value: Name( - ExprName { - range: 13..16, - id: "foo", - ctx: Load, - }, - ), - debug_text: None, - conversion: Str, - format_spec: None, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 10..20, + values: [ + FormattedValue( + ExprFormattedValue { + range: 12..19, + value: Name( + ExprName { + range: 13..16, + id: "foo", + ctx: Load, + }, + ), + debug_text: None, + conversion: Str, + format_spec: None, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, @@ -66,33 +88,41 @@ expression: parse_ast value: FString( ExprFString { range: 21..28, - values: [ - FormattedValue( - ExprFormattedValue { - range: 23..27, - value: Tuple( - ExprTuple { - range: 24..26, - elts: [ - NumberLiteral( - ExprNumberLiteral { - range: 24..25, - value: Int( - 3, - ), - }, - ), - ], - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 21..28, + values: [ + FormattedValue( + ExprFormattedValue { + range: 23..27, + value: Tuple( + ExprTuple { + range: 24..26, + elts: [ + NumberLiteral( + ExprNumberLiteral { + range: 24..25, + value: Int( + 3, + ), + }, + ), + ], + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, @@ -103,51 +133,67 @@ expression: parse_ast value: FString( ExprFString { range: 29..39, - values: [ - FormattedValue( - ExprFormattedValue { - range: 31..38, - value: Compare( - ExprCompare { - range: 32..36, - left: NumberLiteral( - ExprNumberLiteral { - range: 32..33, - value: Int( - 3, + value: FStringValue { + inner: Single( + FString( + FString { + range: 29..39, + values: [ + FormattedValue( + ExprFormattedValue { + range: 31..38, + value: Compare( + ExprCompare { + range: 32..36, + left: NumberLiteral( + ExprNumberLiteral { + range: 32..33, + value: Int( + 3, + ), + }, + ), + ops: [ + NotEq, + ], + comparators: [ + NumberLiteral( + ExprNumberLiteral { + range: 35..36, + value: Int( + 4, + ), + }, + ), + ], + }, + ), + debug_text: None, + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 37..37, + value: FStringValue { + inner: Single( + FString( + FString { + range: 37..37, + values: [], + }, + ), + ), + }, + }, + ), ), }, ), - ops: [ - NotEq, - ], - comparators: [ - NumberLiteral( - ExprNumberLiteral { - range: 35..36, - value: Int( - 4, - ), - }, - ), - ], - }, - ), - debug_text: None, - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 37..37, - values: [], - implicit_concatenated: false, - }, - ), - ), - }, + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, @@ -158,58 +204,86 @@ expression: parse_ast value: FString( ExprFString { range: 40..55, - values: [ - FormattedValue( - ExprFormattedValue { - range: 42..54, - value: NumberLiteral( - ExprNumberLiteral { - range: 43..44, - value: Int( - 3, - ), - }, - ), - debug_text: None, - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 45..53, - values: [ - FormattedValue( - ExprFormattedValue { - range: 45..50, - value: StringLiteral( - ExprStringLiteral { - range: 46..49, - value: "}", - unicode: false, - implicit_concatenated: false, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 40..55, + values: [ + FormattedValue( + ExprFormattedValue { + range: 42..54, + value: NumberLiteral( + ExprNumberLiteral { + range: 43..44, + value: Int( + 3, ), - debug_text: None, - conversion: None, - format_spec: None, }, ), - StringLiteral( - ExprStringLiteral { - range: 50..53, - value: ">10", - unicode: false, - implicit_concatenated: false, - }, + debug_text: None, + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 45..53, + value: FStringValue { + inner: Single( + FString( + FString { + range: 45..53, + values: [ + FormattedValue( + ExprFormattedValue { + range: 45..50, + value: StringLiteral( + ExprStringLiteral { + range: 46..49, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 46..49, + value: "}", + unicode: false, + }, + ), + }, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + StringLiteral( + ExprStringLiteral { + range: 50..53, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 50..53, + value: ">10", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), + ), + }, + }, + ), ), - ], - implicit_concatenated: false, - }, - ), - ), - }, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, @@ -220,58 +294,86 @@ expression: parse_ast value: FString( ExprFString { range: 56..71, - values: [ - FormattedValue( - ExprFormattedValue { - range: 58..70, - value: NumberLiteral( - ExprNumberLiteral { - range: 59..60, - value: Int( - 3, - ), - }, - ), - debug_text: None, - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 61..69, - values: [ - FormattedValue( - ExprFormattedValue { - range: 61..66, - value: StringLiteral( - ExprStringLiteral { - range: 62..65, - value: "{", - unicode: false, - implicit_concatenated: false, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 56..71, + values: [ + FormattedValue( + ExprFormattedValue { + range: 58..70, + value: NumberLiteral( + ExprNumberLiteral { + range: 59..60, + value: Int( + 3, ), - debug_text: None, - conversion: None, - format_spec: None, }, ), - StringLiteral( - ExprStringLiteral { - range: 66..69, - value: ">10", - unicode: false, - implicit_concatenated: false, - }, + debug_text: None, + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 61..69, + value: FStringValue { + inner: Single( + FString( + FString { + range: 61..69, + values: [ + FormattedValue( + ExprFormattedValue { + range: 61..66, + value: StringLiteral( + ExprStringLiteral { + range: 62..65, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 62..65, + value: "{", + unicode: false, + }, + ), + }, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + StringLiteral( + ExprStringLiteral { + range: 66..69, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 66..69, + value: ">10", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), + ), + }, + }, + ), ), - ], - implicit_concatenated: false, - }, - ), - ), - }, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, @@ -282,29 +384,37 @@ expression: parse_ast value: FString( ExprFString { range: 72..86, - values: [ - FormattedValue( - ExprFormattedValue { - range: 74..85, - value: Name( - ExprName { - range: 77..80, - id: "foo", - ctx: Load, - }, - ), - debug_text: Some( - DebugText { - leading: " ", - trailing: " = ", - }, - ), - conversion: None, - format_spec: None, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 72..86, + values: [ + FormattedValue( + ExprFormattedValue { + range: 74..85, + value: Name( + ExprName { + range: 77..80, + id: "foo", + ctx: Load, + }, + ), + debug_text: Some( + DebugText { + leading: " ", + trailing: " = ", + }, + ), + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, @@ -315,46 +425,68 @@ expression: parse_ast value: FString( ExprFString { range: 87..107, - values: [ - FormattedValue( - ExprFormattedValue { - range: 89..106, - value: Name( - ExprName { - range: 92..95, - id: "foo", - ctx: Load, - }, - ), - debug_text: Some( - DebugText { - leading: " ", - trailing: " = ", - }, - ), - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 100..105, - values: [ - StringLiteral( - ExprStringLiteral { - range: 100..105, - value: ".3f ", - unicode: false, - implicit_concatenated: false, + value: FStringValue { + inner: Single( + FString( + FString { + range: 87..107, + values: [ + FormattedValue( + ExprFormattedValue { + range: 89..106, + value: Name( + ExprName { + range: 92..95, + id: "foo", + ctx: Load, }, ), - ], - implicit_concatenated: false, - }, - ), - ), - }, + debug_text: Some( + DebugText { + leading: " ", + trailing: " = ", + }, + ), + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 100..105, + value: FStringValue { + inner: Single( + FString( + FString { + range: 100..105, + values: [ + StringLiteral( + ExprStringLiteral { + range: 100..105, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 100..105, + value: ".3f ", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), + ), + }, + }, + ), + ), + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, @@ -365,29 +497,37 @@ expression: parse_ast value: FString( ExprFString { range: 108..126, - values: [ - FormattedValue( - ExprFormattedValue { - range: 110..125, - value: Name( - ExprName { - range: 113..116, - id: "foo", - ctx: Load, - }, - ), - debug_text: Some( - DebugText { - leading: " ", - trailing: " = ", - }, - ), - conversion: Str, - format_spec: None, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 108..126, + values: [ + FormattedValue( + ExprFormattedValue { + range: 110..125, + value: Name( + ExprName { + range: 113..116, + id: "foo", + ctx: Load, + }, + ), + debug_text: Some( + DebugText { + leading: " ", + trailing: " = ", + }, + ), + conversion: Str, + format_spec: None, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, @@ -398,46 +538,54 @@ expression: parse_ast value: FString( ExprFString { range: 127..143, - values: [ - FormattedValue( - ExprFormattedValue { - range: 129..142, - value: Tuple( - ExprTuple { - range: 132..136, - elts: [ - NumberLiteral( - ExprNumberLiteral { - range: 132..133, - value: Int( - 1, - ), - }, - ), - NumberLiteral( - ExprNumberLiteral { - range: 135..136, - value: Int( - 2, - ), - }, - ), - ], - ctx: Load, - }, - ), - debug_text: Some( - DebugText { - leading: " ", - trailing: " = ", - }, - ), - conversion: None, - format_spec: None, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 127..143, + values: [ + FormattedValue( + ExprFormattedValue { + range: 129..142, + value: Tuple( + ExprTuple { + range: 132..136, + elts: [ + NumberLiteral( + ExprNumberLiteral { + range: 132..133, + value: Int( + 1, + ), + }, + ), + NumberLiteral( + ExprNumberLiteral { + range: 135..136, + value: Int( + 2, + ), + }, + ), + ], + ctx: Load, + }, + ), + debug_text: Some( + DebugText { + leading: " ", + trailing: " = ", + }, + ), + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, @@ -448,80 +596,124 @@ expression: parse_ast value: FString( ExprFString { range: 144..170, - values: [ - FormattedValue( - ExprFormattedValue { - range: 146..169, - value: FString( - ExprFString { - range: 147..163, - values: [ - FormattedValue( - ExprFormattedValue { - range: 149..162, - value: NumberLiteral( - ExprNumberLiteral { - range: 150..156, - value: Float( - 3.1415, + value: FStringValue { + inner: Single( + FString( + FString { + range: 144..170, + values: [ + FormattedValue( + ExprFormattedValue { + range: 146..169, + value: FString( + ExprFString { + range: 147..163, + value: FStringValue { + inner: Single( + FString( + FString { + range: 147..163, + values: [ + FormattedValue( + ExprFormattedValue { + range: 149..162, + value: NumberLiteral( + ExprNumberLiteral { + range: 150..156, + value: Float( + 3.1415, + ), + }, + ), + debug_text: Some( + DebugText { + leading: "", + trailing: "=", + }, + ), + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 158..161, + value: FStringValue { + inner: Single( + FString( + FString { + range: 158..161, + values: [ + StringLiteral( + ExprStringLiteral { + range: 158..161, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 158..161, + value: ".1f", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), + ), + }, + }, + ), + ), + }, + ), + ], + }, + ), ), }, - ), - debug_text: Some( - DebugText { - leading: "", - trailing: "=", - }, - ), - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 158..161, - values: [ - StringLiteral( - ExprStringLiteral { - range: 158..161, - value: ".1f", - unicode: false, - implicit_concatenated: false, + }, + ), + debug_text: None, + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 164..168, + value: FStringValue { + inner: Single( + FString( + FString { + range: 164..168, + values: [ + StringLiteral( + ExprStringLiteral { + range: 164..168, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 164..168, + value: "*^20", + unicode: false, + }, + ), + }, + }, + ), + ], }, ), - ], - implicit_concatenated: false, + ), }, - ), + }, ), - }, - ), - ], - implicit_concatenated: false, - }, - ), - debug_text: None, - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 164..168, - values: [ - StringLiteral( - ExprStringLiteral { - range: 164..168, - value: "*^20", - unicode: false, - implicit_concatenated: false, - }, ), - ], - implicit_concatenated: false, - }, - ), - ), - }, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, @@ -537,53 +729,89 @@ expression: parse_ast FString( ExprFString { range: 173..201, - values: [ - StringLiteral( - ExprStringLiteral { - range: 174..186, - value: "foo bar ", - unicode: false, - implicit_concatenated: true, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 186..193, - value: BinOp( - ExprBinOp { - range: 187..192, - left: Name( - ExprName { - range: 187..188, - id: "x", - ctx: Load, - }, - ), - op: Add, - right: Name( - ExprName { - range: 191..192, - id: "y", - ctx: Load, - }, - ), + value: FStringValue { + inner: Concatenated( + [ + Literal( + StringLiteral { + range: 173..179, + value: "foo ", + unicode: false, }, ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - StringLiteral( - ExprStringLiteral { - range: 193..200, - value: " baz", - unicode: false, - implicit_concatenated: true, - }, + FString( + FString { + range: 180..195, + values: [ + StringLiteral( + ExprStringLiteral { + range: 182..186, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 182..186, + value: "bar ", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 186..193, + value: BinOp( + ExprBinOp { + range: 187..192, + left: Name( + ExprName { + range: 187..188, + id: "x", + ctx: Load, + }, + ), + op: Add, + right: Name( + ExprName { + range: 191..192, + id: "y", + ctx: Load, + }, + ), + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + StringLiteral( + ExprStringLiteral { + range: 193..194, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 193..194, + value: " ", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), + Literal( + StringLiteral { + range: 196..201, + value: "baz", + unicode: false, + }, + ), + ], ), - ], - implicit_concatenated: true, + }, }, ), ), @@ -621,9 +849,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 227..232, - value: "one", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 227..232, + value: "one", + unicode: false, + }, + ), + }, }, ), }, @@ -645,9 +879,25 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 256..284, - value: "implicitly concatenated", - unicode: false, - implicit_concatenated: true, + value: StringLiteralValue { + inner: Concatenated( + ConcatenatedStringLiteral { + strings: [ + StringLiteral { + range: 256..269, + value: "implicitly ", + unicode: false, + }, + StringLiteral { + range: 270..284, + value: "concatenated", + unicode: false, + }, + ], + value: "implicitly concatenated", + }, + ), + }, }, ), }, @@ -670,72 +920,106 @@ expression: parse_ast value: FString( ExprFString { range: 300..317, - values: [ - StringLiteral( - ExprStringLiteral { - range: 302..303, - value: "\\", - unicode: false, - implicit_concatenated: false, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 303..308, - value: Name( - ExprName { - range: 304..307, - id: "foo", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - StringLiteral( - ExprStringLiteral { - range: 308..309, - value: "\\", - unicode: false, - implicit_concatenated: false, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 309..316, - value: Name( - ExprName { - range: 310..313, - id: "bar", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 314..315, - values: [ - StringLiteral( - ExprStringLiteral { - range: 314..315, - value: "\\", - unicode: false, - implicit_concatenated: false, + value: FStringValue { + inner: Single( + FString( + FString { + range: 300..317, + values: [ + StringLiteral( + ExprStringLiteral { + range: 302..303, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 302..303, + value: "\\", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 303..308, + value: Name( + ExprName { + range: 304..307, + id: "foo", + ctx: Load, }, ), - ], - implicit_concatenated: false, - }, - ), - ), - }, + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + StringLiteral( + ExprStringLiteral { + range: 308..309, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 308..309, + value: "\\", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 309..316, + value: Name( + ExprName { + range: 310..313, + id: "bar", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 314..315, + value: FStringValue { + inner: Single( + FString( + FString { + range: 314..315, + values: [ + StringLiteral( + ExprStringLiteral { + range: 314..315, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 314..315, + value: "\\", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), + ), + }, + }, + ), + ), + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, @@ -746,17 +1030,31 @@ expression: parse_ast value: FString( ExprFString { range: 318..332, - values: [ - StringLiteral( - ExprStringLiteral { - range: 320..331, - value: "\\{foo\\}", - unicode: false, - implicit_concatenated: false, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 318..332, + values: [ + StringLiteral( + ExprStringLiteral { + range: 320..331, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 320..331, + value: "\\{foo\\}", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, @@ -767,41 +1065,63 @@ expression: parse_ast value: FString( ExprFString { range: 333..373, - values: [ - FormattedValue( - ExprFormattedValue { - range: 337..370, - value: Name( - ExprName { - range: 343..346, - id: "foo", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 347..369, - values: [ - StringLiteral( - ExprStringLiteral { - range: 347..369, - value: "x\n y\n z\n", - unicode: false, - implicit_concatenated: false, + value: FStringValue { + inner: Single( + FString( + FString { + range: 333..373, + values: [ + FormattedValue( + ExprFormattedValue { + range: 337..370, + value: Name( + ExprName { + range: 343..346, + id: "foo", + ctx: Load, }, ), - ], - implicit_concatenated: false, - }, - ), - ), - }, + debug_text: None, + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 347..369, + value: FStringValue { + inner: Single( + FString( + FString { + range: 347..369, + values: [ + StringLiteral( + ExprStringLiteral { + range: 347..369, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 347..369, + value: "x\n y\n z\n", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), + ), + }, + }, + ), + ), + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings_with_unicode.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings_with_unicode.snap index 587845166d0c7..7373b5c2b69ed 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings_with_unicode.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings_with_unicode.snap @@ -9,40 +9,55 @@ expression: parse_ast value: FString( ExprFString { range: 0..29, - values: [ - StringLiteral( - ExprStringLiteral { - range: 2..5, - value: "foo", - unicode: true, - implicit_concatenated: true, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 9..14, - value: Name( - ExprName { - range: 10..13, - id: "bar", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - StringLiteral( - ExprStringLiteral { - range: 17..28, - value: "baz some", - unicode: false, - implicit_concatenated: true, - }, + value: FStringValue { + inner: Concatenated( + [ + Literal( + StringLiteral { + range: 0..6, + value: "foo", + unicode: true, + }, + ), + FString( + FString { + range: 7..15, + values: [ + FormattedValue( + ExprFormattedValue { + range: 9..14, + value: Name( + ExprName { + range: 10..13, + id: "bar", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), + Literal( + StringLiteral { + range: 16..21, + value: "baz", + unicode: false, + }, + ), + Literal( + StringLiteral { + range: 22..29, + value: " some", + unicode: false, + }, + ), + ], ), - ], - implicit_concatenated: true, + }, }, ), }, @@ -53,40 +68,55 @@ expression: parse_ast value: FString( ExprFString { range: 30..59, - values: [ - StringLiteral( - ExprStringLiteral { - range: 31..34, - value: "foo", - unicode: false, - implicit_concatenated: true, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 38..43, - value: Name( - ExprName { - range: 39..42, - id: "bar", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - StringLiteral( - ExprStringLiteral { - range: 47..58, - value: "baz some", - unicode: true, - implicit_concatenated: true, - }, + value: FStringValue { + inner: Concatenated( + [ + Literal( + StringLiteral { + range: 30..35, + value: "foo", + unicode: false, + }, + ), + FString( + FString { + range: 36..44, + values: [ + FormattedValue( + ExprFormattedValue { + range: 38..43, + value: Name( + ExprName { + range: 39..42, + id: "bar", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), + Literal( + StringLiteral { + range: 45..51, + value: "baz", + unicode: true, + }, + ), + Literal( + StringLiteral { + range: 52..59, + value: " some", + unicode: false, + }, + ), + ], ), - ], - implicit_concatenated: true, + }, }, ), }, @@ -97,40 +127,55 @@ expression: parse_ast value: FString( ExprFString { range: 60..89, - values: [ - StringLiteral( - ExprStringLiteral { - range: 61..64, - value: "foo", - unicode: false, - implicit_concatenated: true, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 68..73, - value: Name( - ExprName { - range: 69..72, - id: "bar", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - StringLiteral( - ExprStringLiteral { - range: 76..88, - value: "baz some", - unicode: false, - implicit_concatenated: true, - }, + value: FStringValue { + inner: Concatenated( + [ + Literal( + StringLiteral { + range: 60..65, + value: "foo", + unicode: false, + }, + ), + FString( + FString { + range: 66..74, + values: [ + FormattedValue( + ExprFormattedValue { + range: 68..73, + value: Name( + ExprName { + range: 69..72, + id: "bar", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), + Literal( + StringLiteral { + range: 75..80, + value: "baz", + unicode: false, + }, + ), + Literal( + StringLiteral { + range: 81..89, + value: " some", + unicode: true, + }, + ), + ], ), - ], - implicit_concatenated: true, + }, }, ), }, @@ -141,40 +186,83 @@ expression: parse_ast value: FString( ExprFString { range: 90..128, - values: [ - StringLiteral( - ExprStringLiteral { - range: 92..103, - value: "foobar ", - unicode: true, - implicit_concatenated: true, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 103..108, - value: Name( - ExprName { - range: 104..107, - id: "baz", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - StringLiteral( - ExprStringLiteral { - range: 108..127, - value: " reallybarno", - unicode: false, - implicit_concatenated: true, - }, + value: FStringValue { + inner: Concatenated( + [ + Literal( + StringLiteral { + range: 90..96, + value: "foo", + unicode: true, + }, + ), + FString( + FString { + range: 97..116, + values: [ + StringLiteral( + ExprStringLiteral { + range: 99..103, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 99..103, + value: "bar ", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 103..108, + value: Name( + ExprName { + range: 104..107, + id: "baz", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + StringLiteral( + ExprStringLiteral { + range: 108..115, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 108..115, + value: " really", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), + Literal( + StringLiteral { + range: 117..123, + value: "bar", + unicode: true, + }, + ), + Literal( + StringLiteral { + range: 124..128, + value: "no", + unicode: false, + }, + ), + ], ), - ], - implicit_concatenated: true, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__generator_expression_argument.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__generator_expression_argument.snap index 5d3cf3b2769a2..08f16c5d09f78 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__generator_expression_argument.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__generator_expression_argument.snap @@ -11,9 +11,15 @@ Call( value: StringLiteral( ExprStringLiteral { range: 0..3, - value: " ", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 0..3, + value: " ", + unicode: false, + }, + ), + }, }, ), attr: Identifier { @@ -66,9 +72,15 @@ Call( left: StringLiteral( ExprStringLiteral { range: 43..53, - value: "LIMIT %d", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 43..53, + value: "LIMIT %d", + unicode: false, + }, + ), + }, }, ), op: Mod, @@ -104,9 +116,15 @@ Call( left: StringLiteral( ExprStringLiteral { range: 91..102, - value: "OFFSET %d", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 91..102, + value: "OFFSET %d", + unicode: false, + }, + ), + }, }, ), op: Mod, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__match.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__match.snap index 79b81f92449e3..545c9396f93b0 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__match.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__match.snap @@ -14,9 +14,15 @@ expression: parse_ast StringLiteral( ExprStringLiteral { range: 8..14, - value: "test", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 8..14, + value: "test", + unicode: false, + }, + ), + }, }, ), ), @@ -97,9 +103,15 @@ expression: parse_ast StringLiteral( ExprStringLiteral { range: 81..88, - value: "label", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 81..88, + value: "label", + unicode: false, + }, + ), + }, }, ), ), @@ -108,9 +120,15 @@ expression: parse_ast StringLiteral( ExprStringLiteral { range: 90..96, - value: "test", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 90..96, + value: "test", + unicode: false, + }, + ), + }, }, ), ], @@ -126,9 +144,15 @@ expression: parse_ast StringLiteral( ExprStringLiteral { range: 118..125, - value: "label", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 118..125, + value: "label", + unicode: false, + }, + ), + }, }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_class.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_class.snap index ebf85a89e247b..28c1d74b4c8f9 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_class.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_class.snap @@ -116,9 +116,15 @@ expression: "parse_suite(source, \"\").unwrap()" StringLiteral( ExprStringLiteral { range: 80..89, - value: "default", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 80..89, + value: "default", + unicode: false, + }, + ), + }, }, ), ), diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap index 323e950616dd2..d99fa9e549dc1 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap @@ -9,17 +9,31 @@ expression: parse_ast value: FString( ExprFString { range: 0..14, - values: [ - StringLiteral( - ExprStringLiteral { - range: 2..13, - value: "Hello world", - unicode: false, - implicit_concatenated: false, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..14, + values: [ + StringLiteral( + ExprStringLiteral { + range: 2..13, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 2..13, + value: "Hello world", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_kwargs.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_kwargs.snap index 5aeea6fccc478..1a66146c80fb2 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_kwargs.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_kwargs.snap @@ -22,9 +22,15 @@ expression: parse_ast StringLiteral( ExprStringLiteral { range: 8..20, - value: "positional", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 8..20, + value: "positional", + unicode: false, + }, + ), + }, }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_print_2.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_print_2.snap index d72338562526b..63fe9f3c0a6fe 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_print_2.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_print_2.snap @@ -22,9 +22,15 @@ expression: parse_ast StringLiteral( ExprStringLiteral { range: 6..19, - value: "Hello world", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 6..19, + value: "Hello world", + unicode: false, + }, + ), + }, }, ), NumberLiteral( diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_print_hello.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_print_hello.snap index 4e665b28312f9..351f287b92ba7 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_print_hello.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_print_hello.snap @@ -22,9 +22,15 @@ expression: parse_ast StringLiteral( ExprStringLiteral { range: 6..19, - value: "Hello world", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 6..19, + value: "Hello world", + unicode: false, + }, + ), + }, }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_string.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_string.snap index 5f65e7d4a785c..8611f5f2fa6fe 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_string.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_string.snap @@ -9,9 +9,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..13, - value: "Hello world", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 0..13, + value: "Hello world", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_type_declaration.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_type_declaration.snap index 24cd00399424f..e8ddd7d13d1eb 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_type_declaration.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_type_declaration.snap @@ -81,9 +81,15 @@ expression: "parse_suite(source, \"\").unwrap()" right: StringLiteral( ExprStringLiteral { range: 48..61, - value: "ForwardRefY", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 48..61, + value: "ForwardRefY", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__patma.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__patma.snap index ab1adbd35e711..c90e9f1e65a04 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__patma.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__patma.snap @@ -501,9 +501,15 @@ expression: parse_ast StringLiteral( ExprStringLiteral { range: 484..489, - value: "seq", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 484..489, + value: "seq", + unicode: false, + }, + ), + }, }, ), ), @@ -530,9 +536,15 @@ expression: parse_ast StringLiteral( ExprStringLiteral { range: 518..523, - value: "map", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 518..523, + value: "map", + unicode: false, + }, + ), + }, }, ), ), @@ -821,9 +833,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 664..667, - value: "X", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 664..667, + value: "X", + unicode: false, + }, + ), + }, }, ), }, @@ -1551,9 +1569,15 @@ expression: parse_ast StringLiteral( ExprStringLiteral { range: 1287..1292, - value: "foo", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 1287..1292, + value: "foo", + unicode: false, + }, + ), + }, }, ), ], @@ -2469,9 +2493,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 2036..2038, - value: "", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 2036..2038, + value: "", + unicode: false, + }, + ), + }, }, ), }, @@ -2513,9 +2543,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 2064..2066, - value: "", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 2064..2066, + value: "", + unicode: false, + }, + ), + }, }, ), }, @@ -3131,9 +3167,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 2449..2452, - value: "X", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 2449..2452, + value: "X", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap index f653b8c7f0d8c..a5e05daf58373 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap @@ -81,50 +81,64 @@ expression: parse_ast FString( ExprFString { range: 62..81, - values: [ - StringLiteral( - ExprStringLiteral { - range: 64..71, - value: "caught ", - unicode: false, - implicit_concatenated: false, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 71..80, - value: Call( - ExprCall { - range: 72..79, - func: Name( - ExprName { - range: 72..76, - id: "type", - ctx: Load, + value: FStringValue { + inner: Single( + FString( + FString { + range: 62..81, + values: [ + StringLiteral( + ExprStringLiteral { + range: 64..71, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 64..71, + value: "caught ", + unicode: false, + }, + ), + }, }, ), - arguments: Arguments { - range: 76..79, - args: [ - Name( - ExprName { - range: 77..78, - id: "e", - ctx: Load, + FormattedValue( + ExprFormattedValue { + range: 71..80, + value: Call( + ExprCall { + range: 72..79, + func: Name( + ExprName { + range: 72..76, + id: "type", + ctx: Load, + }, + ), + arguments: Arguments { + range: 76..79, + args: [ + Name( + ExprName { + range: 77..78, + id: "e", + ctx: Load, + }, + ), + ], + keywords: [], + }, }, ), - ], - keywords: [], - }, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), ], @@ -175,50 +189,64 @@ expression: parse_ast FString( ExprFString { range: 114..133, - values: [ - StringLiteral( - ExprStringLiteral { - range: 116..123, - value: "caught ", - unicode: false, - implicit_concatenated: false, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 123..132, - value: Call( - ExprCall { - range: 124..131, - func: Name( - ExprName { - range: 124..128, - id: "type", - ctx: Load, + value: FStringValue { + inner: Single( + FString( + FString { + range: 114..133, + values: [ + StringLiteral( + ExprStringLiteral { + range: 116..123, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 116..123, + value: "caught ", + unicode: false, + }, + ), + }, }, ), - arguments: Arguments { - range: 128..131, - args: [ - Name( - ExprName { - range: 129..130, - id: "e", - ctx: Load, + FormattedValue( + ExprFormattedValue { + range: 123..132, + value: Call( + ExprCall { + range: 124..131, + func: Name( + ExprName { + range: 124..128, + id: "type", + ctx: Load, + }, + ), + arguments: Arguments { + range: 128..131, + args: [ + Name( + ExprName { + range: 129..130, + id: "e", + ctx: Load, + }, + ), + ], + keywords: [], + }, }, ), - ], - keywords: [], - }, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap index 2ed0abb3ea0fb..eb9cfeefb9791 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap @@ -27,9 +27,15 @@ expression: parse_ast StringLiteral( ExprStringLiteral { range: 30..34, - value: "eg", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 30..34, + value: "eg", + unicode: false, + }, + ), + }, }, ), List( @@ -193,83 +199,103 @@ expression: parse_ast FString( ExprFString { range: 133..179, - values: [ - StringLiteral( - ExprStringLiteral { - range: 135..142, - value: "caught ", - unicode: false, - implicit_concatenated: false, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 142..151, - value: Call( - ExprCall { - range: 143..150, - func: Name( - ExprName { - range: 143..147, - id: "type", - ctx: Load, + value: FStringValue { + inner: Single( + FString( + FString { + range: 133..179, + values: [ + StringLiteral( + ExprStringLiteral { + range: 135..142, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 135..142, + value: "caught ", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 142..151, + value: Call( + ExprCall { + range: 143..150, + func: Name( + ExprName { + range: 143..147, + id: "type", + ctx: Load, + }, + ), + arguments: Arguments { + range: 147..150, + args: [ + Name( + ExprName { + range: 148..149, + id: "e", + ctx: Load, + }, + ), + ], + keywords: [], + }, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + StringLiteral( + ExprStringLiteral { + range: 151..164, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 151..164, + value: " with nested ", + unicode: false, + }, + ), + }, }, ), - arguments: Arguments { - range: 147..150, - args: [ - Name( - ExprName { - range: 148..149, - id: "e", + FormattedValue( + ExprFormattedValue { + range: 164..178, + value: Attribute( + ExprAttribute { + range: 165..177, + value: Name( + ExprName { + range: 165..166, + id: "e", + ctx: Load, + }, + ), + attr: Identifier { + id: "exceptions", + range: 167..177, + }, ctx: Load, }, ), - ], - keywords: [], - }, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - StringLiteral( - ExprStringLiteral { - range: 151..164, - value: " with nested ", - unicode: false, - implicit_concatenated: false, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 164..178, - value: Attribute( - ExprAttribute { - range: 165..177, - value: Name( - ExprName { - range: 165..166, - id: "e", - ctx: Load, + debug_text: None, + conversion: None, + format_spec: None, }, ), - attr: Identifier { - id: "exceptions", - range: 167..177, - }, - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), ], @@ -320,83 +346,103 @@ expression: parse_ast FString( ExprFString { range: 213..259, - values: [ - StringLiteral( - ExprStringLiteral { - range: 215..222, - value: "caught ", - unicode: false, - implicit_concatenated: false, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 222..231, - value: Call( - ExprCall { - range: 223..230, - func: Name( - ExprName { - range: 223..227, - id: "type", - ctx: Load, + value: FStringValue { + inner: Single( + FString( + FString { + range: 213..259, + values: [ + StringLiteral( + ExprStringLiteral { + range: 215..222, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 215..222, + value: "caught ", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 222..231, + value: Call( + ExprCall { + range: 223..230, + func: Name( + ExprName { + range: 223..227, + id: "type", + ctx: Load, + }, + ), + arguments: Arguments { + range: 227..230, + args: [ + Name( + ExprName { + range: 228..229, + id: "e", + ctx: Load, + }, + ), + ], + keywords: [], + }, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, }, ), - arguments: Arguments { - range: 227..230, - args: [ - Name( - ExprName { - range: 228..229, - id: "e", + StringLiteral( + ExprStringLiteral { + range: 231..244, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 231..244, + value: " with nested ", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 244..258, + value: Attribute( + ExprAttribute { + range: 245..257, + value: Name( + ExprName { + range: 245..246, + id: "e", + ctx: Load, + }, + ), + attr: Identifier { + id: "exceptions", + range: 247..257, + }, ctx: Load, }, ), - ], - keywords: [], - }, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - StringLiteral( - ExprStringLiteral { - range: 231..244, - value: " with nested ", - unicode: false, - implicit_concatenated: false, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 244..258, - value: Attribute( - ExprAttribute { - range: 245..257, - value: Name( - ExprName { - range: 245..246, - id: "e", - ctx: Load, + debug_text: None, + conversion: None, + format_spec: None, }, ), - attr: Identifier { - id: "exceptions", - range: 247..257, - }, - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__unicode_aliases.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__unicode_aliases.snap index ce30084c32dcd..7d811685fb945 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__unicode_aliases.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__unicode_aliases.snap @@ -18,9 +18,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 4..37, - value: "\u{8}another cool trick", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 4..37, + value: "\u{8}another cool trick", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__backspace_alias.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__backspace_alias.snap index f29c2f977121f..1e59128678e1a 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__backspace_alias.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__backspace_alias.snap @@ -9,9 +9,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..15, - value: "\u{8}", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 0..15, + value: "\u{8}", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__bell_alias.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__bell_alias.snap index ef30240f8a89b..29d741f9b33b4 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__bell_alias.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__bell_alias.snap @@ -9,9 +9,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..9, - value: "\u{7}", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 0..9, + value: "\u{7}", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__carriage_return_alias.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__carriage_return_alias.snap index 4224f30ab7cbe..594dcafd732e7 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__carriage_return_alias.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__carriage_return_alias.snap @@ -9,9 +9,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..21, - value: "\r", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 0..21, + value: "\r", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__character_tabulation_with_justification_alias.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__character_tabulation_with_justification_alias.snap index 735816fc1fedd..8346f7b04585b 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__character_tabulation_with_justification_alias.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__character_tabulation_with_justification_alias.snap @@ -9,9 +9,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..45, - value: "\u{89}", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 0..45, + value: "\u{89}", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__delete_alias.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__delete_alias.snap index e54a28743075d..7759077dd2cfb 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__delete_alias.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__delete_alias.snap @@ -9,9 +9,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..12, - value: "\u{7f}", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 0..12, + value: "\u{7f}", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__dont_panic_on_8_in_octal_escape.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__dont_panic_on_8_in_octal_escape.snap index 8b8c0a4e68b5f..970c3626905e2 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__dont_panic_on_8_in_octal_escape.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__dont_panic_on_8_in_octal_escape.snap @@ -18,9 +18,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 7..16, - value: "\u{3}8[1m", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 7..16, + value: "\u{3}8[1m", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__double_quoted_byte.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__double_quoted_byte.snap index e3b24f2b52285..5a6129ecb14e5 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__double_quoted_byte.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__double_quoted_byte.snap @@ -9,265 +9,271 @@ expression: parse_ast value: BytesLiteral( ExprBytesLiteral { range: 0..738, - value: [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 68, - 69, - 70, - 71, - 72, - 73, - 74, - 75, - 76, - 77, - 78, - 79, - 80, - 81, - 82, - 83, - 84, - 85, - 86, - 87, - 88, - 89, - 90, - 91, - 92, - 93, - 94, - 95, - 96, - 97, - 98, - 99, - 100, - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120, - 121, - 122, - 123, - 124, - 125, - 126, - 127, - 128, - 129, - 130, - 131, - 132, - 133, - 134, - 135, - 136, - 137, - 138, - 139, - 140, - 141, - 142, - 143, - 144, - 145, - 146, - 147, - 148, - 149, - 150, - 151, - 152, - 153, - 154, - 155, - 156, - 157, - 158, - 159, - 160, - 161, - 162, - 163, - 164, - 165, - 166, - 167, - 168, - 169, - 170, - 171, - 172, - 173, - 174, - 175, - 176, - 177, - 178, - 179, - 180, - 181, - 182, - 183, - 184, - 185, - 186, - 187, - 188, - 189, - 190, - 191, - 192, - 193, - 194, - 195, - 196, - 197, - 198, - 199, - 200, - 201, - 202, - 203, - 204, - 205, - 206, - 207, - 208, - 209, - 210, - 211, - 212, - 213, - 214, - 215, - 216, - 217, - 218, - 219, - 220, - 221, - 222, - 223, - 224, - 225, - 226, - 227, - 228, - 229, - 230, - 231, - 232, - 233, - 234, - 235, - 236, - 237, - 238, - 239, - 240, - 241, - 242, - 243, - 244, - 245, - 246, - 247, - 248, - 249, - 250, - 251, - 252, - 253, - 254, - 255, - ], - implicit_concatenated: false, + value: BytesLiteralValue { + inner: Single( + BytesLiteral { + range: 0..738, + value: [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 145, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 155, + 156, + 157, + 158, + 159, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 219, + 220, + 221, + 222, + 223, + 224, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 251, + 252, + 253, + 254, + 255, + ], + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__escape_alias.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__escape_alias.snap index 871b5788cadb3..2efea4e2f0f9f 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__escape_alias.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__escape_alias.snap @@ -9,9 +9,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..12, - value: "\u{1b}", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 0..12, + value: "\u{1b}", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__escape_char_in_byte_literal.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__escape_char_in_byte_literal.snap index 1ad9fb00a0f37..a62b6665c499f 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__escape_char_in_byte_literal.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__escape_char_in_byte_literal.snap @@ -9,19 +9,25 @@ expression: parse_ast value: BytesLiteral( ExprBytesLiteral { range: 0..13, - value: [ - 111, - 109, - 107, - 109, - 111, - 107, - 92, - 88, - 97, - 97, - ], - implicit_concatenated: false, + value: BytesLiteralValue { + inner: Single( + BytesLiteral { + range: 0..13, + value: [ + 111, + 109, + 107, + 109, + 111, + 107, + 92, + 88, + 97, + 97, + ], + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__escape_octet.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__escape_octet.snap index 1471b60aa0413..52c41dade1da0 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__escape_octet.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__escape_octet.snap @@ -9,14 +9,20 @@ expression: parse_ast value: BytesLiteral( ExprBytesLiteral { range: 0..14, - value: [ - 35, - 97, - 4, - 83, - 52, - ], - implicit_concatenated: false, + value: BytesLiteralValue { + inner: Single( + BytesLiteral { + range: 0..14, + value: [ + 35, + 97, + 4, + 83, + 52, + ], + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__form_feed_alias.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__form_feed_alias.snap index d574d60f91466..652db948cbc28 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__form_feed_alias.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__form_feed_alias.snap @@ -9,9 +9,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..15, - value: "\u{c}", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 0..15, + value: "\u{c}", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap index 2609db65ebcf0..4575aad44eb22 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap @@ -9,63 +9,89 @@ expression: parse_ast value: FString( ExprFString { range: 0..22, - values: [ - StringLiteral( - ExprStringLiteral { - range: 2..5, - value: "aaa", - unicode: false, - implicit_concatenated: false, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..22, + values: [ + StringLiteral( + ExprStringLiteral { + range: 2..5, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 2..5, + value: "aaa", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 5..10, + value: Name( + ExprName { + range: 6..9, + id: "bbb", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + StringLiteral( + ExprStringLiteral { + range: 10..13, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 10..13, + value: "ccc", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 13..18, + value: Name( + ExprName { + range: 14..17, + id: "ddd", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + StringLiteral( + ExprStringLiteral { + range: 18..21, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 18..21, + value: "eee", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), ), - FormattedValue( - ExprFormattedValue { - range: 5..10, - value: Name( - ExprName { - range: 6..9, - id: "bbb", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - StringLiteral( - ExprStringLiteral { - range: 10..13, - value: "ccc", - unicode: false, - implicit_concatenated: false, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 13..18, - value: Name( - ExprName { - range: 14..17, - id: "ddd", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - StringLiteral( - ExprStringLiteral { - range: 18..21, - value: "eee", - unicode: false, - implicit_concatenated: false, - }, - ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap index 9d179474d18c1..2ded682ed4633 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap @@ -9,32 +9,46 @@ expression: parse_ast value: FString( ExprFString { range: 0..8, - values: [ - StringLiteral( - ExprStringLiteral { - range: 2..4, - value: "\\", - unicode: false, - implicit_concatenated: false, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..8, + values: [ + StringLiteral( + ExprStringLiteral { + range: 2..4, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 2..4, + value: "\\", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 4..7, + value: Name( + ExprName { + range: 5..6, + id: "x", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - FormattedValue( - ExprFormattedValue { - range: 4..7, - value: Name( - ExprName { - range: 5..6, - id: "x", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap index aa63b7d99d05c..d7090ab4c0cb9 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap @@ -9,32 +9,46 @@ expression: parse_ast value: FString( ExprFString { range: 0..8, - values: [ - StringLiteral( - ExprStringLiteral { - range: 2..4, - value: "\n", - unicode: false, - implicit_concatenated: false, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..8, + values: [ + StringLiteral( + ExprStringLiteral { + range: 2..4, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 2..4, + value: "\n", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 4..7, + value: Name( + ExprName { + range: 5..6, + id: "x", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - FormattedValue( - ExprFormattedValue { - range: 4..7, - value: Name( - ExprName { - range: 5..6, - id: "x", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap index 52dd4c6e45842..92ac071ae5ba9 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap @@ -9,32 +9,46 @@ expression: parse_ast value: FString( ExprFString { range: 0..9, - values: [ - StringLiteral( - ExprStringLiteral { - range: 3..5, - value: "\\\n", - unicode: false, - implicit_concatenated: false, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..9, + values: [ + StringLiteral( + ExprStringLiteral { + range: 3..5, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 3..5, + value: "\\\n", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 5..8, + value: Name( + ExprName { + range: 6..7, + id: "x", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - FormattedValue( - ExprFormattedValue { - range: 5..8, - value: Name( - ExprName { - range: 6..7, - id: "x", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap index 7927d57d4f621..476a5a3f53fd5 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap @@ -9,29 +9,37 @@ expression: parse_ast value: FString( ExprFString { range: 0..10, - values: [ - FormattedValue( - ExprFormattedValue { - range: 2..9, - value: Name( - ExprName { - range: 3..7, - id: "user", - ctx: Load, - }, - ), - debug_text: Some( - DebugText { - leading: "", - trailing: "=", - }, - ), - conversion: None, - format_spec: None, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..10, + values: [ + FormattedValue( + ExprFormattedValue { + range: 2..9, + value: Name( + ExprName { + range: 3..7, + id: "user", + ctx: Load, + }, + ), + debug_text: Some( + DebugText { + leading: "", + trailing: "=", + }, + ), + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap index 1cf05d42dd09c..765076eddb6c2 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap @@ -9,65 +9,85 @@ expression: parse_ast value: FString( ExprFString { range: 0..38, - values: [ - StringLiteral( - ExprStringLiteral { - range: 2..6, - value: "mix ", - unicode: false, - implicit_concatenated: false, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..38, + values: [ + StringLiteral( + ExprStringLiteral { + range: 2..6, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 2..6, + value: "mix ", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 6..13, + value: Name( + ExprName { + range: 7..11, + id: "user", + ctx: Load, + }, + ), + debug_text: Some( + DebugText { + leading: "", + trailing: "=", + }, + ), + conversion: None, + format_spec: None, + }, + ), + StringLiteral( + ExprStringLiteral { + range: 13..28, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 13..28, + value: " with text and ", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 28..37, + value: Name( + ExprName { + range: 29..35, + id: "second", + ctx: Load, + }, + ), + debug_text: Some( + DebugText { + leading: "", + trailing: "=", + }, + ), + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - FormattedValue( - ExprFormattedValue { - range: 6..13, - value: Name( - ExprName { - range: 7..11, - id: "user", - ctx: Load, - }, - ), - debug_text: Some( - DebugText { - leading: "", - trailing: "=", - }, - ), - conversion: None, - format_spec: None, - }, - ), - StringLiteral( - ExprStringLiteral { - range: 13..28, - value: " with text and ", - unicode: false, - implicit_concatenated: false, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 28..37, - value: Name( - ExprName { - range: 29..35, - id: "second", - ctx: Load, - }, - ), - debug_text: Some( - DebugText { - leading: "", - trailing: "=", - }, - ), - conversion: None, - format_spec: None, - }, - ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap index 5e17b1c8a2843..d34b5387ad99c 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap @@ -9,46 +9,68 @@ expression: parse_ast value: FString( ExprFString { range: 0..14, - values: [ - FormattedValue( - ExprFormattedValue { - range: 2..13, - value: Name( - ExprName { - range: 3..7, - id: "user", - ctx: Load, - }, - ), - debug_text: Some( - DebugText { - leading: "", - trailing: "=", - }, - ), - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 9..12, - values: [ - StringLiteral( - ExprStringLiteral { - range: 9..12, - value: ">10", - unicode: false, - implicit_concatenated: false, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..14, + values: [ + FormattedValue( + ExprFormattedValue { + range: 2..13, + value: Name( + ExprName { + range: 3..7, + id: "user", + ctx: Load, }, ), - ], - implicit_concatenated: false, - }, - ), - ), - }, + debug_text: Some( + DebugText { + leading: "", + trailing: "=", + }, + ), + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 9..12, + value: FStringValue { + inner: Single( + FString( + FString { + range: 9..12, + values: [ + StringLiteral( + ExprStringLiteral { + range: 9..12, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 9..12, + value: ">10", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), + ), + }, + }, + ), + ), + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap index 7ec5e8b42a353..a6079454028a7 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap @@ -9,32 +9,46 @@ expression: parse_ast value: FString( ExprFString { range: 0..11, - values: [ - StringLiteral( - ExprStringLiteral { - range: 4..5, - value: "\n", - unicode: false, - implicit_concatenated: false, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..11, + values: [ + StringLiteral( + ExprStringLiteral { + range: 4..5, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 4..5, + value: "\n", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 5..8, + value: Name( + ExprName { + range: 6..7, + id: "x", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - FormattedValue( - ExprFormattedValue { - range: 5..8, - value: Name( - ExprName { - range: 6..7, - id: "x", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__hts_alias.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__hts_alias.snap index 48eab469043b3..4120136451759 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__hts_alias.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__hts_alias.snap @@ -9,9 +9,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..9, - value: "\u{88}", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 0..9, + value: "\u{88}", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap index 08b71212046b2..a4375d213f044 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap @@ -9,8 +9,16 @@ expression: "parse_suite(r#\"f\"\"\"#, \"\").unwrap()" value: FString( ExprFString { range: 0..3, - values: [], - implicit_concatenated: false, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..3, + values: [], + }, + ), + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap index 97c70a7a22e64..5e831e22e6bc1 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap @@ -9,17 +9,40 @@ expression: parse_ast value: FString( ExprFString { range: 0..17, - values: [ - StringLiteral( - ExprStringLiteral { - range: 1..16, - value: "Hello world", - unicode: false, - implicit_concatenated: true, - }, + value: FStringValue { + inner: Concatenated( + [ + Literal( + StringLiteral { + range: 0..8, + value: "Hello ", + unicode: false, + }, + ), + FString( + FString { + range: 9..17, + values: [ + StringLiteral( + ExprStringLiteral { + range: 11..16, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 11..16, + value: "world", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), + ], ), - ], - implicit_concatenated: true, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap index 97c70a7a22e64..5e831e22e6bc1 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap @@ -9,17 +9,40 @@ expression: parse_ast value: FString( ExprFString { range: 0..17, - values: [ - StringLiteral( - ExprStringLiteral { - range: 1..16, - value: "Hello world", - unicode: false, - implicit_concatenated: true, - }, + value: FStringValue { + inner: Concatenated( + [ + Literal( + StringLiteral { + range: 0..8, + value: "Hello ", + unicode: false, + }, + ), + FString( + FString { + range: 9..17, + values: [ + StringLiteral( + ExprStringLiteral { + range: 11..16, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 11..16, + value: "world", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), + ], ), - ], - implicit_concatenated: true, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap index ccfe7c6484998..c59b4bc18654d 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap @@ -9,33 +9,62 @@ expression: parse_ast value: FString( ExprFString { range: 0..22, - values: [ - StringLiteral( - ExprStringLiteral { - range: 1..16, - value: "Hello world", - unicode: false, - implicit_concatenated: true, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 16..21, - value: StringLiteral( - ExprStringLiteral { - range: 17..20, - value: "!", + value: FStringValue { + inner: Concatenated( + [ + Literal( + StringLiteral { + range: 0..8, + value: "Hello ", unicode: false, - implicit_concatenated: false, }, ), - debug_text: None, - conversion: None, - format_spec: None, - }, + FString( + FString { + range: 9..22, + values: [ + StringLiteral( + ExprStringLiteral { + range: 11..16, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 11..16, + value: "world", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 16..21, + value: StringLiteral( + ExprStringLiteral { + range: 17..20, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 17..20, + value: "!", + unicode: false, + }, + ), + }, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), + ], ), - ], - implicit_concatenated: true, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap index e6cb23a586837..4d777817d7052 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap @@ -9,41 +9,69 @@ expression: parse_ast value: FString( ExprFString { range: 0..31, - values: [ - StringLiteral( - ExprStringLiteral { - range: 1..16, - value: "Hello world", - unicode: false, - implicit_concatenated: true, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 16..21, - value: StringLiteral( - ExprStringLiteral { - range: 17..20, - value: "!", + value: FStringValue { + inner: Concatenated( + [ + Literal( + StringLiteral { + range: 0..8, + value: "Hello ", unicode: false, - implicit_concatenated: false, }, ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - StringLiteral( - ExprStringLiteral { - range: 24..30, - value: "again!", - unicode: false, - implicit_concatenated: true, - }, + FString( + FString { + range: 9..22, + values: [ + StringLiteral( + ExprStringLiteral { + range: 11..16, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 11..16, + value: "world", + unicode: false, + }, + ), + }, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 16..21, + value: StringLiteral( + ExprStringLiteral { + range: 17..20, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 17..20, + value: "!", + unicode: false, + }, + ), + }, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), + Literal( + StringLiteral { + range: 23..31, + value: "again!", + unicode: false, + }, + ), + ], ), - ], - implicit_concatenated: true, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap index 6ee1be1ee840d..c3894637985e7 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap @@ -9,47 +9,61 @@ expression: parse_ast value: FString( ExprFString { range: 0..18, - values: [ - FormattedValue( - ExprFormattedValue { - range: 2..5, - value: Name( - ExprName { - range: 3..4, - id: "a", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..18, + values: [ + FormattedValue( + ExprFormattedValue { + range: 2..5, + value: Name( + ExprName { + range: 3..4, + id: "a", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + FormattedValue( + ExprFormattedValue { + range: 5..10, + value: Name( + ExprName { + range: 7..8, + id: "b", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + StringLiteral( + ExprStringLiteral { + range: 10..17, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 10..17, + value: "{foo}", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), ), - FormattedValue( - ExprFormattedValue { - range: 5..10, - value: Name( - ExprName { - range: 7..8, - id: "b", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - StringLiteral( - ExprStringLiteral { - range: 10..17, - value: "{foo}", - unicode: false, - implicit_concatenated: false, - }, - ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap index 25315bc0359a0..fc8338ee70ac7 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap @@ -9,43 +9,51 @@ expression: parse_ast value: FString( ExprFString { range: 0..13, - values: [ - FormattedValue( - ExprFormattedValue { - range: 2..12, - value: Compare( - ExprCompare { - range: 3..11, - left: NumberLiteral( - ExprNumberLiteral { - range: 3..5, - value: Int( - 42, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..13, + values: [ + FormattedValue( + ExprFormattedValue { + range: 2..12, + value: Compare( + ExprCompare { + range: 3..11, + left: NumberLiteral( + ExprNumberLiteral { + range: 3..5, + value: Int( + 42, + ), + }, + ), + ops: [ + Eq, + ], + comparators: [ + NumberLiteral( + ExprNumberLiteral { + range: 9..11, + value: Int( + 42, + ), + }, + ), + ], + }, ), + debug_text: None, + conversion: None, + format_spec: None, }, ), - ops: [ - Eq, - ], - comparators: [ - NumberLiteral( - ExprNumberLiteral { - range: 9..11, - value: Int( - 42, - ), - }, - ), - ], - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap index 070a1d0eea32f..fdb3a6fc90221 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap @@ -9,49 +9,81 @@ expression: parse_ast value: FString( ExprFString { range: 0..16, - values: [ - FormattedValue( - ExprFormattedValue { - range: 2..15, - value: Name( - ExprName { - range: 3..6, - id: "foo", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 7..14, - values: [ - FormattedValue( - ExprFormattedValue { - range: 7..14, - value: StringLiteral( - ExprStringLiteral { - range: 8..13, - value: "", - unicode: false, - implicit_concatenated: true, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..16, + values: [ + FormattedValue( + ExprFormattedValue { + range: 2..15, + value: Name( + ExprName { + range: 3..6, + id: "foo", + ctx: Load, }, ), - ], - implicit_concatenated: false, - }, - ), - ), - }, + debug_text: None, + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 7..14, + value: FStringValue { + inner: Single( + FString( + FString { + range: 7..14, + values: [ + FormattedValue( + ExprFormattedValue { + range: 7..14, + value: StringLiteral( + ExprStringLiteral { + range: 8..13, + value: StringLiteralValue { + inner: Concatenated( + ConcatenatedStringLiteral { + strings: [ + StringLiteral { + range: 8..10, + value: "", + unicode: false, + }, + StringLiteral { + range: 11..13, + value: "", + unicode: false, + }, + ], + value: "", + }, + ), + }, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), + ), + }, + }, + ), + ), + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap index 39f80bde5c65c..3ffcbc7c9edb4 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap @@ -9,48 +9,64 @@ expression: parse_ast value: FString( ExprFString { range: 0..15, - values: [ - FormattedValue( - ExprFormattedValue { - range: 2..14, - value: Name( - ExprName { - range: 3..6, - id: "foo", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 7..13, - values: [ - FormattedValue( - ExprFormattedValue { - range: 7..13, - value: Name( - ExprName { - range: 8..12, - id: "spec", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..15, + values: [ + FormattedValue( + ExprFormattedValue { + range: 2..14, + value: Name( + ExprName { + range: 3..6, + id: "foo", + ctx: Load, }, ), - ], - implicit_concatenated: false, - }, - ), - ), - }, + debug_text: None, + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 7..13, + value: FStringValue { + inner: Single( + FString( + FString { + range: 7..13, + values: [ + FormattedValue( + ExprFormattedValue { + range: 7..13, + value: Name( + ExprName { + range: 8..12, + id: "spec", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), + ), + }, + }, + ), + ), + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap index 327506de08aa8..06e925c016b72 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap @@ -9,49 +9,71 @@ expression: parse_ast value: FString( ExprFString { range: 0..13, - values: [ - FormattedValue( - ExprFormattedValue { - range: 2..12, - value: Name( - ExprName { - range: 3..6, - id: "foo", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 7..11, - values: [ - FormattedValue( - ExprFormattedValue { - range: 7..11, - value: StringLiteral( - ExprStringLiteral { - range: 8..10, - value: "", - unicode: false, - implicit_concatenated: false, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..13, + values: [ + FormattedValue( + ExprFormattedValue { + range: 2..12, + value: Name( + ExprName { + range: 3..6, + id: "foo", + ctx: Load, }, ), - ], - implicit_concatenated: false, - }, - ), - ), - }, + debug_text: None, + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 7..11, + value: FStringValue { + inner: Single( + FString( + FString { + range: 7..11, + values: [ + FormattedValue( + ExprFormattedValue { + range: 7..11, + value: StringLiteral( + ExprStringLiteral { + range: 8..10, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 8..10, + value: "", + unicode: false, + }, + ), + }, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), + ), + }, + }, + ), + ), + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap index 216021cec10c5..c4aee850245c2 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap @@ -9,43 +9,51 @@ expression: parse_ast value: FString( ExprFString { range: 0..11, - values: [ - FormattedValue( - ExprFormattedValue { - range: 2..10, - value: Compare( - ExprCompare { - range: 3..9, - left: NumberLiteral( - ExprNumberLiteral { - range: 3..4, - value: Int( - 1, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..11, + values: [ + FormattedValue( + ExprFormattedValue { + range: 2..10, + value: Compare( + ExprCompare { + range: 3..9, + left: NumberLiteral( + ExprNumberLiteral { + range: 3..4, + value: Int( + 1, + ), + }, + ), + ops: [ + NotEq, + ], + comparators: [ + NumberLiteral( + ExprNumberLiteral { + range: 8..9, + value: Int( + 2, + ), + }, + ), + ], + }, ), + debug_text: None, + conversion: None, + format_spec: None, }, ), - ops: [ - NotEq, - ], - comparators: [ - NumberLiteral( - ExprNumberLiteral { - range: 8..9, - value: Int( - 2, - ), - }, - ), - ], - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap index cb1664e20c9c2..6b8b11fe88c13 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap @@ -9,41 +9,63 @@ expression: parse_ast value: FString( ExprFString { range: 0..13, - values: [ - FormattedValue( - ExprFormattedValue { - range: 2..12, - value: Name( - ExprName { - range: 3..6, - id: "foo", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 7..11, - values: [ - StringLiteral( - ExprStringLiteral { - range: 7..11, - value: "spec", - unicode: false, - implicit_concatenated: false, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..13, + values: [ + FormattedValue( + ExprFormattedValue { + range: 2..12, + value: Name( + ExprName { + range: 3..6, + id: "foo", + ctx: Load, }, ), - ], - implicit_concatenated: false, - }, - ), - ), - }, + debug_text: None, + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 7..11, + value: FStringValue { + inner: Single( + FString( + FString { + range: 7..11, + values: [ + StringLiteral( + ExprStringLiteral { + range: 7..11, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 7..11, + value: "spec", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), + ), + }, + }, + ), + ), + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap index 134e8043877e3..fd024631ef18b 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap @@ -9,29 +9,37 @@ expression: parse_ast value: FString( ExprFString { range: 0..10, - values: [ - FormattedValue( - ExprFormattedValue { - range: 2..9, - value: Name( - ExprName { - range: 3..4, - id: "x", - ctx: Load, - }, - ), - debug_text: Some( - DebugText { - leading: "", - trailing: " =", - }, - ), - conversion: None, - format_spec: None, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..10, + values: [ + FormattedValue( + ExprFormattedValue { + range: 2..9, + value: Name( + ExprName { + range: 3..4, + id: "x", + ctx: Load, + }, + ), + debug_text: Some( + DebugText { + leading: "", + trailing: " =", + }, + ), + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap index b7c6e8505810c..c1f08c3397dd8 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap @@ -9,29 +9,37 @@ expression: parse_ast value: FString( ExprFString { range: 0..10, - values: [ - FormattedValue( - ExprFormattedValue { - range: 2..9, - value: Name( - ExprName { - range: 3..4, - id: "x", - ctx: Load, - }, - ), - debug_text: Some( - DebugText { - leading: "", - trailing: "= ", - }, - ), - conversion: None, - format_spec: None, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..10, + values: [ + FormattedValue( + ExprFormattedValue { + range: 2..9, + value: Name( + ExprName { + range: 3..4, + id: "x", + ctx: Load, + }, + ), + debug_text: Some( + DebugText { + leading: "", + trailing: "= ", + }, + ), + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap index 32693e49d7ac4..20ccfbf7e1379 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap @@ -9,23 +9,31 @@ expression: parse_ast value: FString( ExprFString { range: 0..10, - values: [ - FormattedValue( - ExprFormattedValue { - range: 2..9, - value: Yield( - ExprYield { - range: 3..8, - value: None, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..10, + values: [ + FormattedValue( + ExprFormattedValue { + range: 2..9, + value: Yield( + ExprYield { + range: 3..8, + value: None, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_string_concat.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_string_concat.snap index 93c14088eb2f0..df7acef064365 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_string_concat.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_string_concat.snap @@ -9,9 +9,25 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..16, - value: "Hello world", - unicode: false, - implicit_concatenated: true, + value: StringLiteralValue { + inner: Concatenated( + ConcatenatedStringLiteral { + strings: [ + StringLiteral { + range: 0..8, + value: "Hello ", + unicode: false, + }, + StringLiteral { + range: 9..16, + value: "world", + unicode: false, + }, + ], + value: "Hello world", + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_string_triple_quotes_with_kind.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_string_triple_quotes_with_kind.snap index 9347faf323fa9..071761efae957 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_string_triple_quotes_with_kind.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_string_triple_quotes_with_kind.snap @@ -9,9 +9,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..20, - value: "Hello, world!", - unicode: true, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 0..20, + value: "Hello, world!", + unicode: true, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap index df260efb74a14..c8495e4b318e2 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap @@ -9,17 +9,40 @@ expression: parse_ast value: FString( ExprFString { range: 0..18, - values: [ - StringLiteral( - ExprStringLiteral { - range: 2..17, - value: "Hello world", - unicode: true, - implicit_concatenated: true, - }, + value: FStringValue { + inner: Concatenated( + [ + Literal( + StringLiteral { + range: 0..9, + value: "Hello ", + unicode: true, + }, + ), + FString( + FString { + range: 10..18, + values: [ + StringLiteral( + ExprStringLiteral { + range: 12..17, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 12..17, + value: "world", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), + ], ), - ], - implicit_concatenated: true, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap index aced9ed7983cd..9278f809af668 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap @@ -9,17 +9,47 @@ expression: parse_ast value: FString( ExprFString { range: 0..22, - values: [ - StringLiteral( - ExprStringLiteral { - range: 2..21, - value: "Hello world!", - unicode: true, - implicit_concatenated: true, - }, + value: FStringValue { + inner: Concatenated( + [ + Literal( + StringLiteral { + range: 0..9, + value: "Hello ", + unicode: true, + }, + ), + FString( + FString { + range: 10..18, + values: [ + StringLiteral( + ExprStringLiteral { + range: 12..17, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 12..17, + value: "world", + unicode: false, + }, + ), + }, + }, + ), + ], + }, + ), + Literal( + StringLiteral { + range: 19..22, + value: "!", + unicode: false, + }, + ), + ], ), - ], - implicit_concatenated: true, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_string_concat_1.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_string_concat_1.snap index 21dd4a1c10911..601474e802474 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_string_concat_1.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_string_concat_1.snap @@ -9,9 +9,25 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..17, - value: "Hello world", - unicode: false, - implicit_concatenated: true, + value: StringLiteralValue { + inner: Concatenated( + ConcatenatedStringLiteral { + strings: [ + StringLiteral { + range: 0..8, + value: "Hello ", + unicode: false, + }, + StringLiteral { + range: 9..17, + value: "world", + unicode: true, + }, + ], + value: "Hello world", + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_string_concat_2.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_string_concat_2.snap index 19c9f87309d02..5a84316d8a220 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_string_concat_2.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_string_concat_2.snap @@ -9,9 +9,25 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..17, - value: "Hello world", - unicode: true, - implicit_concatenated: true, + value: StringLiteralValue { + inner: Concatenated( + ConcatenatedStringLiteral { + strings: [ + StringLiteral { + range: 0..9, + value: "Hello ", + unicode: true, + }, + StringLiteral { + range: 10..17, + value: "world", + unicode: false, + }, + ], + value: "Hello world", + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_byte_literal_1.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_byte_literal_1.snap index 0ddea1aeca5ff..d8d18c4fe34de 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_byte_literal_1.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_byte_literal_1.snap @@ -9,13 +9,19 @@ expression: parse_ast value: BytesLiteral( ExprBytesLiteral { range: 0..8, - value: [ - 92, - 120, - 49, - 122, - ], - implicit_concatenated: false, + value: BytesLiteralValue { + inner: Single( + BytesLiteral { + range: 0..8, + value: [ + 92, + 120, + 49, + 122, + ], + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_byte_literal_2.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_byte_literal_2.snap index c7f13431590a8..ec5562eb0b002 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_byte_literal_2.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_byte_literal_2.snap @@ -9,11 +9,17 @@ expression: parse_ast value: BytesLiteral( ExprBytesLiteral { range: 0..6, - value: [ - 92, - 92, - ], - implicit_concatenated: false, + value: BytesLiteralValue { + inner: Single( + BytesLiteral { + range: 0..6, + value: [ + 92, + 92, + ], + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap index 65f4daf83d8d7..100bf1ed55946 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap @@ -9,24 +9,32 @@ expression: parse_ast value: FString( ExprFString { range: 0..7, - values: [ - FormattedValue( - ExprFormattedValue { - range: 3..6, - value: Name( - ExprName { - range: 4..5, - id: "x", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..7, + values: [ + FormattedValue( + ExprFormattedValue { + range: 3..6, + value: Name( + ExprName { + range: 4..5, + id: "x", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__single_quoted_byte.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__single_quoted_byte.snap index e3b24f2b52285..5a6129ecb14e5 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__single_quoted_byte.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__single_quoted_byte.snap @@ -9,265 +9,271 @@ expression: parse_ast value: BytesLiteral( ExprBytesLiteral { range: 0..738, - value: [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 68, - 69, - 70, - 71, - 72, - 73, - 74, - 75, - 76, - 77, - 78, - 79, - 80, - 81, - 82, - 83, - 84, - 85, - 86, - 87, - 88, - 89, - 90, - 91, - 92, - 93, - 94, - 95, - 96, - 97, - 98, - 99, - 100, - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120, - 121, - 122, - 123, - 124, - 125, - 126, - 127, - 128, - 129, - 130, - 131, - 132, - 133, - 134, - 135, - 136, - 137, - 138, - 139, - 140, - 141, - 142, - 143, - 144, - 145, - 146, - 147, - 148, - 149, - 150, - 151, - 152, - 153, - 154, - 155, - 156, - 157, - 158, - 159, - 160, - 161, - 162, - 163, - 164, - 165, - 166, - 167, - 168, - 169, - 170, - 171, - 172, - 173, - 174, - 175, - 176, - 177, - 178, - 179, - 180, - 181, - 182, - 183, - 184, - 185, - 186, - 187, - 188, - 189, - 190, - 191, - 192, - 193, - 194, - 195, - 196, - 197, - 198, - 199, - 200, - 201, - 202, - 203, - 204, - 205, - 206, - 207, - 208, - 209, - 210, - 211, - 212, - 213, - 214, - 215, - 216, - 217, - 218, - 219, - 220, - 221, - 222, - 223, - 224, - 225, - 226, - 227, - 228, - 229, - 230, - 231, - 232, - 233, - 234, - 235, - 236, - 237, - 238, - 239, - 240, - 241, - 242, - 243, - 244, - 245, - 246, - 247, - 248, - 249, - 250, - 251, - 252, - 253, - 254, - 255, - ], - implicit_concatenated: false, + value: BytesLiteralValue { + inner: Single( + BytesLiteral { + range: 0..738, + value: [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 145, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 155, + 156, + 157, + 158, + 159, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 219, + 220, + 221, + 222, + 223, + 224, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 251, + 252, + 253, + 254, + 255, + ], + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__string_parser_escaped_mac_eol.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__string_parser_escaped_mac_eol.snap index 50d87b93a57cc..a20e906204e44 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__string_parser_escaped_mac_eol.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__string_parser_escaped_mac_eol.snap @@ -9,9 +9,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..18, - value: "text more text", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 0..18, + value: "text more text", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__string_parser_escaped_unix_eol.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__string_parser_escaped_unix_eol.snap index 50d87b93a57cc..a20e906204e44 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__string_parser_escaped_unix_eol.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__string_parser_escaped_unix_eol.snap @@ -9,9 +9,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..18, - value: "text more text", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 0..18, + value: "text more text", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__string_parser_escaped_windows_eol.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__string_parser_escaped_windows_eol.snap index fcee590ad5ca8..29f69a54bc297 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__string_parser_escaped_windows_eol.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__string_parser_escaped_windows_eol.snap @@ -9,9 +9,15 @@ expression: parse_ast value: StringLiteral( ExprStringLiteral { range: 0..19, - value: "text more text", - unicode: false, - implicit_concatenated: false, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 0..19, + value: "text more text", + unicode: false, + }, + ), + }, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap index 6793e65f73804..872fe090c8071 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap @@ -9,24 +9,32 @@ expression: parse_ast value: FString( ExprFString { range: 0..11, - values: [ - FormattedValue( - ExprFormattedValue { - range: 5..8, - value: Name( - ExprName { - range: 6..7, - id: "x", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, + value: FStringValue { + inner: Single( + FString( + FString { + range: 0..11, + values: [ + FormattedValue( + ExprFormattedValue { + range: 5..8, + value: Name( + ExprName { + range: 6..7, + id: "x", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, + ), ), - ], - implicit_concatenated: false, + }, }, ), }, diff --git a/crates/ruff_python_parser/src/string.rs b/crates/ruff_python_parser/src/string.rs index a3fa6f6495467..2d64e66bd2ec4 100644 --- a/crates/ruff_python_parser/src/string.rs +++ b/crates/ruff_python_parser/src/string.rs @@ -7,9 +7,9 @@ use crate::lexer::{LexicalError, LexicalErrorType}; use crate::token::{StringKind, Tok}; pub(crate) enum StringType { - Str(ast::ExprStringLiteral), - Bytes(ast::ExprBytesLiteral), - FString(ast::ExprFString), + Str(ast::StringLiteral), + Bytes(ast::BytesLiteral), + FString(ast::FString), } impl Ranged for StringType { @@ -22,11 +22,12 @@ impl Ranged for StringType { } } -impl StringType { - fn is_unicode(&self) -> bool { - match self { - Self::Str(ast::ExprStringLiteral { unicode, .. }) => *unicode, - _ => false, +impl From for Expr { + fn from(string: StringType) -> Self { + match string { + StringType::Str(node) => Expr::from(node), + StringType::Bytes(node) => Expr::from(node), + StringType::FString(node) => Expr::from(node), } } } @@ -35,14 +36,16 @@ struct StringParser<'a> { rest: &'a str, kind: StringKind, location: TextSize, + range: TextRange, } impl<'a> StringParser<'a> { - fn new(source: &'a str, kind: StringKind, start: TextSize) -> Self { + fn new(source: &'a str, kind: StringKind, start: TextSize, range: TextRange) -> Self { Self { rest: source, kind, location: start, + range, } } @@ -59,11 +62,6 @@ impl<'a> StringParser<'a> { self.location } - #[inline] - fn range(&self, start_location: TextSize) -> TextRange { - TextRange::new(start_location, self.location) - } - /// Returns the next byte in the string, if there is one. /// /// # Panics @@ -208,7 +206,6 @@ impl<'a> StringParser<'a> { fn parse_fstring_middle(&mut self) -> Result { let mut value = String::new(); - let start_location = self.get_pos(); while let Some(ch) = self.next_char() { match ch { // We can encounter a `\` as the last character in a `FStringMiddle` @@ -244,17 +241,15 @@ impl<'a> StringParser<'a> { ch => value.push(ch), } } - Ok(Expr::from(ast::ExprStringLiteral { + Ok(Expr::from(ast::StringLiteral { value, unicode: false, - implicit_concatenated: false, - range: self.range(start_location), + range: self.range, })) } fn parse_bytes(&mut self) -> Result { let mut content = String::new(); - let start_location = self.get_pos(); while let Some(ch) = self.next_char() { match ch { '\\' if !self.kind.is_raw() => { @@ -274,15 +269,13 @@ impl<'a> StringParser<'a> { } } - Ok(StringType::Bytes(ast::ExprBytesLiteral { + Ok(StringType::Bytes(ast::BytesLiteral { value: content.chars().map(|c| c as u8).collect::>(), - implicit_concatenated: false, - range: self.range(start_location), + range: self.range, })) } fn parse_string(&mut self) -> Result { - let start_location = self.get_pos(); let mut value = String::new(); if self.kind.is_raw() { @@ -301,11 +294,10 @@ impl<'a> StringParser<'a> { self.parse_escaped_char(&mut value)?; } } - Ok(StringType::Str(ast::ExprStringLiteral { + Ok(StringType::Str(ast::StringLiteral { value, unicode: self.kind.is_unicode(), - implicit_concatenated: false, - range: self.range(start_location), + range: self.range, })) } @@ -322,38 +314,37 @@ pub(crate) fn parse_string_literal( source: &str, kind: StringKind, triple_quoted: bool, - start_location: TextSize, + range: TextRange, ) -> Result { - let start_location = start_location + let start_location = range.start() + kind.prefix_len() + if triple_quoted { TextSize::from(3) } else { TextSize::from(1) }; - StringParser::new(source, kind, start_location).parse() + StringParser::new(source, kind, start_location, range).parse() } pub(crate) fn parse_fstring_middle( source: &str, is_raw: bool, - start_location: TextSize, + range: TextRange, ) -> Result { let kind = if is_raw { StringKind::RawString } else { StringKind::String }; - StringParser::new(source, kind, start_location).parse_fstring_middle() + StringParser::new(source, kind, range.start(), range).parse_fstring_middle() } -/// Concatenate a list of string literals into a single string expression. -pub(crate) fn concatenate_strings( +pub(crate) fn concatenated_strings( strings: Vec, range: TextRange, ) -> Result { #[cfg(debug_assertions)] - debug_assert!(!strings.is_empty()); + debug_assert!(strings.len() > 1); let mut has_fstring = false; let mut byte_literal_count = 0; @@ -365,7 +356,6 @@ pub(crate) fn concatenate_strings( } } let has_bytes = byte_literal_count > 0; - let implicit_concatenated = strings.len() > 1; if has_bytes && byte_literal_count < strings.len() { return Err(LexicalError { @@ -377,111 +367,44 @@ pub(crate) fn concatenate_strings( } if has_bytes { - let mut content: Vec = vec![]; + let mut values = Vec::with_capacity(strings.len()); for string in strings { match string { - StringType::Bytes(ast::ExprBytesLiteral { value, .. }) => content.extend(value), + StringType::Bytes(value) => values.push(value), _ => unreachable!("Unexpected non-bytes literal."), } } - return Ok(ast::ExprBytesLiteral { - value: content, - implicit_concatenated, + return Ok(Expr::from(ast::ExprBytesLiteral { + value: ast::BytesLiteralValue::concatenated(values), range, - } - .into()); + })); } if !has_fstring { - let mut content = String::new(); - let is_unicode = strings.first().map_or(false, StringType::is_unicode); + let mut values = Vec::with_capacity(strings.len()); for string in strings { match string { - StringType::Str(ast::ExprStringLiteral { value, .. }) => content.push_str(&value), + StringType::Str(value) => values.push(value), _ => unreachable!("Unexpected non-string literal."), } } - return Ok(ast::ExprStringLiteral { - value: content, - unicode: is_unicode, - implicit_concatenated, + return Ok(Expr::from(ast::ExprStringLiteral { + value: ast::StringLiteralValue::concatenated(values), range, - } - .into()); - } - - // De-duplicate adjacent constants. - let mut deduped: Vec = vec![]; - let mut current = String::new(); - let mut current_start = range.start(); - let mut current_end = range.end(); - let mut is_unicode = false; - - let take_current = |current: &mut String, start, end, unicode| -> Expr { - Expr::StringLiteral(ast::ExprStringLiteral { - value: std::mem::take(current), - unicode, - implicit_concatenated, - range: TextRange::new(start, end), - }) - }; + })); + } + let mut parts = Vec::with_capacity(strings.len()); for string in strings { - let string_range = string.range(); match string { - StringType::FString(ast::ExprFString { values, .. }) => { - for value in values { - let value_range = value.range(); - match value { - Expr::FormattedValue { .. } => { - if !current.is_empty() { - deduped.push(take_current( - &mut current, - current_start, - current_end, - is_unicode, - )); - } - deduped.push(value); - is_unicode = false; - } - Expr::StringLiteral(ast::ExprStringLiteral { value, unicode, .. }) => { - if current.is_empty() { - is_unicode |= unicode; - current_start = value_range.start(); - } - current_end = value_range.end(); - current.push_str(&value); - } - _ => { - unreachable!("Expected `Expr::FormattedValue` or `Expr::StringLiteral`") - } - } - } - } - StringType::Str(ast::ExprStringLiteral { value, unicode, .. }) => { - if current.is_empty() { - is_unicode |= unicode; - current_start = string_range.start(); - } - current_end = string_range.end(); - current.push_str(&value); - } + StringType::FString(fstring) => parts.push(ast::FStringPart::FString(fstring)), + StringType::Str(string) => parts.push(ast::FStringPart::Literal(string)), StringType::Bytes(_) => unreachable!("Unexpected bytes literal."), } } - if !current.is_empty() { - deduped.push(take_current( - &mut current, - current_start, - current_end, - is_unicode, - )); - } Ok(ast::ExprFString { - values: deduped, - implicit_concatenated, + value: ast::FStringValue::concatenated(parts), range, } .into()) From 626b0577cdc458bbeaeb00f8b2af5268bb917a39 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Fri, 24 Nov 2023 18:03:59 -0600 Subject: [PATCH 031/197] Explicit `as_str` (no deref), add no allocation methods (#8826) ## Summary This PR is a follow-up to the AST refactor which does the following: - Remove `Deref` implementation on `StringLiteralValue` and use explicit `as_str` calls instead. The `Deref` implementation would implicitly perform allocations in case of implicitly concatenated strings. This is to make sure the allocation is explicit. - Now, certain methods can be implemented to do zero allocations which have been implemented in this PR. They are: - `is_empty` - `len` - `chars` - Custom `PartialEq` implementation to compare each character ## Test Plan Run the linter test suite and make sure all tests pass. --- .../src/checkers/ast/analyze/expression.rs | 18 +++++++--- crates/ruff_linter/src/checkers/ast/mod.rs | 4 +-- .../flake8_annotations/rules/definition.rs | 8 ++--- .../rules/hardcoded_password_string.rs | 2 +- .../rules/hardcoded_sql_expression.rs | 4 +-- .../rules/hardcoded_tmp_directory.rs | 2 +- .../rules/suspicious_function_call.rs | 2 +- .../rules/getattr_with_constant.rs | 4 +-- .../rules/setattr_with_constant.rs | 6 ++-- .../call_datetime_strptime_without_zone.rs | 2 +- .../rules/logging_call.rs | 2 +- .../rules/unnecessary_dict_kwargs.rs | 2 +- .../flake8_pytest_style/rules/parametrize.rs | 15 ++++---- .../rules/flake8_simplify/rules/ast_expr.rs | 8 ++--- .../ruff_linter/src/rules/pylint/helpers.rs | 2 +- .../src/rules/pylint/rules/bad_open_mode.rs | 2 +- .../rules/pylint/rules/bad_str_strip_call.rs | 2 +- .../pylint/rules/repeated_keyword_argument.rs | 2 +- .../pylint/rules/unspecified_encoding.rs | 7 +++- ...convert_named_tuple_functional_to_class.rs | 6 ++-- .../convert_typed_dict_functional_to_class.rs | 6 ++-- .../rules/printf_string_formatting.rs | 4 +-- .../pyupgrade/rules/redundant_open_modes.rs | 4 +-- .../rules/unnecessary_encode_utf8.rs | 4 +-- .../src/rules/ruff/rules/implicit_optional.rs | 8 ++--- crates/ruff_linter/src/rules/ruff/typing.rs | 9 +++-- crates/ruff_python_ast/src/all.rs | 2 +- crates/ruff_python_ast/src/nodes.rs | 35 +++++++++++++------ 28 files changed, 95 insertions(+), 77 deletions(-) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 76b735944978c..e5ca3bbee31f6 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -369,18 +369,24 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { ]) { if let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() { let attr = attr.as_str(); - if let Expr::StringLiteral(ast::ExprStringLiteral { value: string, .. }) = - value.as_ref() + if let Expr::StringLiteral(ast::ExprStringLiteral { + value: string_value, + .. + }) = value.as_ref() { if attr == "join" { // "...".join(...) call if checker.enabled(Rule::StaticJoinToFString) { - flynt::rules::static_join_to_fstring(checker, expr, string); + flynt::rules::static_join_to_fstring( + checker, + expr, + string_value.as_str(), + ); } } else if attr == "format" { // "...".format(...) call let location = expr.range(); - match pyflakes::format::FormatSummary::try_from(string.as_ref()) { + match pyflakes::format::FormatSummary::try_from(string_value.as_str()) { Err(e) => { if checker.enabled(Rule::StringDotFormatInvalidFormat) { checker.diagnostics.push(Diagnostic::new( @@ -425,7 +431,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::BadStringFormatCharacter) { pylint::rules::bad_string_format_character::call( - checker, string, location, + checker, + string_value.as_str(), + location, ); } } diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 7357937c1a88f..bf0eba8e4fd86 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -799,7 +799,7 @@ where if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = expr { self.deferred.string_type_definitions.push(( expr.range(), - value, + value.as_str(), self.semantic.snapshot(), )); } else { @@ -1219,7 +1219,7 @@ where { self.deferred.string_type_definitions.push(( expr.range(), - value, + value.as_str(), self.semantic.snapshot(), )); } diff --git a/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs b/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs index c73f8da87cd2e..b1bfc9df67021 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs +++ b/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs @@ -505,14 +505,10 @@ fn check_dynamically_typed( ) where F: FnOnce() -> String, { - if let Expr::StringLiteral(ast::ExprStringLiteral { - range, - value: string, - }) = annotation - { + if let Expr::StringLiteral(ast::ExprStringLiteral { range, value }) = annotation { // Quoted annotations if let Ok((parsed_annotation, _)) = - parse_type_annotation(string, *range, checker.locator().contents()) + parse_type_annotation(value.as_str(), *range, checker.locator().contents()) { if type_hint_resolves_to_any( &parsed_annotation, diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_password_string.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_password_string.rs index 9839cd58ae283..0509986804873 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_password_string.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_password_string.rs @@ -55,7 +55,7 @@ fn password_target(target: &Expr) -> Option<&str> { Expr::Name(ast::ExprName { id, .. }) => id.as_str(), // d["password"] = "s3cr3t" Expr::Subscript(ast::ExprSubscript { slice, .. }) => match slice.as_ref() { - Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => value, + Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => value.as_str(), _ => return None, }, // obj.password = "s3cr3t" diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs index d4d3df9bad712..e132e806d8f06 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs @@ -93,7 +93,7 @@ pub(crate) fn hardcoded_sql_expression(checker: &mut Checker, expr: &Expr) { let Some(string) = left.as_string_literal_expr() else { return; }; - string.value.escape_default().to_string() + string.value.as_str().escape_default().to_string() } Expr::Call(ast::ExprCall { func, .. }) => { let Expr::Attribute(ast::ExprAttribute { attr, value, .. }) = func.as_ref() else { @@ -106,7 +106,7 @@ pub(crate) fn hardcoded_sql_expression(checker: &mut Checker, expr: &Expr) { let Some(string) = value.as_string_literal_expr() else { return; }; - string.value.escape_default().to_string() + string.value.as_str().escape_default().to_string() } // f"select * from table where val = {val}" Expr::FString(f_string) => concatenated_f_string(f_string, checker.locator()), diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs index 592f4e76211b2..9b5a913dd7a3f 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs @@ -57,7 +57,7 @@ pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, string: &ast::ExprS .flake8_bandit .hardcoded_tmp_directory .iter() - .any(|prefix| string.value.starts_with(prefix)) + .any(|prefix| string.value.as_str().starts_with(prefix)) { return; } diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs index 0c6d9b9300664..46fbec7612be2 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs @@ -855,7 +855,7 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, call: &ExprCall) { // If the `url` argument is a string literal, allow `http` and `https` schemes. if call.arguments.args.iter().all(|arg| !arg.is_starred_expr()) && call.arguments.keywords.iter().all(|keyword| keyword.arg.is_some()) { if let Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) = &call.arguments.find_argument("url", 0) { - let url = value.trim_start(); + let url = value.as_str().trim_start(); if url.starts_with("http://") || url.starts_with("https://") { return None; } diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/getattr_with_constant.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/getattr_with_constant.rs index 4c6133d779733..66f563a234769 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/getattr_with_constant.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/getattr_with_constant.rs @@ -69,10 +69,10 @@ pub(crate) fn getattr_with_constant( let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = arg else { return; }; - if !is_identifier(value) { + if !is_identifier(value.as_str()) { return; } - if is_mangled_private(value) { + if is_mangled_private(value.as_str()) { return; } if !checker.semantic().is_builtin("getattr") { diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/setattr_with_constant.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/setattr_with_constant.rs index 92599a5807eba..bc17ed3ffddd5 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/setattr_with_constant.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/setattr_with_constant.rs @@ -83,10 +83,10 @@ pub(crate) fn setattr_with_constant( let Expr::StringLiteral(ast::ExprStringLiteral { value: name, .. }) = name else { return; }; - if !is_identifier(name) { + if !is_identifier(name.as_str()) { return; } - if is_mangled_private(name) { + if is_mangled_private(name.as_str()) { return; } if !checker.semantic().is_builtin("setattr") { @@ -104,7 +104,7 @@ pub(crate) fn setattr_with_constant( if expr == child.as_ref() { let mut diagnostic = Diagnostic::new(SetAttrWithConstant, expr.range()); diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - assignment(obj, name, value, checker.generator()), + assignment(obj, name.as_str(), value, checker.generator()), expr.range(), ))); checker.diagnostics.push(diagnostic); diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs index 6efde68d0d2cc..0a9fe6c0e7a55 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs @@ -78,7 +78,7 @@ pub(crate) fn call_datetime_strptime_without_zone(checker: &mut Checker, call: & if let Some(Expr::StringLiteral(ast::ExprStringLiteral { value: format, .. })) = call.arguments.args.get(1).as_ref() { - if format.contains("%z") { + if format.as_str().contains("%z") { return; } }; diff --git a/crates/ruff_linter/src/rules/flake8_logging_format/rules/logging_call.rs b/crates/ruff_linter/src/rules/flake8_logging_format/rules/logging_call.rs index 4b214fffec95f..db56255ff4df9 100644 --- a/crates/ruff_linter/src/rules/flake8_logging_format/rules/logging_call.rs +++ b/crates/ruff_linter/src/rules/flake8_logging_format/rules/logging_call.rs @@ -93,7 +93,7 @@ fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) { for key in keys { if let Some(key) = &key { if let Expr::StringLiteral(ast::ExprStringLiteral { value: attr, .. }) = key { - if is_reserved_attr(attr) { + if is_reserved_attr(attr.as_str()) { checker.diagnostics.push(Diagnostic::new( LoggingExtraAttrClash(attr.to_string()), key.range(), diff --git a/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs b/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs index a37da79ade651..fcf5707fe700a 100644 --- a/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs +++ b/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs @@ -110,7 +110,7 @@ pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, expr: &Expr, kwargs /// Return `Some` if a key is a valid keyword argument name, or `None` otherwise. fn as_kwarg(key: &Expr) -> Option<&str> { if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = key { - if is_identifier(value) { + if is_identifier(value.as_str()) { return Some(value.as_str()); } } diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs index e9b5b7a8954fc..cead79a028412 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs @@ -300,8 +300,8 @@ fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) { let names_type = checker.settings.flake8_pytest_style.parametrize_names_type; match expr { - Expr::StringLiteral(ast::ExprStringLiteral { value: string, .. }) => { - let names = split_names(string); + Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { + let names = split_names(value.as_str()); if names.len() > 1 { match names_type { types::ParametrizeNameType::Tuple => { @@ -475,12 +475,11 @@ fn check_values(checker: &mut Checker, names: &Expr, values: &Expr) { .flake8_pytest_style .parametrize_values_row_type; - let is_multi_named = - if let Expr::StringLiteral(ast::ExprStringLiteral { value: string, .. }) = &names { - split_names(string).len() > 1 - } else { - true - }; + let is_multi_named = if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &names { + split_names(value.as_str()).len() > 1 + } else { + true + }; match values { Expr::List(ast::ExprList { elts, .. }) => { diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_expr.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_expr.rs index deee6d9b2488d..392b2507ce69e 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_expr.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_expr.rs @@ -161,11 +161,11 @@ pub(crate) fn use_capital_environment_variables(checker: &mut Checker, expr: &Ex return; } - if is_lowercase_allowed(env_var) { + if is_lowercase_allowed(env_var.as_str()) { return; } - let capital_env_var = env_var.to_ascii_uppercase(); + let capital_env_var = env_var.as_str().to_ascii_uppercase(); if capital_env_var == env_var.as_str() { return; } @@ -201,11 +201,11 @@ fn check_os_environ_subscript(checker: &mut Checker, expr: &Expr) { return; }; - if is_lowercase_allowed(env_var) { + if is_lowercase_allowed(env_var.as_str()) { return; } - let capital_env_var = env_var.to_ascii_uppercase(); + let capital_env_var = env_var.as_str().to_ascii_uppercase(); if capital_env_var == env_var.as_str() { return; } diff --git a/crates/ruff_linter/src/rules/pylint/helpers.rs b/crates/ruff_linter/src/rules/pylint/helpers.rs index 8c040f2ed2c87..562b5e2304b9b 100644 --- a/crates/ruff_linter/src/rules/pylint/helpers.rs +++ b/crates/ruff_linter/src/rules/pylint/helpers.rs @@ -12,7 +12,7 @@ pub(super) fn type_param_name(arguments: &Arguments) -> Option<&str> { // Handle both `TypeVar("T")` and `TypeVar(name="T")`. let name_param = arguments.find_argument("name", 0)?; if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &name_param { - Some(value) + Some(value.as_str()) } else { None } diff --git a/crates/ruff_linter/src/rules/pylint/rules/bad_open_mode.rs b/crates/ruff_linter/src/rules/pylint/rules/bad_open_mode.rs index 0750af43b59a0..a5e7f5f325751 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/bad_open_mode.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/bad_open_mode.rs @@ -154,7 +154,7 @@ impl TryFrom for OpenMode { } /// Returns `true` if the open mode is valid. -fn is_valid_mode(mode: &str) -> bool { +fn is_valid_mode(mode: &ast::StringLiteralValue) -> bool { // Flag duplicates and invalid characters. let mut flags = OpenMode::empty(); for char in mode.chars() { diff --git a/crates/ruff_linter/src/rules/pylint/rules/bad_str_strip_call.rs b/crates/ruff_linter/src/rules/pylint/rules/bad_str_strip_call.rs index 36fc831d59c8b..dafa3b0c4f98f 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/bad_str_strip_call.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/bad_str_strip_call.rs @@ -122,7 +122,7 @@ impl fmt::Display for RemovalKind { /// Return `true` if a string contains duplicate characters, taking into account /// escapes. -fn has_duplicates(s: &str) -> bool { +fn has_duplicates(s: &ast::StringLiteralValue) -> bool { let mut escaped = false; let mut seen = FxHashSet::default(); for ch in s.chars() { diff --git a/crates/ruff_linter/src/rules/pylint/rules/repeated_keyword_argument.rs b/crates/ruff_linter/src/rules/pylint/rules/repeated_keyword_argument.rs index 42e896054028b..f3a45e5694ae2 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/repeated_keyword_argument.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/repeated_keyword_argument.rs @@ -60,7 +60,7 @@ pub(crate) fn repeated_keyword_argument(checker: &mut Checker, call: &ExprCall) // Ex) `func(**{"a": 1, "a": 2})` for key in keys.iter().flatten() { if let Expr::StringLiteral(ExprStringLiteral { value, .. }) = key { - if !seen.insert(value) { + if !seen.insert(value.as_str()) { checker.diagnostics.push(Diagnostic::new( RepeatedKeywordArgument { duplicate_keyword: value.to_string(), diff --git a/crates/ruff_linter/src/rules/pylint/rules/unspecified_encoding.rs b/crates/ruff_linter/src/rules/pylint/rules/unspecified_encoding.rs index 49c5575199cf9..0559919d8e905 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/unspecified_encoding.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/unspecified_encoding.rs @@ -81,7 +81,12 @@ pub(crate) fn unspecified_encoding(checker: &mut Checker, call: &ast::ExprCall) /// Returns `true` if the given expression is a string literal containing a `b` character. fn is_binary_mode(expr: &ast::Expr) -> Option { - Some(expr.as_string_literal_expr()?.value.contains('b')) + Some( + expr.as_string_literal_expr()? + .value + .chars() + .any(|c| c == 'b'), + ) } /// Returns `true` if the given call lacks an explicit `encoding`. diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs index 161b63bfa2f77..70e50d0c2288b 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs @@ -185,13 +185,13 @@ fn create_fields_from_fields_arg(fields: &Expr) -> Option> { return None; } let ast::ExprStringLiteral { value: field, .. } = field.as_string_literal_expr()?; - if !is_identifier(field) { + if !is_identifier(field.as_str()) { return None; } - if is_dunder(field) { + if is_dunder(field.as_str()) { return None; } - Some(create_field_assignment_stmt(field, annotation)) + Some(create_field_assignment_stmt(field.as_str(), annotation)) }) .collect() } diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs index dd5503ce22631..a61ac82245bfe 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs @@ -174,13 +174,13 @@ fn fields_from_dict_literal(keys: &[Option], values: &[Expr]) -> Option { - if !is_identifier(field) { + if !is_identifier(field.as_str()) { return None; } - if is_dunder(field) { + if is_dunder(field.as_str()) { return None; } - Some(create_field_assignment_stmt(field, value)) + Some(create_field_assignment_stmt(field.as_str(), value)) } _ => None, }) diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs index 3c757820d9078..ec9cae1295734 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs @@ -228,14 +228,14 @@ fn clean_params_dictionary(right: &Expr, locator: &Locator, stylist: &Stylist) - }) = key { // If the dictionary key is not a valid variable name, abort. - if !is_identifier(key_string) { + if !is_identifier(key_string.as_str()) { return None; } // If there are multiple entries of the same key, abort. if seen.contains(&key_string.as_str()) { return None; } - seen.push(key_string); + seen.push(key_string.as_str()); if is_multi_line { if indent.is_none() { indent = indentation(locator, key); diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/redundant_open_modes.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/redundant_open_modes.rs index 549b340a76127..7a87d03948d5b 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/redundant_open_modes.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/redundant_open_modes.rs @@ -76,7 +76,7 @@ pub(crate) fn redundant_open_modes(checker: &mut Checker, call: &ast::ExprCall) .. }) = &keyword.value { - if let Ok(mode) = OpenMode::from_str(mode_param_value) { + if let Ok(mode) = OpenMode::from_str(mode_param_value.as_str()) { checker.diagnostics.push(create_check( call, &keyword.value, @@ -91,7 +91,7 @@ pub(crate) fn redundant_open_modes(checker: &mut Checker, call: &ast::ExprCall) } Some(mode_param) => { if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &mode_param { - if let Ok(mode) = OpenMode::from_str(value) { + if let Ok(mode) = OpenMode::from_str(value.as_str()) { checker.diagnostics.push(create_check( call, mode_param, diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/unnecessary_encode_utf8.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/unnecessary_encode_utf8.rs index 5966624d9e661..1f9e5ff7ebc4f 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/unnecessary_encode_utf8.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/unnecessary_encode_utf8.rs @@ -74,7 +74,7 @@ fn match_encoded_variable(func: &Expr) -> Option<&Expr> { fn is_utf8_encoding_arg(arg: &Expr) -> bool { if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &arg { - UTF8_LITERALS.contains(&value.to_lowercase().as_str()) + UTF8_LITERALS.contains(&value.as_str().to_lowercase().as_str()) } else { false } @@ -161,7 +161,7 @@ pub(crate) fn unnecessary_encode_utf8(checker: &mut Checker, call: &ast::ExprCal Expr::StringLiteral(ast::ExprStringLiteral { value: literal, .. }) => { // Ex) `"str".encode()`, `"str".encode("utf-8")` if let Some(encoding_arg) = match_encoding_arg(&call.arguments) { - if literal.is_ascii() { + if literal.as_str().is_ascii() { // Ex) Convert `"foo".encode()` to `b"foo"`. let mut diagnostic = Diagnostic::new( UnnecessaryEncodeUTF8 { diff --git a/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs b/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs index 065fa94ec1a83..36259cdc86076 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs @@ -181,14 +181,10 @@ pub(crate) fn implicit_optional(checker: &mut Checker, parameters: &Parameters) continue; }; - if let Expr::StringLiteral(ast::ExprStringLiteral { - range, - value: string, - }) = annotation.as_ref() - { + if let Expr::StringLiteral(ast::ExprStringLiteral { range, value }) = annotation.as_ref() { // Quoted annotation. if let Ok((annotation, kind)) = - parse_type_annotation(string, *range, checker.locator().contents()) + parse_type_annotation(value.as_str(), *range, checker.locator().contents()) { let Some(expr) = type_hint_explicitly_allows_none( &annotation, diff --git a/crates/ruff_linter/src/rules/ruff/typing.rs b/crates/ruff_linter/src/rules/ruff/typing.rs index f02cc09ad5ad0..de898ff285d16 100644 --- a/crates/ruff_linter/src/rules/ruff/typing.rs +++ b/crates/ruff_linter/src/rules/ruff/typing.rs @@ -108,11 +108,10 @@ impl<'a> TypingTarget<'a> { .. }) => Some(TypingTarget::PEP604Union(left, right)), Expr::NoneLiteral(_) => Some(TypingTarget::None), - Expr::StringLiteral(ast::ExprStringLiteral { - value: string, - range, - }) => parse_type_annotation(string, *range, locator.contents()) - .map_or(None, |(expr, _)| Some(TypingTarget::ForwardReference(expr))), + Expr::StringLiteral(ast::ExprStringLiteral { value, range }) => { + parse_type_annotation(value.as_str(), *range, locator.contents()) + .map_or(None, |(expr, _)| Some(TypingTarget::ForwardReference(expr))) + } _ => semantic.resolve_call_path(expr).map_or( // If we can't resolve the call path, it must be defined in the // same file, so we assume it's `Any` as it could be a type alias. diff --git a/crates/ruff_python_ast/src/all.rs b/crates/ruff_python_ast/src/all.rs index 23472dafb61f9..5ac523cf1b8cf 100644 --- a/crates/ruff_python_ast/src/all.rs +++ b/crates/ruff_python_ast/src/all.rs @@ -24,7 +24,7 @@ where fn add_to_names<'a>(elts: &'a [Expr], names: &mut Vec<&'a str>, flags: &mut DunderAllFlags) { for elt in elts { if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = elt { - names.push(value); + names.push(value.as_str()); } else { *flags |= DunderAllFlags::INVALID_OBJECT; } diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index e0bc5b4730686..23faaa9419939 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -1213,7 +1213,26 @@ impl StringLiteralValue { } } + /// Returns `true` if the string literal value is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the total length of the string literal value, in bytes, not + /// [`char`]s or graphemes. + pub fn len(&self) -> usize { + self.parts().fold(0, |acc, part| acc + part.value.len()) + } + + /// Returns an iterator over the [`char`]s of each string literal part. + pub fn chars(&self) -> impl Iterator + '_ { + self.parts().flat_map(|part| part.value.chars()) + } + /// Returns the concatenated string value as a [`str`]. + /// + /// Note that this will perform an allocation on the first invocation if the + /// string value is implicitly concatenated. pub fn as_str(&self) -> &str { match &self.inner { StringLiteralValueInner::Single(value) => value.as_str(), @@ -1224,21 +1243,17 @@ impl StringLiteralValue { impl PartialEq for StringLiteralValue { fn eq(&self, other: &str) -> bool { - self.as_str() == other + if self.len() != other.len() { + return false; + } + // The `zip` here is safe because we have checked the length of both parts. + self.chars().zip(other.chars()).all(|(c1, c2)| c1 == c2) } } impl PartialEq for StringLiteralValue { fn eq(&self, other: &String) -> bool { - self.as_str() == other - } -} - -impl Deref for StringLiteralValue { - type Target = str; - - fn deref(&self) -> &Self::Target { - self.as_str() + self == other.as_str() } } From 501cca8b72f21546b478338990f842f5a16b50f0 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Fri, 24 Nov 2023 18:09:46 -0600 Subject: [PATCH 032/197] Remove `#[allow(unused_variables)]` from visitor methods (#8828) Small follow-up to remove `#[allow(unused_variables)]` from visitor methods and use underscore prefix for unused variables instead. --- crates/ruff_python_ast/src/visitor.rs | 32 ++++++++----------- .../src/visitor/transformer.rs | 30 ++++++++--------- 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/crates/ruff_python_ast/src/visitor.rs b/crates/ruff_python_ast/src/visitor.rs index 8687b09c1019d..3a0781f0724b9 100644 --- a/crates/ruff_python_ast/src/visitor.rs +++ b/crates/ruff_python_ast/src/visitor.rs @@ -757,34 +757,30 @@ pub fn walk_pattern_keyword<'a, V: Visitor<'a> + ?Sized>( visitor.visit_pattern(&pattern_keyword.pattern); } -#[allow(unused_variables)] -pub fn walk_expr_context<'a, V: Visitor<'a> + ?Sized>(visitor: &V, expr_context: &'a ExprContext) {} +pub fn walk_expr_context<'a, V: Visitor<'a> + ?Sized>( + _visitor: &V, + _expr_context: &'a ExprContext, +) { +} -#[allow(unused_variables)] -pub fn walk_bool_op<'a, V: Visitor<'a> + ?Sized>(visitor: &V, bool_op: &'a BoolOp) {} +pub fn walk_bool_op<'a, V: Visitor<'a> + ?Sized>(_visitor: &V, _bool_op: &'a BoolOp) {} -#[allow(unused_variables)] -pub fn walk_operator<'a, V: Visitor<'a> + ?Sized>(visitor: &V, operator: &'a Operator) {} +pub fn walk_operator<'a, V: Visitor<'a> + ?Sized>(_visitor: &V, _operator: &'a Operator) {} -#[allow(unused_variables)] -pub fn walk_unary_op<'a, V: Visitor<'a> + ?Sized>(visitor: &V, unary_op: &'a UnaryOp) {} +pub fn walk_unary_op<'a, V: Visitor<'a> + ?Sized>(_visitor: &V, _unary_op: &'a UnaryOp) {} -#[allow(unused_variables)] -pub fn walk_cmp_op<'a, V: Visitor<'a> + ?Sized>(visitor: &V, cmp_op: &'a CmpOp) {} +pub fn walk_cmp_op<'a, V: Visitor<'a> + ?Sized>(_visitor: &V, _cmp_op: &'a CmpOp) {} -#[allow(unused_variables)] -pub fn walk_alias<'a, V: Visitor<'a> + ?Sized>(visitor: &V, alias: &'a Alias) {} +pub fn walk_alias<'a, V: Visitor<'a> + ?Sized>(_visitor: &V, _alias: &'a Alias) {} -#[allow(unused_variables)] pub fn walk_string_literal<'a, V: Visitor<'a> + ?Sized>( - visitor: &V, - string_literal: &'a StringLiteral, + _visitor: &V, + _string_literal: &'a StringLiteral, ) { } -#[allow(unused_variables)] pub fn walk_bytes_literal<'a, V: Visitor<'a> + ?Sized>( - visitor: &V, - bytes_literal: &'a BytesLiteral, + _visitor: &V, + _bytes_literal: &'a BytesLiteral, ) { } diff --git a/crates/ruff_python_ast/src/visitor/transformer.rs b/crates/ruff_python_ast/src/visitor/transformer.rs index 7e0688092f592..b193aa6c299f0 100644 --- a/crates/ruff_python_ast/src/visitor/transformer.rs +++ b/crates/ruff_python_ast/src/visitor/transformer.rs @@ -743,30 +743,26 @@ pub fn walk_pattern_keyword( visitor.visit_pattern(&mut pattern_keyword.pattern); } -#[allow(unused_variables)] -pub fn walk_expr_context(visitor: &V, expr_context: &mut ExprContext) {} +pub fn walk_expr_context(_visitor: &V, _expr_context: &mut ExprContext) {} -#[allow(unused_variables)] -pub fn walk_bool_op(visitor: &V, bool_op: &mut BoolOp) {} +pub fn walk_bool_op(_visitor: &V, _bool_op: &mut BoolOp) {} -#[allow(unused_variables)] -pub fn walk_operator(visitor: &V, operator: &mut Operator) {} +pub fn walk_operator(_visitor: &V, _operator: &mut Operator) {} -#[allow(unused_variables)] -pub fn walk_unary_op(visitor: &V, unary_op: &mut UnaryOp) {} +pub fn walk_unary_op(_visitor: &V, _unary_op: &mut UnaryOp) {} -#[allow(unused_variables)] -pub fn walk_cmp_op(visitor: &V, cmp_op: &mut CmpOp) {} +pub fn walk_cmp_op(_visitor: &V, _cmp_op: &mut CmpOp) {} -#[allow(unused_variables)] -pub fn walk_alias(visitor: &V, alias: &mut Alias) {} +pub fn walk_alias(_visitor: &V, _alias: &mut Alias) {} -#[allow(unused_variables)] pub fn walk_string_literal( - visitor: &V, - string_literal: &mut StringLiteral, + _visitor: &V, + _string_literal: &mut StringLiteral, ) { } -#[allow(unused_variables)] -pub fn walk_bytes_literal(visitor: &V, bytes_literal: &mut BytesLiteral) {} +pub fn walk_bytes_literal( + _visitor: &V, + _bytes_literal: &mut BytesLiteral, +) { +} From 1dbfab9a0c8cdea9624783dba70b974a6b4de529 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Sat, 25 Nov 2023 07:00:47 -0600 Subject: [PATCH 033/197] Auto-generate formatter nodes for string parts (#8837) A follow-up to auto-generate the `FormatNodeRule` implementation for the string part nodes. This is just a dummy implementation that is unreachable because it's handled by the parent nodes. --- crates/ruff_python_formatter/src/generated.rs | 100 ++++++++++++++++++ .../src/other/bytes_literal.rs | 12 +++ .../src/other/f_string.rs | 12 +++ crates/ruff_python_formatter/src/other/mod.rs | 3 + .../src/other/string_literal.rs | 12 +++ 5 files changed, 139 insertions(+) create mode 100644 crates/ruff_python_formatter/src/other/bytes_literal.rs create mode 100644 crates/ruff_python_formatter/src/other/f_string.rs create mode 100644 crates/ruff_python_formatter/src/other/string_literal.rs diff --git a/crates/ruff_python_formatter/src/generated.rs b/crates/ruff_python_formatter/src/generated.rs index dfa93b8961ac3..30b5bb122ae9e 100644 --- a/crates/ruff_python_formatter/src/generated.rs +++ b/crates/ruff_python_formatter/src/generated.rs @@ -2978,3 +2978,103 @@ impl<'ast> IntoFormat> for ast::TypeParamParamSpec { ) } } + +impl FormatRule> for crate::other::f_string::FormatFString { + #[inline] + fn fmt(&self, node: &ast::FString, f: &mut PyFormatter) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl<'ast> AsFormat> for ast::FString { + type Format<'a> = FormatRefWithRule< + 'a, + ast::FString, + crate::other::f_string::FormatFString, + PyFormatContext<'ast>, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new(self, crate::other::f_string::FormatFString::default()) + } +} +impl<'ast> IntoFormat> for ast::FString { + type Format = FormatOwnedWithRule< + ast::FString, + crate::other::f_string::FormatFString, + PyFormatContext<'ast>, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new(self, crate::other::f_string::FormatFString::default()) + } +} + +impl FormatRule> + for crate::other::string_literal::FormatStringLiteral +{ + #[inline] + fn fmt(&self, node: &ast::StringLiteral, f: &mut PyFormatter) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl<'ast> AsFormat> for ast::StringLiteral { + type Format<'a> = FormatRefWithRule< + 'a, + ast::StringLiteral, + crate::other::string_literal::FormatStringLiteral, + PyFormatContext<'ast>, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::other::string_literal::FormatStringLiteral::default(), + ) + } +} +impl<'ast> IntoFormat> for ast::StringLiteral { + type Format = FormatOwnedWithRule< + ast::StringLiteral, + crate::other::string_literal::FormatStringLiteral, + PyFormatContext<'ast>, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::other::string_literal::FormatStringLiteral::default(), + ) + } +} + +impl FormatRule> + for crate::other::bytes_literal::FormatBytesLiteral +{ + #[inline] + fn fmt(&self, node: &ast::BytesLiteral, f: &mut PyFormatter) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl<'ast> AsFormat> for ast::BytesLiteral { + type Format<'a> = FormatRefWithRule< + 'a, + ast::BytesLiteral, + crate::other::bytes_literal::FormatBytesLiteral, + PyFormatContext<'ast>, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::other::bytes_literal::FormatBytesLiteral::default(), + ) + } +} +impl<'ast> IntoFormat> for ast::BytesLiteral { + type Format = FormatOwnedWithRule< + ast::BytesLiteral, + crate::other::bytes_literal::FormatBytesLiteral, + PyFormatContext<'ast>, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::other::bytes_literal::FormatBytesLiteral::default(), + ) + } +} diff --git a/crates/ruff_python_formatter/src/other/bytes_literal.rs b/crates/ruff_python_formatter/src/other/bytes_literal.rs new file mode 100644 index 0000000000000..55117241f8598 --- /dev/null +++ b/crates/ruff_python_formatter/src/other/bytes_literal.rs @@ -0,0 +1,12 @@ +use ruff_python_ast::BytesLiteral; + +use crate::prelude::*; + +#[derive(Default)] +pub struct FormatBytesLiteral; + +impl FormatNodeRule for FormatBytesLiteral { + fn fmt_fields(&self, _item: &BytesLiteral, _f: &mut PyFormatter) -> FormatResult<()> { + unreachable!("Handled inside of `FormatExprBytesLiteral`"); + } +} diff --git a/crates/ruff_python_formatter/src/other/f_string.rs b/crates/ruff_python_formatter/src/other/f_string.rs new file mode 100644 index 0000000000000..e08254aba7511 --- /dev/null +++ b/crates/ruff_python_formatter/src/other/f_string.rs @@ -0,0 +1,12 @@ +use ruff_python_ast::FString; + +use crate::prelude::*; + +#[derive(Default)] +pub struct FormatFString; + +impl FormatNodeRule for FormatFString { + fn fmt_fields(&self, _item: &FString, _f: &mut PyFormatter) -> FormatResult<()> { + unreachable!("Handled inside of `FormatExprFString`"); + } +} diff --git a/crates/ruff_python_formatter/src/other/mod.rs b/crates/ruff_python_formatter/src/other/mod.rs index e7eb28ae7f4fd..c980a14c0fe09 100644 --- a/crates/ruff_python_formatter/src/other/mod.rs +++ b/crates/ruff_python_formatter/src/other/mod.rs @@ -1,14 +1,17 @@ pub(crate) mod alias; pub(crate) mod arguments; +pub(crate) mod bytes_literal; pub(crate) mod commas; pub(crate) mod comprehension; pub(crate) mod decorator; pub(crate) mod elif_else_clause; pub(crate) mod except_handler_except_handler; +pub(crate) mod f_string; pub(crate) mod identifier; pub(crate) mod keyword; pub(crate) mod match_case; pub(crate) mod parameter; pub(crate) mod parameter_with_default; pub(crate) mod parameters; +pub(crate) mod string_literal; pub(crate) mod with_item; diff --git a/crates/ruff_python_formatter/src/other/string_literal.rs b/crates/ruff_python_formatter/src/other/string_literal.rs new file mode 100644 index 0000000000000..291552db73a1d --- /dev/null +++ b/crates/ruff_python_formatter/src/other/string_literal.rs @@ -0,0 +1,12 @@ +use ruff_python_ast::StringLiteral; + +use crate::prelude::*; + +#[derive(Default)] +pub struct FormatStringLiteral; + +impl FormatNodeRule for FormatStringLiteral { + fn fmt_fields(&self, _item: &StringLiteral, _f: &mut PyFormatter) -> FormatResult<()> { + unreachable!("Handled inside of `FormatExprStringLiteral`"); + } +} From 0d4af9d3c60715b88ba7a5ed3c4386887c6ce4f8 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 25 Nov 2023 18:16:43 +0000 Subject: [PATCH 034/197] Allow space-before-colon after end-of-slice (#8838) Closes https://github.com/astral-sh/ruff/issues/8752. --- .../test/fixtures/pycodestyle/E20.py | 12 +++++++++++ .../logical_lines/extraneous_whitespace.rs | 19 ++++++++++++++++-- ...ules__pycodestyle__tests__E202_E20.py.snap | 20 +++++++++++++++++++ ...ules__pycodestyle__tests__E203_E20.py.snap | 20 +++++++++++++++++++ 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E20.py b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E20.py index 84355d21e0e48..7c76aa6ed14b0 100644 --- a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E20.py +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E20.py @@ -135,3 +135,15 @@ #: E203:1:20 ham[{lower + offset : upper + offset} : upper + offset] + +#: Okay +ham[upper:] + +#: Okay +ham[upper :] + +#: E202:1:12 +ham[upper : ] + +#: E203:1:10 +ham[upper :] diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs index bfc7bcaefd065..a4134e51cbb96 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs @@ -213,13 +213,28 @@ pub(crate) fn extraneous_whitespace(line: &LogicalLine, context: &mut LogicalLin diagnostic.range(), ))); context.push_diagnostic(diagnostic); + } else if iter + .peek() + .is_some_and(|token| token.kind() == TokenKind::Rsqb) + { + // Allow `foo[1 :]`, but not `foo[1 :]`. + if let (Whitespace::Many | Whitespace::Tab, offset) = whitespace + { + let mut diagnostic = Diagnostic::new( + WhitespaceBeforePunctuation { symbol }, + TextRange::at(token.start() - offset, offset), + ); + diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion( + diagnostic.range(), + ))); + context.push_diagnostic(diagnostic); + } } else { + // Allow, e.g., `foo[1:2]` or `foo[1 : 2]` or `foo[1 :: 2]`. let token = iter .peek() .filter(|next| matches!(next.kind(), TokenKind::Colon)) .unwrap_or(&token); - - // Allow, e.g., `foo[1:2]` or `foo[1 : 2]` or `foo[1 :: 2]`. if line.trailing_whitespace(token) != whitespace { let mut diagnostic = Diagnostic::new( WhitespaceBeforePunctuation { symbol }, diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E202_E20.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E202_E20.py.snap index 67d7bc6e28897..971a719f3da44 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E202_E20.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E202_E20.py.snap @@ -146,4 +146,24 @@ E20.py:90:18: E202 [*] Whitespace before ']' 92 92 | 93 93 | #: Okay +E20.py:146:12: E202 [*] Whitespace before ']' + | +145 | #: E202:1:12 +146 | ham[upper : ] + | ^ E202 +147 | +148 | #: E203:1:10 + | + = help: Remove whitespace before ']' + +ℹ Safe fix +143 143 | ham[upper :] +144 144 | +145 145 | #: E202:1:12 +146 |-ham[upper : ] + 146 |+ham[upper :] +147 147 | +148 148 | #: E203:1:10 +149 149 | ham[upper :] + diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E203_E20.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E203_E20.py.snap index c81fa5d87894a..d92741af055a6 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E203_E20.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E203_E20.py.snap @@ -211,6 +211,8 @@ E20.py:137:20: E203 [*] Whitespace before ':' 136 | #: E203:1:20 137 | ham[{lower + offset : upper + offset} : upper + offset] | ^ E203 +138 | +139 | #: Okay | = help: Remove whitespace before ':' @@ -220,5 +222,23 @@ E20.py:137:20: E203 [*] Whitespace before ':' 136 136 | #: E203:1:20 137 |-ham[{lower + offset : upper + offset} : upper + offset] 137 |+ham[{lower + offset: upper + offset} : upper + offset] +138 138 | +139 139 | #: Okay +140 140 | ham[upper:] + +E20.py:149:10: E203 [*] Whitespace before ':' + | +148 | #: E203:1:10 +149 | ham[upper :] + | ^^ E203 + | + = help: Remove whitespace before ':' + +ℹ Safe fix +146 146 | ham[upper : ] +147 147 | +148 148 | #: E203:1:10 +149 |-ham[upper :] + 149 |+ham[upper:] From 9b17724d7781415a9d0ed5895d55cef6232156fa Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 25 Nov 2023 18:42:19 +0000 Subject: [PATCH 035/197] [`pylint`] Extend `self-assigning-variable` to multi-target assignments (#8839) Closes https://github.com/astral-sh/ruff/issues/8667. --- .../pylint/self_assigning_variable.py | 3 + .../src/checkers/ast/analyze/statement.rs | 11 ++- .../pylint/rules/self_assigning_variable.rs | 71 ++++++++++++------- ...s__PLW0127_self_assigning_variable.py.snap | 53 +++++++++++++- 4 files changed, 105 insertions(+), 33 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/self_assigning_variable.py b/crates/ruff_linter/resources/test/fixtures/pylint/self_assigning_variable.py index 288d6d6c6272e..05925a02f18a8 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/self_assigning_variable.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/self_assigning_variable.py @@ -23,6 +23,9 @@ (foo, (bar, baz)) = (foo, (bar, 1)) foo: int = foo bar: int = bar +foo = foo = bar +(foo, bar) = (foo, bar) = baz +(foo, bar) = baz = (foo, bar) = 1 # Non-errors. foo = bar diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 48343b3825c7c..448ce1d2bac06 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -1355,7 +1355,6 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { } } Stmt::Assign(assign @ ast::StmtAssign { targets, value, .. }) => { - checker.enabled(Rule::NonAsciiName); if checker.enabled(Rule::LambdaAssignment) { if let [target] = &targets[..] { pycodestyle::rules::lambda_assignment(checker, target, value, None, stmt); @@ -1407,9 +1406,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { } } if checker.settings.rules.enabled(Rule::SelfAssigningVariable) { - if let [target] = targets.as_slice() { - pylint::rules::self_assigning_variable(checker, target, value); - } + pylint::rules::self_assignment(checker, assign); } if checker.settings.rules.enabled(Rule::TypeParamNameMismatch) { pylint::rules::type_param_name_mismatch(checker, value, targets); @@ -1479,9 +1476,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { stmt, ); } - if checker.enabled(Rule::SelfAssigningVariable) { - pylint::rules::self_assigning_variable(checker, target, value); - } + } + if checker.enabled(Rule::SelfAssigningVariable) { + pylint::rules::self_annotated_assignment(checker, assign_stmt); } if checker.enabled(Rule::UnintentionalTypeAnnotation) { flake8_bugbear::rules::unintentional_type_annotation( diff --git a/crates/ruff_linter/src/rules/pylint/rules/self_assigning_variable.rs b/crates/ruff_linter/src/rules/pylint/rules/self_assigning_variable.rs index a30b6294acc43..68875a9eb57c2 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/self_assigning_variable.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/self_assigning_variable.rs @@ -1,3 +1,4 @@ +use itertools::Itertools; use ruff_python_ast::{self as ast, Expr}; use ruff_diagnostics::{Diagnostic, Violation}; @@ -36,30 +37,28 @@ impl Violation for SelfAssigningVariable { } /// PLW0127 -pub(crate) fn self_assigning_variable(checker: &mut Checker, target: &Expr, value: &Expr) { - fn inner(left: &Expr, right: &Expr, diagnostics: &mut Vec) { - match (left, right) { - ( - Expr::Tuple(ast::ExprTuple { elts: lhs_elts, .. }), - Expr::Tuple(ast::ExprTuple { elts: rhs_elts, .. }), - ) if lhs_elts.len() == rhs_elts.len() => lhs_elts - .iter() - .zip(rhs_elts.iter()) - .for_each(|(lhs, rhs)| inner(lhs, rhs, diagnostics)), - ( - Expr::Name(ast::ExprName { id: lhs_name, .. }), - Expr::Name(ast::ExprName { id: rhs_name, .. }), - ) if lhs_name == rhs_name => { - diagnostics.push(Diagnostic::new( - SelfAssigningVariable { - name: lhs_name.to_string(), - }, - left.range(), - )); - } - _ => {} - } +pub(crate) fn self_assignment(checker: &mut Checker, assign: &ast::StmtAssign) { + // Assignments in class bodies are attributes (e.g., `x = x` assigns `x` to `self.x`, and thus + // is not a self-assignment). + if checker.semantic().current_scope().kind.is_class() { + return; + } + + for (left, right) in assign + .targets + .iter() + .chain(std::iter::once(assign.value.as_ref())) + .tuple_combinations() + { + visit_assignments(left, right, &mut checker.diagnostics); } +} + +/// PLW0127 +pub(crate) fn self_annotated_assignment(checker: &mut Checker, assign: &ast::StmtAnnAssign) { + let Some(value) = assign.value.as_ref() else { + return; + }; // Assignments in class bodies are attributes (e.g., `x = x` assigns `x` to `self.x`, and thus // is not a self-assignment). @@ -67,5 +66,29 @@ pub(crate) fn self_assigning_variable(checker: &mut Checker, target: &Expr, valu return; } - inner(target, value, &mut checker.diagnostics); + visit_assignments(&assign.target, value, &mut checker.diagnostics); +} + +fn visit_assignments(left: &Expr, right: &Expr, diagnostics: &mut Vec) { + match (left, right) { + ( + Expr::Tuple(ast::ExprTuple { elts: lhs_elts, .. }), + Expr::Tuple(ast::ExprTuple { elts: rhs_elts, .. }), + ) if lhs_elts.len() == rhs_elts.len() => lhs_elts + .iter() + .zip(rhs_elts.iter()) + .for_each(|(lhs, rhs)| visit_assignments(lhs, rhs, diagnostics)), + ( + Expr::Name(ast::ExprName { id: lhs_name, .. }), + Expr::Name(ast::ExprName { id: rhs_name, .. }), + ) if lhs_name == rhs_name => { + diagnostics.push(Diagnostic::new( + SelfAssigningVariable { + name: lhs_name.to_string(), + }, + left.range(), + )); + } + _ => {} + } } diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0127_self_assigning_variable.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0127_self_assigning_variable.py.snap index 80ecb80e58fdd..882bd21a0a030 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0127_self_assigning_variable.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW0127_self_assigning_variable.py.snap @@ -347,6 +347,7 @@ self_assigning_variable.py:24:1: PLW0127 Self-assignment of variable `foo` 24 | foo: int = foo | ^^^ PLW0127 25 | bar: int = bar +26 | foo = foo = bar | self_assigning_variable.py:25:1: PLW0127 Self-assignment of variable `bar` @@ -355,8 +356,56 @@ self_assigning_variable.py:25:1: PLW0127 Self-assignment of variable `bar` 24 | foo: int = foo 25 | bar: int = bar | ^^^ PLW0127 -26 | -27 | # Non-errors. +26 | foo = foo = bar +27 | (foo, bar) = (foo, bar) = baz + | + +self_assigning_variable.py:26:1: PLW0127 Self-assignment of variable `foo` + | +24 | foo: int = foo +25 | bar: int = bar +26 | foo = foo = bar + | ^^^ PLW0127 +27 | (foo, bar) = (foo, bar) = baz +28 | (foo, bar) = baz = (foo, bar) = 1 + | + +self_assigning_variable.py:27:2: PLW0127 Self-assignment of variable `foo` + | +25 | bar: int = bar +26 | foo = foo = bar +27 | (foo, bar) = (foo, bar) = baz + | ^^^ PLW0127 +28 | (foo, bar) = baz = (foo, bar) = 1 + | + +self_assigning_variable.py:27:7: PLW0127 Self-assignment of variable `bar` + | +25 | bar: int = bar +26 | foo = foo = bar +27 | (foo, bar) = (foo, bar) = baz + | ^^^ PLW0127 +28 | (foo, bar) = baz = (foo, bar) = 1 + | + +self_assigning_variable.py:28:2: PLW0127 Self-assignment of variable `foo` + | +26 | foo = foo = bar +27 | (foo, bar) = (foo, bar) = baz +28 | (foo, bar) = baz = (foo, bar) = 1 + | ^^^ PLW0127 +29 | +30 | # Non-errors. + | + +self_assigning_variable.py:28:7: PLW0127 Self-assignment of variable `bar` + | +26 | foo = foo = bar +27 | (foo, bar) = (foo, bar) = baz +28 | (foo, bar) = baz = (foo, bar) = 1 + | ^^^ PLW0127 +29 | +30 | # Non-errors. | From 074812115f3076e7d8f22f04d703a2eccfe378a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 10:02:53 +0000 Subject: [PATCH 036/197] Bump wasm-bindgen-test from 0.3.37 to 0.3.38 (#8847) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 13 +++++++------ crates/ruff_wasm/Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 18464bcbec0a1..f27f309d3559f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3485,9 +3485,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if", "js-sys", @@ -3526,9 +3526,9 @@ checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "wasm-bindgen-test" -version = "0.3.37" +version = "0.3.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671" +checksum = "c6433b7c56db97397842c46b67e11873eda263170afeb3a2dc74a7cb370fee0d" dependencies = [ "console_error_panic_hook", "js-sys", @@ -3540,12 +3540,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.37" +version = "0.3.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" +checksum = "493fcbab756bb764fa37e6bee8cec2dd709eb4273d06d0c282a5e74275ded735" dependencies = [ "proc-macro2", "quote", + "syn 2.0.39", ] [[package]] diff --git a/crates/ruff_wasm/Cargo.toml b/crates/ruff_wasm/Cargo.toml index b1abff1d3fb4f..a4998df0fb852 100644 --- a/crates/ruff_wasm/Cargo.toml +++ b/crates/ruff_wasm/Cargo.toml @@ -41,7 +41,7 @@ wasm-bindgen = { version = "0.2.84" } js-sys = { version = "0.3.65" } [dev-dependencies] -wasm-bindgen-test = { version = "0.3.34" } +wasm-bindgen-test = { version = "0.3.38" } [lints] workspace = true From 16085339bcfcf99619a5b8afa9cbfe40d96e44fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 10:04:24 +0000 Subject: [PATCH 037/197] Bump globset from 0.4.13 to 0.4.14 (#8848) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f27f309d3559f..03c52ed1a938b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -903,15 +903,15 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" dependencies = [ "aho-corasick", "bstr", - "fnv", "log", - "regex", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 2a12303cd8d7e..293faa781132c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ clap = { version = "4.4.7", features = ["derive"] } colored = { version = "2.0.0" } filetime = { version = "0.2.20" } glob = { version = "0.3.1" } -globset = { version = "0.4.10" } +globset = { version = "0.4.14" } ignore = { version = "0.4.20" } insta = { version = "1.34.0", feature = ["filters", "glob"] } is-macro = { version = "0.3.0" } From 2f5859e79e75c3f92ecfeb3c45f97dd73c97f0e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 10:05:50 +0000 Subject: [PATCH 038/197] Bump uuid from 1.6.0 to 1.6.1 (#8851) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03c52ed1a938b..badd4c0eaefa3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3367,9 +3367,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58fe91d841bc04822c9801002db4ea904b9e4b8e6bbad25127b46eff8dc516b" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" dependencies = [ "getrandom", "rand", @@ -3379,9 +3379,9 @@ dependencies = [ [[package]] name = "uuid-macro-internal" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fccbdae4ed44e1ea6c1aae832af19cd3487ee186953f721b46d1c441176050" +checksum = "f49e7f3f3db8040a100710a11932239fd30697115e2ba4107080d8252939845e" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 293faa781132c..aead6ebcc45e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } unicode-ident = { version = "1.0.12" } unicode_names2 = { version = "1.2.0" } unicode-width = { version = "0.1.11" } -uuid = { version = "1.6.0", features = ["v4", "fast-rng", "macro-diagnostics", "js"] } +uuid = { version = "1.6.1", features = ["v4", "fast-rng", "macro-diagnostics", "js"] } wsl = { version = "0.1.0" } [workspace.lints.rust] From d0591561c92faa299bfde4ffc6b1616589269576 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 10:07:22 +0000 Subject: [PATCH 039/197] Bump configparser from 3.0.2 to 3.0.3 (#8849) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- crates/flake8_to_ruff/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index badd4c0eaefa3..81f6eb9711a7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -444,9 +444,9 @@ dependencies = [ [[package]] name = "configparser" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5458d9d1a587efaf5091602c59d299696a3877a439c8f6d461a2d3cce11df87a" +checksum = "e0e56e414a2a52ab2a104f85cd40933c2fbc278b83637facf646ecf451b49237" [[package]] name = "console" diff --git a/crates/flake8_to_ruff/Cargo.toml b/crates/flake8_to_ruff/Cargo.toml index 9d85f52c19e4f..b17abde1a880d 100644 --- a/crates/flake8_to_ruff/Cargo.toml +++ b/crates/flake8_to_ruff/Cargo.toml @@ -19,7 +19,7 @@ ruff_workspace = { path = "../ruff_workspace" } anyhow = { workspace = true } clap = { workspace = true } colored = { workspace = true } -configparser = { version = "3.0.2" } +configparser = { version = "3.0.3" } itertools = { workspace = true } log = { workspace = true } once_cell = { workspace = true } From 0202a4929732f3b3afb916f50691aaa678027fee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 10:14:06 +0000 Subject: [PATCH 040/197] Bump proc-macro2 from 1.0.69 to 1.0.70 (#8850) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81f6eb9711a7b..b29c2bd77ae0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1793,9 +1793,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] diff --git a/Cargo.toml b/Cargo.toml index aead6ebcc45e2..606769499258d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ log = { version = "0.4.17" } memchr = { version = "2.6.4" } once_cell = { version = "1.17.1" } path-absolutize = { version = "3.1.1" } -proc-macro2 = { version = "1.0.69" } +proc-macro2 = { version = "1.0.70" } quote = { version = "1.0.23" } regex = { version = "1.10.2" } rustc-hash = { version = "1.1.0" } From 1f14d9a9f793b25cba37a376bff0ee467f090c38 Mon Sep 17 00:00:00 2001 From: Samuel Searles-Bryant Date: Mon, 27 Nov 2023 15:27:22 +0000 Subject: [PATCH 041/197] Add advice for fixing RUF008 when mutability is not desired (#8853) --- .../src/rules/ruff/rules/mutable_class_default.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/src/rules/ruff/rules/mutable_class_default.rs b/crates/ruff_linter/src/rules/ruff/rules/mutable_class_default.rs index da1e2837512a4..776209d6f6812 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/mutable_class_default.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/mutable_class_default.rs @@ -20,13 +20,15 @@ use crate::rules::ruff::rules::helpers::{ /// changed in one instance, as those changes will unexpectedly affect all /// other instances. /// -/// When mutable value are intended, they should be annotated with -/// `typing.ClassVar`. +/// When mutable values are intended, they should be annotated with +/// `typing.ClassVar`. When mutability is not required, values should be +/// immutable types, like `tuple` or `frozenset`. /// /// ## Examples /// ```python /// class A: /// mutable_default: list[int] = [] +/// immutable_default: list[int] = [] /// ``` /// /// Use instead: @@ -36,6 +38,7 @@ use crate::rules::ruff::rules::helpers::{ /// /// class A: /// mutable_default: ClassVar[list[int]] = [] +/// immutable_default: tuple[int, ...] = () /// ``` #[violation] pub struct MutableClassDefault; From d9845a2628d25cba3fa21bb53ad78ad377128aa2 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Mon, 27 Nov 2023 11:14:55 -0500 Subject: [PATCH 042/197] format doctests in docstrings (#8811) ## Summary This PR adds opt-in support for formatting doctests in docstrings. This reflects initial support and it is intended to add support for Markdown and reStructuredText Python code blocks in the future. But I believe this PR lays the groundwork, and future additions for Markdown and reST should be less costly to add. It's strongly recommended to review this PR commit-by-commit. The last few commits in particular implement the bulk of the work here and represent the denser portions. Some things worth mentioning: * The formatter is itself not perfect, and it is possible for it to produce invalid Python code. Because of this, reformatted code snippets are checked for Python validity. If they aren't valid, then we (unfortunately silently) bail on formatting that code snippet. * There are a couple places where it would be nice to at least warn the user that doctest formatting failed, but it wasn't clear to me what the best way to do that is. * I haven't yet run this in anger on a real world code base. I think that should happen before merging. Closes #7146 ## Test Plan * [x] Pass the local test suite. * [x] Scrutinize ecosystem changes. * [x] Run this formatter on extant code and scrutinize the results. (e.g., CPython, numpy.) --- .gitattributes | 3 + Cargo.lock | 1 + crates/ruff_python_formatter/Cargo.toml | 1 + .../ruff/docstring_code_examples.options.json | 42 + .../fixtures/ruff/docstring_code_examples.py | 316 ++ .../docstring_code_examples_crlf.options.json | 8 + .../ruff/docstring_code_examples_crlf.py | 9 + crates/ruff_python_formatter/src/context.rs | 33 +- .../src/expression/string.rs | 676 +++- crates/ruff_python_formatter/src/lib.rs | 4 +- crates/ruff_python_formatter/src/options.rs | 34 + .../ruff_python_formatter/tests/fixtures.rs | 28 +- .../ruff_python_formatter/tests/normalizer.rs | 34 +- .../tests/snapshots/format@docstring.py.snap | 8 + .../format@docstring_code_examples.py.snap | 3006 +++++++++++++++++ ...ormat@docstring_code_examples_crlf.py.snap | 44 + .../format@expression__bytes.py.snap | 4 + .../format@expression__string.py.snap | 4 + ...rmat@fmt_on_off__fmt_off_docstring.py.snap | 4 + .../format@fmt_on_off__indent.py.snap | 6 + ...at@fmt_on_off__mixed_space_and_tab.py.snap | 6 + .../tests/snapshots/format@preview.py.snap | 4 + .../format@skip_magic_trailing_comma.py.snap | 4 + .../tests/snapshots/format@tab_width.py.snap | 6 + 24 files changed, 4194 insertions(+), 91 deletions(-) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_crlf.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_crlf.py create mode 100644 crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap diff --git a/.gitattributes b/.gitattributes index 23c253a26d08a..8dd4fe466ad6e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,5 +3,8 @@ crates/ruff_linter/resources/test/fixtures/isort/line_ending_crlf.py text eol=crlf crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_1.py text eol=crlf +crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_crlf.py text eol=crlf +crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap text eol=crlf + ruff.schema.json linguist-generated=true text=auto eol=lf *.md.snap linguist-language=Markdown diff --git a/Cargo.lock b/Cargo.lock index b29c2bd77ae0c..ee526538f941e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2334,6 +2334,7 @@ dependencies = [ "itertools 0.11.0", "memchr", "once_cell", + "regex", "ruff_cache", "ruff_formatter", "ruff_macros", diff --git a/crates/ruff_python_formatter/Cargo.toml b/crates/ruff_python_formatter/Cargo.toml index 24325082f0f99..5bc38d4960f15 100644 --- a/crates/ruff_python_formatter/Cargo.toml +++ b/crates/ruff_python_formatter/Cargo.toml @@ -41,6 +41,7 @@ unicode-width = { workspace = true } ruff_formatter = { path = "../ruff_formatter" } insta = { workspace = true, features = ["glob"] } +regex = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } similar = { workspace = true } diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.options.json b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.options.json new file mode 100644 index 0000000000000..b2a2d8a4e537d --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.options.json @@ -0,0 +1,42 @@ +[ + { + "docstring_code": "disabled", + "indent_style": "space", + "indent_width": 4 + }, + { + "docstring_code": "disabled", + "indent_style": "space", + "indent_width": 2 + }, + { + "docstring_code": "disabled", + "indent_style": "tab", + "indent_width": 8 + }, + { + "docstring_code": "disabled", + "indent_style": "tab", + "indent_width": 4 + }, + { + "docstring_code": "enabled", + "indent_style": "space", + "indent_width": 4 + }, + { + "docstring_code": "enabled", + "indent_style": "space", + "indent_width": 2 + }, + { + "docstring_code": "enabled", + "indent_style": "tab", + "indent_width": 8 + }, + { + "docstring_code": "enabled", + "indent_style": "tab", + "indent_width": 4 + } +] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py new file mode 100644 index 0000000000000..1050c71a31847 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py @@ -0,0 +1,316 @@ +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + >>> cool_stuff( y ) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + """ + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... + ... print( x ) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested( x ): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + ''' + Do cool stuff. + + >>> assert ("Easy!") + >>> import math + >>> math.floor( 1.9 ) + 1 + ''' + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + ''' + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) + ''' + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( x ) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_crlf.options.json b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_crlf.options.json new file mode 100644 index 0000000000000..6af4394568536 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_crlf.options.json @@ -0,0 +1,8 @@ +[ + { + "docstring_code": "enabled", + "indent_style": "space", + "indent_width": 4, + "line_ending": "CarriageReturnLineFeed" + } +] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_crlf.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_crlf.py new file mode 100644 index 0000000000000..05cc97963f21e --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_crlf.py @@ -0,0 +1,9 @@ +def doctest_line_ending(): + """ + Do cool stuff. + >>> def foo( x ): + ... print( x ) + ... + ... print( x ) + """ + pass diff --git a/crates/ruff_python_formatter/src/context.rs b/crates/ruff_python_formatter/src/context.rs index f92825fe958f4..eb8fe7edf4155 100644 --- a/crates/ruff_python_formatter/src/context.rs +++ b/crates/ruff_python_formatter/src/context.rs @@ -1,5 +1,5 @@ use crate::comments::Comments; -use crate::PyFormatOptions; +use crate::{PyFormatOptions, QuoteStyle}; use ruff_formatter::{Buffer, FormatContext, GroupId, SourceCode}; use ruff_source_file::Locator; use std::fmt::{Debug, Formatter}; @@ -11,6 +11,15 @@ pub struct PyFormatContext<'a> { contents: &'a str, comments: Comments<'a>, node_level: NodeLevel, + /// Set to a non-None value when the formatter is running on a code + /// snippet within a docstring. The value should be the quote style of the + /// docstring containing the code snippet. + /// + /// Various parts of the formatter may inspect this state to change how it + /// works. For example, multi-line strings will always be written with a + /// quote style that is inverted from the one here in order to ensure that + /// the formatted Python code will be valid. + docstring: Option, } impl<'a> PyFormatContext<'a> { @@ -20,6 +29,7 @@ impl<'a> PyFormatContext<'a> { contents, comments, node_level: NodeLevel::TopLevel(TopLevelStatementPosition::Other), + docstring: None, } } @@ -43,6 +53,27 @@ impl<'a> PyFormatContext<'a> { pub(crate) fn comments(&self) -> &Comments<'a> { &self.comments } + + /// Returns a non-None value only if the formatter is running on a code + /// snippet within a docstring. + /// + /// The quote style returned corresponds to the quoting used for the + /// docstring containing the code snippet currently being formatted. + pub(crate) fn docstring(&self) -> Option { + self.docstring + } + + /// Return a new context suitable for formatting code snippets within a + /// docstring. + /// + /// The quote style given should correspond to the style of quoting used + /// for the docstring containing the code snippets. + pub(crate) fn in_docstring(self, style: QuoteStyle) -> PyFormatContext<'a> { + PyFormatContext { + docstring: Some(style), + ..self + } + } } impl FormatContext for PyFormatContext<'_> { diff --git a/crates/ruff_python_formatter/src/expression/string.rs b/crates/ruff_python_formatter/src/expression/string.rs index cb534d49a4517..2c711ac60ef1f 100644 --- a/crates/ruff_python_formatter/src/expression/string.rs +++ b/crates/ruff_python_formatter/src/expression/string.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use bitflags::bitflags; -use ruff_formatter::{format_args, write}; +use ruff_formatter::{format_args, write, Printed}; use ruff_python_ast::AnyNodeRef; use ruff_python_ast::{ self as ast, ExprBytesLiteral, ExprFString, ExprStringLiteral, ExpressionRef, @@ -16,9 +16,10 @@ use crate::expression::parentheses::{ }; use crate::expression::Expr; use crate::prelude::*; +use crate::FormatModuleError; use crate::QuoteStyle; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] enum Quoting { CanChange, Preserve, @@ -189,6 +190,7 @@ impl<'a> FormatString<'a> { impl<'a> Format> for FormatString<'a> { fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { + let parent_docstring_quote_style = f.context().docstring(); let locator = f.context().locator(); let result = match self.layout { StringLayout::Default => { @@ -200,14 +202,19 @@ impl<'a> Format> for FormatString<'a> { self.string.quoting(&locator), &locator, f.options().quote_style(), + parent_docstring_quote_style, ) .fmt(f) } } StringLayout::DocString => { let string_part = StringPart::from_source(self.string.range(), &locator); - let normalized = - string_part.normalize(Quoting::CanChange, &locator, f.options().quote_style()); + let normalized = string_part.normalize( + Quoting::CanChange, + &locator, + f.options().quote_style(), + parent_docstring_quote_style, + ); format_docstring(&normalized, f) } StringLayout::ImplicitConcatenatedStringInBinaryLike => { @@ -243,6 +250,7 @@ impl Format> for FormatStringContinuation<'_> { fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { let comments = f.context().comments().clone(); let locator = f.context().locator(); + let in_docstring = f.context().docstring(); let quote_style = f.options().quote_style(); let mut joiner = f.join_with(in_parentheses_only_soft_line_break_or_space()); @@ -252,6 +260,7 @@ impl Format> for FormatStringContinuation<'_> { self.string.quoting(&locator), &locator, quote_style, + in_docstring, ); joiner.entry(&format_args![ @@ -301,16 +310,72 @@ impl StringPart { } /// Computes the strings preferred quotes and normalizes its content. + /// + /// The parent docstring quote style should be set when formatting a code + /// snippet within the docstring. The quote style should correspond to the + /// style of quotes used by said docstring. Normalization will ensure the + /// quoting styles don't conflict. fn normalize<'a>( self, quoting: Quoting, locator: &'a Locator, configured_style: QuoteStyle, + parent_docstring_quote_style: Option, ) -> NormalizedString<'a> { - // Per PEP 8 and PEP 257, always prefer double quotes for docstrings and triple-quoted - // strings. (We assume docstrings are always triple-quoted.) + // Per PEP 8 and PEP 257, always prefer double quotes for docstrings + // and triple-quoted strings. (We assume docstrings are always + // triple-quoted.) let preferred_style = if self.quotes.triple { - QuoteStyle::Double + // ... unless we're formatting a code snippet inside a docstring, + // then we specifically want to invert our quote style to avoid + // writing out invalid Python. + // + // It's worth pointing out that we can actually wind up being + // somewhat out of sync with PEP8 in this case. Consider this + // example: + // + // def foo(): + // ''' + // Something. + // + // >>> """tricksy""" + // ''' + // pass + // + // Ideally, this would be reformatted as: + // + // def foo(): + // """ + // Something. + // + // >>> '''tricksy''' + // """ + // pass + // + // But the logic here results in the original quoting being + // preserved. This is because the quoting style of the outer + // docstring is determined, in part, by looking at its contents. In + // this case, it notices that it contains a `"""` and thus infers + // that using `'''` would overall read better because it avoids + // the need to escape the interior `"""`. Except... in this case, + // the `"""` is actually part of a code snippet that could get + // reformatted to using a different quoting style itself. + // + // Fixing this would, I believe, require some fairly seismic + // changes to how formatting strings works. Namely, we would need + // to look for code snippets before normalizing the docstring, and + // then figure out the quoting style more holistically by looking + // at the various kinds of quotes used in the code snippets and + // what reformatting them might look like. + // + // Overall this is a bit of a corner case and just inverting the + // style from what the parent ultimately decided upon works, even + // if it doesn't have perfect alignment with PEP8. + if let Some(style) = parent_docstring_quote_style { + style.invert() + } else { + QuoteStyle::Double + } } else { configured_style }; @@ -924,7 +989,7 @@ fn format_docstring(normalized: &NormalizedString, f: &mut PyFormatter) -> Forma // align it with the docstring statement. Conversely, if all lines are over-indented, we strip // the extra indentation. We call this stripped indentation since it's relative to the block // indent printer-made indentation. - let stripped_indentation = lines + let stripped_indentation_length = lines .clone() // We don't want to count whitespace-only lines as miss-indented .filter(|line| !line.trim().is_empty()) @@ -932,19 +997,15 @@ fn format_docstring(normalized: &NormalizedString, f: &mut PyFormatter) -> Forma .min() .unwrap_or_default(); - while let Some(line) = lines.next() { - let is_last = lines.peek().is_none(); - format_docstring_line( - line, - is_last, - offset, - stripped_indentation, - already_normalized, - f, - )?; - // We know that the normalized string has \n line endings - offset += line.text_len() + "\n".text_len(); + DocstringLinePrinter { + f, + offset, + stripped_indentation_length, + already_normalized, + quote_style: normalized.quotes.style, + code_example: CodeExample::default(), } + .add_iter(lines)?; // Same special case in the last line as for the first line let trim_end = docstring @@ -957,74 +1018,537 @@ fn format_docstring(normalized: &NormalizedString, f: &mut PyFormatter) -> Forma write!(f, [source_position(normalized.end()), normalized.quotes]) } -/// If the last line of the docstring is `content" """` or `content\ """`, we need a chaperone space -/// that avoids `content""""` and `content\"""`. This does only applies to un-escaped backslashes, -/// so `content\\ """` doesn't need a space while `content\\\ """` does. -fn needs_chaperone_space(normalized: &NormalizedString, trim_end: &str) -> bool { - trim_end.ends_with(normalized.quotes.style.as_char()) - || trim_end.chars().rev().take_while(|c| *c == '\\').count() % 2 == 1 -} - -/// Format a docstring line that is not the first line -fn format_docstring_line( - line: &str, - is_last: bool, +/// An abstraction for printing each line of a docstring. +struct DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { + f: &'fmt mut PyFormatter<'ast, 'buf>, + /// The source offset of the beginning of the line that is currently being + /// printed. offset: TextSize, + /// Indentation alignment based on the least indented line in the + /// docstring. stripped_indentation_length: TextSize, + /// Whether the docstring is overall already considered normalized. When it + /// is, the formatter can take a fast path. already_normalized: bool, - f: &mut PyFormatter, -) -> FormatResult<()> { - let trim_end = line.trim_end(); - if trim_end.is_empty() { - return if is_last { - // If the doc string ends with ` """`, the last line is ` `, but we don't want to - // insert an empty line (but close the docstring) - Ok(()) + /// The quote style used by the docstring being printed. + quote_style: QuoteStyle, + /// The current code example detected in the docstring. + code_example: CodeExample<'src>, +} + +impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { + /// Print all of the lines in the given iterator to this + /// printer's formatter. + /// + /// Note that callers may treat the first line specially, such that the + /// iterator given contains all lines except for the first. + fn add_iter( + &mut self, + mut lines: std::iter::Peekable>, + ) -> FormatResult<()> { + while let Some(line) = lines.next() { + let line = DocstringLine { + line: Cow::Borrowed(line), + offset: self.offset, + is_last: lines.peek().is_none(), + }; + // We know that the normalized string has \n line endings. + self.offset += line.line.text_len() + "\n".text_len(); + self.add_one(line)?; + } + Ok(()) + } + + /// Adds the given line to this printer. + /// + /// Depending on what's in the line, this may or may not print the line + /// immediately to the underlying buffer. If the line starts or is part + /// of an existing code snippet, then the lines will get buffered until + /// the code snippet is complete. + fn add_one(&mut self, line: DocstringLine<'src>) -> FormatResult<()> { + // Just pass through the line as-is without looking for a code snippet + // when docstring code formatting is disabled. And also when we are + // formatting a code snippet so as to avoid arbitrarily nested code + // snippet formatting. We avoid this because it's likely quite tricky + // to get right 100% of the time, although perhaps not impossible. It's + // not clear that it's worth the effort to support. + if !self.f.options().docstring_code().is_enabled() || self.f.context().docstring().is_some() + { + return self.print_one(&line); + } + match self.code_example.add(line) { + CodeExampleAddAction::Print { original } => self.print_one(&original)?, + CodeExampleAddAction::Kept => {} + CodeExampleAddAction::Format { + kind, + code, + original, + } => { + let Some(formatted_lines) = self.format(&code)? else { + // If formatting failed in a way that should not be + // allowed, we back out what we're doing and print the + // original lines we found as-is as if we did nothing. + for codeline in code { + self.print_one(&codeline.original)?; + } + if let Some(original) = original { + self.print_one(&original)?; + } + return Ok(()); + }; + + self.already_normalized = false; + match kind { + CodeExampleKind::Doctest(CodeExampleDoctest { indent }) => { + let mut lines = formatted_lines.into_iter(); + if let Some(first) = lines.next() { + self.print_one(&first.map(|line| std::format!("{indent}>>> {line}")))?; + for docline in lines { + self.print_one( + &docline.map(|line| std::format!("{indent}... {line}")), + )?; + } + } + } + } + if let Some(original) = original { + self.print_one(&original)?; + } + } + } + Ok(()) + } + + /// Prints the single line given. + /// + /// This mostly just handles indentation and ensuring line breaks are + /// inserted as appropriate before passing it on to the formatter to + /// print to the buffer. + fn print_one(&mut self, line: &DocstringLine<'_>) -> FormatResult<()> { + let trim_end = line.line.trim_end(); + if trim_end.is_empty() { + return if line.is_last { + // If the doc string ends with ` """`, the last line is + // ` `, but we don't want to insert an empty line (but close + // the docstring). + Ok(()) + } else { + empty_line().fmt(self.f) + }; + } + + let tab_or_non_ascii_space = trim_end + .chars() + .take_while(|c| c.is_whitespace()) + .any(|c| c != ' '); + + if tab_or_non_ascii_space { + // We strip the indentation that is shared with the docstring + // statement, unless a line was indented less than the docstring + // statement, in which case we strip only this much indentation to + // implicitly pad all lines by the difference, or all lines were + // overindented, in which case we strip the additional whitespace + // (see example in [`format_docstring`] doc comment). We then + // prepend the in-docstring indentation to the string. + let indent_len = indentation_length(trim_end) - self.stripped_indentation_length; + let in_docstring_indent = " ".repeat(usize::from(indent_len)) + trim_end.trim_start(); + text(&in_docstring_indent, Some(line.offset)).fmt(self.f)?; } else { - empty_line().fmt(f) + // Take the string with the trailing whitespace removed, then also + // skip the leading whitespace. + let trimmed_line_range = TextRange::at(line.offset, trim_end.text_len()) + .add_start(self.stripped_indentation_length); + if self.already_normalized { + source_text_slice(trimmed_line_range).fmt(self.f)?; + } else { + // All indents are ascii spaces, so the slicing is correct. + text( + &trim_end[usize::from(self.stripped_indentation_length)..], + Some(trimmed_line_range.start()), + ) + .fmt(self.f)?; + } + } + + // We handled the case that the closing quotes are on their own line + // above (the last line is empty except for whitespace). If they are on + // the same line as content, we don't insert a line break. + if !line.is_last { + hard_line_break().fmt(self.f)?; + } + + Ok(()) + } + + /// Given a sequence of lines from a code snippet, format them and return + /// the formatted code as a sequence of owned docstring lines. + /// + /// This routine generally only returns an error when the recursive call + /// to the formatter itself returns a `FormatError`. In all other cases + /// (for example, if the code snippet is invalid Python or even if the + /// resulting reformatted code snippet is invalid Python), then `Ok(None)` + /// is returned. In this case, callers should assume that a reformatted + /// code snippet is unavailable and bail out of trying to format it. + /// + /// Currently, when the above cases happen and `Ok(None)` is returned, the + /// routine is silent about it. So from the user's perspective, this will + /// fail silently. Ideally, this would at least emit a warning message, + /// but at time of writing, it wasn't clear to me how to best do that. + fn format( + &mut self, + code: &[CodeExampleLine<'src>], + ) -> FormatResult>>> { + use ruff_python_parser::AsMode; + + let offset = code + .get(0) + .expect("code blob must be non-empty") + .original + .offset; + let last_line_is_last = code + .last() + .expect("code blob must be non-empty") + .original + .is_last; + let codeblob = code + .iter() + .map(|line| &*line.code) + .collect::>() + .join("\n"); + let printed = match docstring_format_source(self.f.options(), self.quote_style, &codeblob) { + Ok(printed) => printed, + Err(FormatModuleError::FormatError(err)) => return Err(err), + Err( + FormatModuleError::LexError(_) + | FormatModuleError::ParseError(_) + | FormatModuleError::PrintError(_), + ) => { + return Ok(None); + } + }; + // This is a little hokey, but we want to determine whether the + // reformatted code snippet will lead to an overall invalid docstring. + // So attempt to parse it as Python code, but ensure it is wrapped + // within a docstring using the same quotes as the docstring we're in + // right now. + // + // This is an unfortunate stop-gap to attempt to prevent us from + // writing invalid Python due to some oddity of the code snippet within + // a docstring. As we fix corner cases over time, we can perhaps + // remove this check. See the `doctest_invalid_skipped` tests in + // `docstring_code_examples.py` for when this check is relevant. + let wrapped = match self.quote_style { + QuoteStyle::Single => std::format!("'''{}'''", printed.as_code()), + QuoteStyle::Double => std::format!(r#""""{}""""#, printed.as_code()), }; + let result = ruff_python_parser::parse( + &wrapped, + self.f.options().source_type().as_mode(), + "", + ); + // If the resulting code is not valid, then reset and pass through + // the docstring lines as-is. + if result.is_err() { + return Ok(None); + } + let mut lines = printed + .as_code() + .lines() + .map(|line| DocstringLine { + line: Cow::Owned(line.into()), + offset, + is_last: false, + }) + .collect::>(); + if let Some(last) = lines.last_mut() { + last.is_last = last_line_is_last; + } + Ok(Some(lines)) } +} - let tab_or_non_ascii_space = trim_end - .chars() - .take_while(|c| c.is_whitespace()) - .any(|c| c != ' '); - - if tab_or_non_ascii_space { - // We strip the indentation that is shared with the docstring statement, unless a line - // was indented less than the docstring statement, in which we strip only this much - // indentation to implicitly pad all lines by the difference, or all lines were - // overindented, in which case we strip the additional whitespace (see example in - // [`format_docstring`] doc comment). We then prepend the in-docstring indentation to the - // string. - let indent_len = indentation_length(trim_end) - stripped_indentation_length; - let in_docstring_indent = " ".repeat(usize::from(indent_len)) + trim_end.trim_start(); - text(&in_docstring_indent, Some(offset)).fmt(f)?; - } else { - // Take the string with the trailing whitespace removed, then also skip the leading - // whitespace - let trimmed_line_range = - TextRange::at(offset, trim_end.text_len()).add_start(stripped_indentation_length); - if already_normalized { - source_text_slice(trimmed_line_range).fmt(f)?; - } else { - // All indents are ascii spaces, so the slicing is correct - text( - &trim_end[usize::from(stripped_indentation_length)..], - Some(trimmed_line_range.start()), - ) - .fmt(f)?; +/// Represents a single line in a docstring. +/// +/// This type is used to both represent the original lines in a docstring +/// (the line will be borrowed) and also the newly formatted lines from code +/// snippets (the line will be owned). +#[derive(Clone, Debug)] +struct DocstringLine<'src> { + /// The actual text of the line, not including the line terminator. + line: Cow<'src, str>, + /// The offset into the source document which this line corresponds to. + offset: TextSize, + /// Whether this is the last line in a docstring or not. "Last" lines have + /// some special treatment when printing. + is_last: bool, +} + +impl<'src> DocstringLine<'src> { + /// Return this line, but with the given function applied to the text of + /// the line. + fn map(self, mut map: impl FnMut(&str) -> String) -> DocstringLine<'static> { + DocstringLine { + line: Cow::Owned(map(&self.line)), + ..self } } +} + +/// A single code example extracted from a docstring. +/// +/// This represents an intermediate state from when the code example was first +/// found all the way up until the point at which the code example has finished +/// and is reformatted. +/// +/// Its default state is "empty." That is, that no code example is currently +/// being collected. +#[derive(Debug, Default)] +struct CodeExample<'src> { + /// The kind of code example being collected, or `None` if no code example + /// has been observed. + kind: Option, + /// The lines that have been seen so far that make up the code example. + lines: Vec>, +} - // We handled the case that the closing quotes are on their own line above (the last line is - // empty except for whitespace). If they are on the same line as content, we don't insert a line - // break. - if !is_last { - hard_line_break().fmt(f)?; +impl<'src> CodeExample<'src> { + /// Attempt to add an original line from a docstring to this code example. + /// + /// Based on the line and the internal state of whether a code example is + /// currently being collected or not, this will return an "action" for + /// the caller to perform. The typical case is a "print" action, which + /// instructs the caller to just print the line as though it were not part + /// of a code snippet. + fn add(&mut self, original: DocstringLine<'src>) -> CodeExampleAddAction<'src> { + match self.kind.take() { + // There's no existing code example being built, so we look for + // the start of one or otherwise tell the caller we couldn't find + // anything. + None => match self.add_start(original) { + None => CodeExampleAddAction::Kept, + Some(original) => CodeExampleAddAction::Print { original }, + }, + Some(CodeExampleKind::Doctest(doctest)) => { + if let Some(code) = doctest_find_ps2_prompt(&doctest.indent, &original.line) { + let code = code.to_string(); + self.lines.push(CodeExampleLine { original, code }); + // Stay with the doctest kind while we accumulate all + // PS2 prompts. + self.kind = Some(CodeExampleKind::Doctest(doctest)); + return CodeExampleAddAction::Kept; + } + let code = std::mem::take(&mut self.lines); + let original = self.add_start(original); + CodeExampleAddAction::Format { + code, + kind: CodeExampleKind::Doctest(doctest), + original, + } + } + } + } + + /// Looks for the start of a code example. If one was found, then the given + /// line is kept and added as part of the code example. Otherwise, the line + /// is returned unchanged and no code example was found. + /// + /// # Panics + /// + /// This panics when the existing code-example is any non-None value. That + /// is, this routine assumes that there is no ongoing code example being + /// collected and looks for the beginning of another code example. + fn add_start(&mut self, original: DocstringLine<'src>) -> Option> { + assert_eq!(None, self.kind, "expected no existing code example"); + if let Some((indent, code)) = doctest_find_ps1_prompt(&original.line) { + let indent = indent.to_string(); + let code = code.to_string(); + self.lines.push(CodeExampleLine { original, code }); + self.kind = Some(CodeExampleKind::Doctest(CodeExampleDoctest { indent })); + return None; + } + Some(original) } +} + +/// The kind of code example observed in a docstring. +#[derive(Clone, Debug, Eq, PartialEq)] +enum CodeExampleKind { + /// Code found in Python "doctests." + /// + /// Documentation describing doctests and how they're recognized can be + /// found as part of the Python standard library: + /// https://docs.python.org/3/library/doctest.html. + /// + /// (You'll likely need to read the regex matching used internally by the + /// doctest module to determine more precisely how it works.) + Doctest(CodeExampleDoctest), +} + +/// State corresponding to a single doctest code example found in a docstring. +#[derive(Clone, Debug, Eq, PartialEq)] +struct CodeExampleDoctest { + /// The indent observed in the first doctest line. + /// + /// More precisely, this corresponds to the whitespace observed before + /// the starting `>>> ` (the "PS1 prompt"). + indent: String, +} - Ok(()) +/// A single line in a code example found in a docstring. +/// +/// A code example line exists prior to formatting, and is thus in full +/// correspondence with the original lines from the docstring. Indeed, a +/// code example line includes both the original line *and* the actual code +/// extracted from the line. For example, if a line in a docstring is `>>> +/// foo(x)`, then the original line is `>>> foo(x)` and the code portion is +/// `foo(x)`. +/// +/// The original line is kept for things like offset information, but also +/// because it may still be needed if it turns out that the code snippet is +/// not valid or otherwise could not be formatted. In which case, the original +/// lines are printed as-is. +#[derive(Debug)] +struct CodeExampleLine<'src> { + /// The normalized (but original) line from the doc string. This might, for + /// example, contain a `>>> ` or `... ` prefix if this code example is a + /// doctest. + original: DocstringLine<'src>, + /// The code extracted from the line. + code: String, +} + +/// An action that a caller should perform after attempting to add a line from +/// a docstring to a code example. +/// +/// Callers are expected to add every line from a docstring to a code example, +/// and the state of the code example (and the line itself) will determine +/// how the caller should react. +#[derive(Debug)] +enum CodeExampleAddAction<'src> { + /// The line added was ignored by `CodeExample` and the caller should print + /// it to the formatter as-is. + /// + /// This is the common case. That is, most lines in most docstrings are not + /// part of a code example. + Print { original: DocstringLine<'src> }, + /// The line added was kept by `CodeExample` as part of a new or existing + /// code example. + /// + /// When this occurs, callers should not try to format the line and instead + /// move on to the next line. + Kept, + /// The line added indicated that the code example is finished and should + /// be formatted and printed. The line added is not treated as part of + /// the code example. If the line added indicated the start of another + /// code example, then is won't be returned to the caller here. Otherwise, + /// callers should pass it through to the formatter as-is. + Format { + /// The kind of code example that was found. + kind: CodeExampleKind, + /// The Python code that should be formatted, indented and printed. + /// + /// This is guaranteed to be non-empty. + code: Vec>, + /// When set, the line is considered not part of any code example + /// and should be formatted as if the `Ignore` action were returned. + /// Otherwise, if there is no line, then either one does not exist + /// or it is part of another code example and should be treated as a + /// `Kept` action. + original: Option>, + }, +} + +/// Looks for a valid doctest PS1 prompt in the line given. +/// +/// If one was found, then the indentation prior to the prompt is returned +/// along with the code portion of the line. +fn doctest_find_ps1_prompt(line: &str) -> Option<(&str, &str)> { + let trim_start = line.trim_start(); + // Prompts must be followed by an ASCII space character[1]. + // + // [1]: https://github.com/python/cpython/blob/0ff6368519ed7542ad8b443de01108690102420a/Lib/doctest.py#L809-L812 + let code = trim_start.strip_prefix(">>> ")?; + let indent_len = line + .len() + .checked_sub(trim_start.len()) + .expect("suffix is <= original"); + let indent = &line[..indent_len]; + Some((indent, code)) +} + +/// Looks for a valid doctest PS2 prompt in the line given. +/// +/// If one is found, then the code portion of the line following the PS2 prompt +/// is returned. +/// +/// Callers must provide a string containing the original indentation of the +/// PS1 prompt that started the doctest containing the potential PS2 prompt +/// in the line given. If the line contains a PS2 prompt, its indentation must +/// match the indentation used for the corresponding PS1 prompt (otherwise +/// `None` will be returned). +fn doctest_find_ps2_prompt<'src>(ps1_indent: &str, line: &'src str) -> Option<&'src str> { + let (ps2_indent, ps2_after) = line.split_once("...")?; + // PS2 prompts must have the same indentation as their + // corresponding PS1 prompt.[1] While the 'doctest' Python + // module will error in this case, we just treat this line as a + // non-doctest line. + // + // [1]: https://github.com/python/cpython/blob/0ff6368519ed7542ad8b443de01108690102420a/Lib/doctest.py#L733 + if ps1_indent != ps2_indent { + return None; + } + // PS2 prompts must be followed by an ASCII space character unless + // it's an otherwise empty line[1]. + // + // [1]: https://github.com/python/cpython/blob/0ff6368519ed7542ad8b443de01108690102420a/Lib/doctest.py#L809-L812 + match ps2_after.strip_prefix(' ') { + None if ps2_after.is_empty() => Some(""), + None => None, + Some(code) => Some(code), + } +} + +/// Formats the given source code using the given options. +/// +/// The given quote style should correspond to the style used by the docstring +/// containing the code snippet being formatted. The formatter will use this +/// information to invert the quote style of any such strings contained within +/// the code snippet in order to avoid writing invalid Python code. +/// +/// This is similar to the top-level formatting entrypoint, except this +/// explicitly sets the context to indicate that formatting is taking place +/// inside of a docstring. +fn docstring_format_source( + options: &crate::PyFormatOptions, + docstring_quote_style: QuoteStyle, + source: &str, +) -> Result { + use ruff_python_parser::AsMode; + + let source_type = options.source_type(); + let (tokens, comment_ranges) = ruff_python_index::tokens_and_ranges(source, source_type)?; + let module = + ruff_python_parser::parse_ok_tokens(tokens, source, source_type.as_mode(), "")?; + let source_code = ruff_formatter::SourceCode::new(source); + let comments = crate::Comments::from_ast(&module, source_code, &comment_ranges); + let locator = Locator::new(source); + + let ctx = PyFormatContext::new(options.clone(), locator.contents(), comments) + .in_docstring(docstring_quote_style); + let formatted = crate::format!(ctx, [module.format()])?; + formatted + .context() + .comments() + .assert_all_formatted(source_code); + Ok(formatted.print()?) +} + +/// If the last line of the docstring is `content" """` or `content\ """`, we need a chaperone space +/// that avoids `content""""` and `content\"""`. This does only applies to un-escaped backslashes, +/// so `content\\ """` doesn't need a space while `content\\\ """` does. +fn needs_chaperone_space(normalized: &NormalizedString, trim_end: &str) -> bool { + trim_end.ends_with(normalized.quotes.style.as_char()) + || trim_end.chars().rev().take_while(|c| *c == '\\').count() % 2 == 1 } #[cfg(test)] diff --git a/crates/ruff_python_formatter/src/lib.rs b/crates/ruff_python_formatter/src/lib.rs index d85806e3dfc63..e9a3c34757da9 100644 --- a/crates/ruff_python_formatter/src/lib.rs +++ b/crates/ruff_python_formatter/src/lib.rs @@ -15,7 +15,9 @@ use crate::comments::{ dangling_comments, leading_comments, trailing_comments, Comments, SourceComment, }; pub use crate::context::PyFormatContext; -pub use crate::options::{MagicTrailingComma, PreviewMode, PyFormatOptions, QuoteStyle}; +pub use crate::options::{ + DocstringCode, MagicTrailingComma, PreviewMode, PyFormatOptions, QuoteStyle, +}; pub use crate::shared_traits::{AsFormat, FormattedIter, FormattedIterExt, IntoFormat}; use crate::verbatim::suppressed_node; diff --git a/crates/ruff_python_formatter/src/options.rs b/crates/ruff_python_formatter/src/options.rs index b39c7b6ff79c6..261dfeab190ff 100644 --- a/crates/ruff_python_formatter/src/options.rs +++ b/crates/ruff_python_formatter/src/options.rs @@ -43,6 +43,12 @@ pub struct PyFormatOptions { /// in the formatted document. source_map_generation: SourceMapGeneration, + /// Whether to format code snippets in docstrings or not. + /// + /// By default this is disabled (opt-in), but the plan is to make this + /// enabled by default (opt-out) in the future. + docstring_code: DocstringCode, + /// Whether preview style formatting is enabled or not preview: PreviewMode, } @@ -70,6 +76,7 @@ impl Default for PyFormatOptions { line_ending: LineEnding::default(), magic_trailing_comma: MagicTrailingComma::default(), source_map_generation: SourceMapGeneration::default(), + docstring_code: DocstringCode::default(), preview: PreviewMode::default(), } } @@ -108,6 +115,10 @@ impl PyFormatOptions { self.line_ending } + pub fn docstring_code(&self) -> DocstringCode { + self.docstring_code + } + pub fn preview(&self) -> PreviewMode { self.preview } @@ -148,6 +159,12 @@ impl PyFormatOptions { self } + #[must_use] + pub fn with_docstring_code(mut self, docstring_code: DocstringCode) -> Self { + self.docstring_code = docstring_code; + self + } + #[must_use] pub fn with_preview(mut self, preview: PreviewMode) -> Self { self.preview = preview; @@ -284,3 +301,20 @@ impl PreviewMode { matches!(self, PreviewMode::Enabled) } } + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, CacheKey)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +pub enum DocstringCode { + #[default] + Disabled, + + Enabled, +} + +impl DocstringCode { + pub const fn is_enabled(self) -> bool { + matches!(self, DocstringCode::Enabled) + } +} diff --git a/crates/ruff_python_formatter/tests/fixtures.rs b/crates/ruff_python_formatter/tests/fixtures.rs index c3fd2b20707e8..1b949c7b73d0b 100644 --- a/crates/ruff_python_formatter/tests/fixtures.rs +++ b/crates/ruff_python_formatter/tests/fixtures.rs @@ -41,7 +41,7 @@ fn black_compatibility() { let formatted_code = printed.as_code(); ensure_unchanged_ast(&content, formatted_code, &options, input_path); - ensure_stability_when_formatting_twice(formatted_code, options, input_path); + ensure_stability_when_formatting_twice(formatted_code, &options, input_path); if formatted_code == expected_output { // Black and Ruff formatting matches. Delete any existing snapshot files because the Black output @@ -120,7 +120,7 @@ fn format() { let formatted_code = printed.as_code(); ensure_unchanged_ast(&content, formatted_code, &options, input_path); - ensure_stability_when_formatting_twice(formatted_code, options.clone(), input_path); + ensure_stability_when_formatting_twice(formatted_code, &options, input_path); let mut snapshot = format!("## Input\n{}", CodeFrame::new("python", &content)); @@ -138,7 +138,7 @@ fn format() { let formatted_code = printed.as_code(); ensure_unchanged_ast(&content, formatted_code, &options, input_path); - ensure_stability_when_formatting_twice(formatted_code, options.clone(), input_path); + ensure_stability_when_formatting_twice(formatted_code, &options, input_path); writeln!( snapshot, @@ -157,7 +157,7 @@ fn format() { let formatted_preview = printed_preview.as_code(); ensure_unchanged_ast(&content, formatted_preview, &options_preview, input_path); - ensure_stability_when_formatting_twice(formatted_preview, options_preview, input_path); + ensure_stability_when_formatting_twice(formatted_preview, &options_preview, input_path); if formatted_code == formatted_preview { writeln!( @@ -203,10 +203,10 @@ fn format() { /// Format another time and make sure that there are no changes anymore fn ensure_stability_when_formatting_twice( formatted_code: &str, - options: PyFormatOptions, + options: &PyFormatOptions, input_path: &Path, ) { - let reformatted = match format_module_source(formatted_code, options) { + let reformatted = match format_module_source(formatted_code, options.clone()) { Ok(reformatted) => reformatted, Err(err) => { panic!( @@ -223,7 +223,10 @@ fn ensure_stability_when_formatting_twice( .header("Formatted once", "Formatted twice") .to_string(); panic!( - r#"Reformatting the formatted code of {} a second time resulted in formatting changes. + r#"Reformatting the formatted code of {input_path} a second time resulted in formatting changes. + +Options: +{options} --- {diff}--- @@ -233,9 +236,10 @@ Formatted once: Formatted twice: --- -{}---"#, - input_path.display(), - reformatted.as_code(), +{reformatted}---"#, + input_path = input_path.display(), + options = &DisplayPyOptions(options), + reformatted = reformatted.as_code(), ); } } @@ -338,13 +342,17 @@ impl fmt::Display for DisplayPyOptions<'_> { line-width = {line_width} indent-width = {indent_width} quote-style = {quote_style:?} +line-ending = {line_ending:?} magic-trailing-comma = {magic_trailing_comma:?} +docstring-code = {docstring_code:?} preview = {preview:?}"#, indent_style = self.0.indent_style(), indent_width = self.0.indent_width().value(), line_width = self.0.line_width().value(), quote_style = self.0.quote_style(), + line_ending = self.0.line_ending(), magic_trailing_comma = self.0.magic_trailing_comma(), + docstring_code = self.0.docstring_code(), preview = self.0.preview() ) } diff --git a/crates/ruff_python_formatter/tests/normalizer.rs b/crates/ruff_python_formatter/tests/normalizer.rs index 991c4206fb9c2..d6f6454ed397a 100644 --- a/crates/ruff_python_formatter/tests/normalizer.rs +++ b/crates/ruff_python_formatter/tests/normalizer.rs @@ -1,4 +1,8 @@ -use itertools::Either::{Left, Right}; +use { + itertools::Either::{Left, Right}, + once_cell::sync::Lazy, + regex::Regex, +}; use ruff_python_ast::visitor::transformer; use ruff_python_ast::visitor::transformer::Transformer; @@ -12,6 +16,10 @@ use ruff_python_ast::{self as ast, Expr, Stmt}; /// between `class C: ...` and `class C(): ...`, which is part of our AST but not `CPython`'s. /// - Normalize strings. The formatter can re-indent docstrings, so we need to compare string /// contents ignoring whitespace. (Black does the same.) +/// - The formatter can also reformat code snippets when they're Python code, which can of +/// course change the string in arbitrary ways. Black itself does not reformat code snippets, +/// so we carve our own path here by stripping everything that looks like code snippets from +/// string literals. /// - Ignores nested tuples in deletions. (Black does the same.) pub(crate) struct Normalizer; @@ -52,8 +60,28 @@ impl Transformer for Normalizer { } fn visit_string_literal(&self, string_literal: &mut ast::StringLiteral) { - // Normalize a string by (1) stripping any leading and trailing space from each - // line, and (2) removing any blank lines from the start and end of the string. + static STRIP_CODE_SNIPPETS: Lazy = Lazy::new(|| { + Regex::new( + r#"(?mx) + # strip doctest PS1 prompt lines + ^\s*>>>\s.*(\n|$) + | + # strip doctest PS2 prompt lines + # Also handles the case of an empty ... line. + ^\s*\.\.\.((\n|$)|\s.*(\n|$)) + "#, + ) + .unwrap() + }); + + // Start by (1) stripping everything that looks like a code + // snippet, since code snippets may be completely reformatted if + // they are Python code. + string_literal.value = STRIP_CODE_SNIPPETS + .replace_all(&string_literal.value, "") + .into_owned(); + // Normalize a string by (2) stripping any leading and trailing space from each + // line, and (3) removing any blank lines from the start and end of the string. string_literal.value = string_literal .value .lines() diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap index 4e92b7c09db29..bac8a446b18a1 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap @@ -165,7 +165,9 @@ indent-style = space line-width = 88 indent-width = 4 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` @@ -331,7 +333,9 @@ indent-style = space line-width = 88 indent-width = 2 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` @@ -497,7 +501,9 @@ indent-style = tab line-width = 88 indent-width = 8 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` @@ -663,7 +669,9 @@ indent-style = tab line-width = 88 indent-width = 4 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap new file mode 100644 index 0000000000000..3a83075f29975 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap @@ -0,0 +1,3006 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py +--- +## Input +```python +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + >>> cool_stuff( y ) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + """ + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... + ... print( x ) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested( x ): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + ''' + Do cool stuff. + + >>> assert ("Easy!") + >>> import math + >>> math.floor( 1.9 ) + 1 + ''' + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + ''' + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) + ''' + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( x ) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass +``` + +## Outputs +### Output 1 +``` +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +preview = Disabled +``` + +```python +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + >>> cool_stuff( y ) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + """ + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... + ... print( x ) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested( x ): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert ("Easy!") + >>> import math + >>> math.floor( 1.9 ) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( x ) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass +``` + + +### Output 2 +``` +indent-style = space +line-width = 88 +indent-width = 2 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +preview = Disabled +``` + +```python +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + >>> cool_stuff( y ) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + """ + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... + ... print( x ) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested( x ): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert ("Easy!") + >>> import math + >>> math.floor( 1.9 ) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( x ) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass +``` + + +### Output 3 +``` +indent-style = tab +line-width = 88 +indent-width = 8 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +preview = Disabled +``` + +```python +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + >>> cool_stuff( y ) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + """ + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... + ... print( x ) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested( x ): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert ("Easy!") + >>> import math + >>> math.floor( 1.9 ) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( x ) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass +``` + + +### Output 4 +``` +indent-style = tab +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +preview = Disabled +``` + +```python +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + >>> cool_stuff( y ) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + """ + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... + ... print( x ) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested( x ): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert ("Easy!") + >>> import math + >>> math.floor( 1.9 ) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( x ) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass +``` + + +### Output 5 +``` +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +preview = Disabled +``` + +```python +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff(1) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(f"hi {x}") + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff(x) + >>> cool_stuff(y) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff(x) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(f"hi {x}") + """ + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... + ... print(x) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print(x) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print(x) + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested(x): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard + ... ) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass +``` + + +### Output 6 +``` +indent-style = space +line-width = 88 +indent-width = 2 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +preview = Disabled +``` + +```python +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff(1) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(f"hi {x}") + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff(x) + >>> cool_stuff(y) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff(x) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(f"hi {x}") + """ + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... + ... print(x) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print(x) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print(x) + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested(x): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard + ... ) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass +``` + + +### Output 7 +``` +indent-style = tab +line-width = 88 +indent-width = 8 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +preview = Disabled +``` + +```python +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff(1) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(f"hi {x}") + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff(x) + >>> cool_stuff(y) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff(x) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(f"hi {x}") + """ + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... + ... print(x) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print(x) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print(x) + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested(x): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard + ... ) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass +``` + + +### Output 8 +``` +indent-style = tab +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +preview = Disabled +``` + +```python +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff(1) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(f"hi {x}") + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff(x) + >>> cool_stuff(y) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff(x) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(f"hi {x}") + """ + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... + ... print(x) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print(x) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print(x) + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested(x): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard + ... ) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass +``` + + + diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap new file mode 100644 index 0000000000000..7391fb69387a6 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap @@ -0,0 +1,44 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_crlf.py +--- +## Input +```python +def doctest_line_ending(): + """ + Do cool stuff. + >>> def foo( x ): + ... print( x ) + ... + ... print( x ) + """ + pass +``` + +## Outputs +### Output 1 +``` +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = CarriageReturnLineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +preview = Disabled +``` + +```python +def doctest_line_ending(): + """ + Do cool stuff. + >>> def foo(x): + ... print(x) + ... + ... print(x) + """ + pass +``` + + + diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap index 1e8baabd73238..ba906f5a34567 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap @@ -133,7 +133,9 @@ indent-style = space line-width = 88 indent-width = 4 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` @@ -282,7 +284,9 @@ indent-style = space line-width = 88 indent-width = 4 quote-style = Single +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap index 09830dae06dfa..af7a9ecb62130 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap @@ -148,7 +148,9 @@ indent-style = space line-width = 88 indent-width = 4 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` @@ -321,7 +323,9 @@ indent-style = space line-width = 88 indent-width = 4 quote-style = Single +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap index 8cca1bee8815a..cd2da8896be2c 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap @@ -32,7 +32,9 @@ indent-style = space line-width = 88 indent-width = 4 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` @@ -65,7 +67,9 @@ indent-style = space line-width = 88 indent-width = 2 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap index 87873bcc8a203..12a58faa13871 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap @@ -13,7 +13,9 @@ indent-style = space line-width = 88 indent-width = 4 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` @@ -27,7 +29,9 @@ indent-style = space line-width = 88 indent-width = 1 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` @@ -41,7 +45,9 @@ indent-style = tab line-width = 88 indent-width = 4 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap index 619cb49876d8d..54e970077c352 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap @@ -28,7 +28,9 @@ indent-style = space line-width = 88 indent-width = 4 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` @@ -58,7 +60,9 @@ indent-style = space line-width = 88 indent-width = 2 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` @@ -88,7 +92,9 @@ indent-style = tab line-width = 88 indent-width = 4 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap index f7167deef5e09..c3504c47f856c 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap @@ -79,7 +79,9 @@ indent-style = space line-width = 88 indent-width = 4 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` @@ -158,7 +160,9 @@ indent-style = space line-width = 88 indent-width = 4 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Enabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap index 1434f6a964a93..4add8537b1d2c 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap @@ -46,7 +46,9 @@ indent-style = space line-width = 88 indent-width = 4 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` @@ -99,7 +101,9 @@ indent-style = space line-width = 88 indent-width = 4 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Ignore +docstring-code = Disabled preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap index 2ff5d8afde9b6..d57334c7caf6e 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap @@ -21,7 +21,9 @@ indent-style = space line-width = 88 indent-width = 2 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` @@ -43,7 +45,9 @@ indent-style = space line-width = 88 indent-width = 4 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` @@ -68,7 +72,9 @@ indent-style = space line-width = 88 indent-width = 8 quote-style = Double +line-ending = LineFeed magic-trailing-comma = Respect +docstring-code = Disabled preview = Disabled ``` From 33caa2ab1c62348cfa47a22e6df05f6627b7d4af Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Mon, 27 Nov 2023 13:32:26 -0500 Subject: [PATCH 043/197] ruff_python_formatter: move docstring handling to a submodule (#8861) This turns `string` into a parent module with a `docstring` sub-module. I arranged things this way because there are parts of the `string` module that the `docstring` module wants to know about (such as a `NormalizedString`). The alternative I think would be to make `docstring` a sibling module and expose more of `string`'s internals. I think I overall like this change because it gives docstring handling a bit more room to breath. It has grown quite a bit with the addition of code snippet formatting. [This was suggested by @charliermarsh.](https://github.com/astral-sh/ruff/pull/8811#discussion_r1401169531) --- .../{string.rs => string/docstring.rs} | 854 +----------------- .../src/expression/string/mod.rs | 811 +++++++++++++++++ 2 files changed, 839 insertions(+), 826 deletions(-) rename crates/ruff_python_formatter/src/expression/{string.rs => string/docstring.rs} (52%) create mode 100644 crates/ruff_python_formatter/src/expression/string/mod.rs diff --git a/crates/ruff_python_formatter/src/expression/string.rs b/crates/ruff_python_formatter/src/expression/string/docstring.rs similarity index 52% rename from crates/ruff_python_formatter/src/expression/string.rs rename to crates/ruff_python_formatter/src/expression/string/docstring.rs index 2c711ac60ef1f..8f1f335218f6d 100644 --- a/crates/ruff_python_formatter/src/expression/string.rs +++ b/crates/ruff_python_formatter/src/expression/string/docstring.rs @@ -1,832 +1,14 @@ use std::borrow::Cow; -use bitflags::bitflags; - -use ruff_formatter::{format_args, write, Printed}; -use ruff_python_ast::AnyNodeRef; -use ruff_python_ast::{ - self as ast, ExprBytesLiteral, ExprFString, ExprStringLiteral, ExpressionRef, -}; -use ruff_source_file::Locator; -use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; - -use crate::comments::{leading_comments, trailing_comments}; -use crate::expression::parentheses::{ - in_parentheses_only_group, in_parentheses_only_soft_line_break_or_space, +use { + ruff_formatter::{write, Printed}, + ruff_source_file::Locator, + ruff_text_size::{Ranged, TextLen, TextRange, TextSize}, }; -use crate::expression::Expr; -use crate::prelude::*; -use crate::FormatModuleError; -use crate::QuoteStyle; - -#[derive(Copy, Clone, Debug)] -enum Quoting { - CanChange, - Preserve, -} - -#[derive(Clone, Debug)] -pub(super) enum AnyString<'a> { - String(&'a ExprStringLiteral), - Bytes(&'a ExprBytesLiteral), - FString(&'a ExprFString), -} - -impl<'a> AnyString<'a> { - pub(crate) fn from_expression(expression: &'a Expr) -> Option> { - match expression { - Expr::StringLiteral(string) => Some(AnyString::String(string)), - Expr::BytesLiteral(bytes) => Some(AnyString::Bytes(bytes)), - Expr::FString(fstring) => Some(AnyString::FString(fstring)), - _ => None, - } - } - - fn quoting(&self, locator: &Locator) -> Quoting { - match self { - Self::String(_) | Self::Bytes(_) => Quoting::CanChange, - Self::FString(f_string) => { - let unprefixed = locator - .slice(f_string.range) - .trim_start_matches(|c| c != '"' && c != '\''); - let triple_quoted = - unprefixed.starts_with(r#"""""#) || unprefixed.starts_with(r"'''"); - if f_string.value.elements().any(|value| match value { - Expr::FormattedValue(ast::ExprFormattedValue { range, .. }) => { - let string_content = locator.slice(*range); - if triple_quoted { - string_content.contains(r#"""""#) || string_content.contains("'''") - } else { - string_content.contains(['"', '\'']) - } - } - _ => false, - }) { - Quoting::Preserve - } else { - Quoting::CanChange - } - } - } - } - - /// Returns `true` if the string is implicitly concatenated. - pub(super) fn is_implicit_concatenated(&self) -> bool { - match self { - Self::String(ExprStringLiteral { value, .. }) => value.is_implicit_concatenated(), - Self::Bytes(ExprBytesLiteral { value, .. }) => value.is_implicit_concatenated(), - Self::FString(ExprFString { value, .. }) => value.is_implicit_concatenated(), - } - } - - fn parts(&self) -> Vec> { - match self { - Self::String(ExprStringLiteral { value, .. }) => { - value.parts().map(AnyStringPart::String).collect() - } - Self::Bytes(ExprBytesLiteral { value, .. }) => { - value.parts().map(AnyStringPart::Bytes).collect() - } - Self::FString(ExprFString { value, .. }) => value - .parts() - .map(|f_string_part| match f_string_part { - ast::FStringPart::Literal(string_literal) => { - AnyStringPart::String(string_literal) - } - ast::FStringPart::FString(f_string) => AnyStringPart::FString(f_string), - }) - .collect(), - } - } -} - -impl Ranged for AnyString<'_> { - fn range(&self) -> TextRange { - match self { - Self::String(expr) => expr.range(), - Self::Bytes(expr) => expr.range(), - Self::FString(expr) => expr.range(), - } - } -} - -impl<'a> From<&AnyString<'a>> for AnyNodeRef<'a> { - fn from(value: &AnyString<'a>) -> Self { - match value { - AnyString::String(expr) => AnyNodeRef::ExprStringLiteral(expr), - AnyString::Bytes(expr) => AnyNodeRef::ExprBytesLiteral(expr), - AnyString::FString(expr) => AnyNodeRef::ExprFString(expr), - } - } -} - -impl<'a> From<&AnyString<'a>> for ExpressionRef<'a> { - fn from(value: &AnyString<'a>) -> Self { - match value { - AnyString::String(expr) => ExpressionRef::StringLiteral(expr), - AnyString::Bytes(expr) => ExpressionRef::BytesLiteral(expr), - AnyString::FString(expr) => ExpressionRef::FString(expr), - } - } -} - -#[derive(Clone, Debug)] -enum AnyStringPart<'a> { - String(&'a ast::StringLiteral), - Bytes(&'a ast::BytesLiteral), - FString(&'a ast::FString), -} - -impl<'a> From<&AnyStringPart<'a>> for AnyNodeRef<'a> { - fn from(value: &AnyStringPart<'a>) -> Self { - match value { - AnyStringPart::String(part) => AnyNodeRef::StringLiteral(part), - AnyStringPart::Bytes(part) => AnyNodeRef::BytesLiteral(part), - AnyStringPart::FString(part) => AnyNodeRef::FString(part), - } - } -} - -impl Ranged for AnyStringPart<'_> { - fn range(&self) -> TextRange { - match self { - Self::String(part) => part.range(), - Self::Bytes(part) => part.range(), - Self::FString(part) => part.range(), - } - } -} - -pub(super) struct FormatString<'a> { - string: &'a AnyString<'a>, - layout: StringLayout, -} - -#[derive(Default, Copy, Clone, Debug)] -pub enum StringLayout { - #[default] - Default, - DocString, - /// An implicit concatenated string in a binary like (e.g. `a + b` or `a < b`) expression. - /// - /// Formats the implicit concatenated string parts without the enclosing group because the group - /// is added by the binary like formatting. - ImplicitConcatenatedStringInBinaryLike, -} - -impl<'a> FormatString<'a> { - pub(super) fn new(string: &'a AnyString<'a>) -> Self { - Self { - string, - layout: StringLayout::Default, - } - } - - pub(super) fn with_layout(mut self, layout: StringLayout) -> Self { - self.layout = layout; - self - } -} - -impl<'a> Format> for FormatString<'a> { - fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { - let parent_docstring_quote_style = f.context().docstring(); - let locator = f.context().locator(); - let result = match self.layout { - StringLayout::Default => { - if self.string.is_implicit_concatenated() { - in_parentheses_only_group(&FormatStringContinuation::new(self.string)).fmt(f) - } else { - StringPart::from_source(self.string.range(), &locator) - .normalize( - self.string.quoting(&locator), - &locator, - f.options().quote_style(), - parent_docstring_quote_style, - ) - .fmt(f) - } - } - StringLayout::DocString => { - let string_part = StringPart::from_source(self.string.range(), &locator); - let normalized = string_part.normalize( - Quoting::CanChange, - &locator, - f.options().quote_style(), - parent_docstring_quote_style, - ); - format_docstring(&normalized, f) - } - StringLayout::ImplicitConcatenatedStringInBinaryLike => { - FormatStringContinuation::new(self.string).fmt(f) - } - }; - // TODO(dhruvmanila): With PEP 701, comments can be inside f-strings. - // This is to mark all of those comments as formatted but we need to - // figure out how to handle them. Note that this needs to be done only - // after the f-string is formatted, so only for all the non-formatted - // comments. - if let AnyString::FString(fstring) = self.string { - let comments = f.context().comments(); - fstring.value.elements().for_each(|value| { - comments.mark_verbatim_node_comments_formatted(value.into()); - }); - } - result - } -} - -struct FormatStringContinuation<'a> { - string: &'a AnyString<'a>, -} - -impl<'a> FormatStringContinuation<'a> { - fn new(string: &'a AnyString<'a>) -> Self { - Self { string } - } -} - -impl Format> for FormatStringContinuation<'_> { - fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { - let comments = f.context().comments().clone(); - let locator = f.context().locator(); - let in_docstring = f.context().docstring(); - let quote_style = f.options().quote_style(); - - let mut joiner = f.join_with(in_parentheses_only_soft_line_break_or_space()); - - for part in self.string.parts() { - let normalized = StringPart::from_source(part.range(), &locator).normalize( - self.string.quoting(&locator), - &locator, - quote_style, - in_docstring, - ); - - joiner.entry(&format_args![ - line_suffix_boundary(), - leading_comments(comments.leading(&part)), - normalized, - trailing_comments(comments.trailing(&part)) - ]); - } - - joiner.finish() - } -} - -#[derive(Debug)] -struct StringPart { - /// The prefix. - prefix: StringPrefix, - - /// The actual quotes of the string in the source - quotes: StringQuotes, - - /// The range of the string's content (full range minus quotes and prefix) - content_range: TextRange, -} - -impl StringPart { - fn from_source(range: TextRange, locator: &Locator) -> Self { - let string_content = locator.slice(range); - - let prefix = StringPrefix::parse(string_content); - let after_prefix = &string_content[usize::from(prefix.text_len())..]; - - let quotes = - StringQuotes::parse(after_prefix).expect("Didn't find string quotes after prefix"); - let relative_raw_content_range = TextRange::new( - prefix.text_len() + quotes.text_len(), - string_content.text_len() - quotes.text_len(), - ); - let raw_content_range = relative_raw_content_range + range.start(); - - Self { - prefix, - content_range: raw_content_range, - quotes, - } - } - - /// Computes the strings preferred quotes and normalizes its content. - /// - /// The parent docstring quote style should be set when formatting a code - /// snippet within the docstring. The quote style should correspond to the - /// style of quotes used by said docstring. Normalization will ensure the - /// quoting styles don't conflict. - fn normalize<'a>( - self, - quoting: Quoting, - locator: &'a Locator, - configured_style: QuoteStyle, - parent_docstring_quote_style: Option, - ) -> NormalizedString<'a> { - // Per PEP 8 and PEP 257, always prefer double quotes for docstrings - // and triple-quoted strings. (We assume docstrings are always - // triple-quoted.) - let preferred_style = if self.quotes.triple { - // ... unless we're formatting a code snippet inside a docstring, - // then we specifically want to invert our quote style to avoid - // writing out invalid Python. - // - // It's worth pointing out that we can actually wind up being - // somewhat out of sync with PEP8 in this case. Consider this - // example: - // - // def foo(): - // ''' - // Something. - // - // >>> """tricksy""" - // ''' - // pass - // - // Ideally, this would be reformatted as: - // - // def foo(): - // """ - // Something. - // - // >>> '''tricksy''' - // """ - // pass - // - // But the logic here results in the original quoting being - // preserved. This is because the quoting style of the outer - // docstring is determined, in part, by looking at its contents. In - // this case, it notices that it contains a `"""` and thus infers - // that using `'''` would overall read better because it avoids - // the need to escape the interior `"""`. Except... in this case, - // the `"""` is actually part of a code snippet that could get - // reformatted to using a different quoting style itself. - // - // Fixing this would, I believe, require some fairly seismic - // changes to how formatting strings works. Namely, we would need - // to look for code snippets before normalizing the docstring, and - // then figure out the quoting style more holistically by looking - // at the various kinds of quotes used in the code snippets and - // what reformatting them might look like. - // - // Overall this is a bit of a corner case and just inverting the - // style from what the parent ultimately decided upon works, even - // if it doesn't have perfect alignment with PEP8. - if let Some(style) = parent_docstring_quote_style { - style.invert() - } else { - QuoteStyle::Double - } - } else { - configured_style - }; - - let raw_content = locator.slice(self.content_range); - - let quotes = match quoting { - Quoting::Preserve => self.quotes, - Quoting::CanChange => { - if self.prefix.is_raw_string() { - choose_quotes_raw(raw_content, self.quotes, preferred_style) - } else { - choose_quotes(raw_content, self.quotes, preferred_style) - } - } - }; - - let normalized = normalize_string(locator.slice(self.content_range), quotes, self.prefix); - - NormalizedString { - prefix: self.prefix, - content_range: self.content_range, - text: normalized, - quotes, - } - } -} - -#[derive(Debug)] -struct NormalizedString<'a> { - prefix: StringPrefix, - - /// The quotes of the normalized string (preferred quotes) - quotes: StringQuotes, - - /// The range of the string's content in the source (minus prefix and quotes). - content_range: TextRange, - - /// The normalized text - text: Cow<'a, str>, -} - -impl Ranged for NormalizedString<'_> { - fn range(&self) -> TextRange { - self.content_range - } -} - -impl Format> for NormalizedString<'_> { - fn fmt(&self, f: &mut Formatter>) -> FormatResult<()> { - write!(f, [self.prefix, self.quotes])?; - match &self.text { - Cow::Borrowed(_) => { - source_text_slice(self.range()).fmt(f)?; - } - Cow::Owned(normalized) => { - text(normalized, Some(self.start())).fmt(f)?; - } - } - self.quotes.fmt(f) - } -} - -bitflags! { - #[derive(Copy, Clone, Debug, PartialEq, Eq)] - pub(super) struct StringPrefix: u8 { - const UNICODE = 0b0000_0001; - /// `r"test"` - const RAW = 0b0000_0010; - /// `R"test" - const RAW_UPPER = 0b0000_0100; - const BYTE = 0b0000_1000; - const F_STRING = 0b0001_0000; - } -} - -impl StringPrefix { - pub(super) fn parse(input: &str) -> StringPrefix { - let chars = input.chars(); - let mut prefix = StringPrefix::empty(); - - for c in chars { - let flag = match c { - 'u' | 'U' => StringPrefix::UNICODE, - 'f' | 'F' => StringPrefix::F_STRING, - 'b' | 'B' => StringPrefix::BYTE, - 'r' => StringPrefix::RAW, - 'R' => StringPrefix::RAW_UPPER, - '\'' | '"' => break, - c => { - unreachable!( - "Unexpected character '{c}' terminating the prefix of a string literal" - ); - } - }; - - prefix |= flag; - } - - prefix - } - - pub(super) const fn text_len(self) -> TextSize { - TextSize::new(self.bits().count_ones()) - } - - pub(super) const fn is_raw_string(self) -> bool { - self.contains(StringPrefix::RAW) || self.contains(StringPrefix::RAW_UPPER) - } - - pub(super) const fn is_fstring(self) -> bool { - self.contains(StringPrefix::F_STRING) - } -} - -impl Format> for StringPrefix { - fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { - // Retain the casing for the raw prefix: - // https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#r-strings-and-r-strings - if self.contains(StringPrefix::RAW) { - token("r").fmt(f)?; - } else if self.contains(StringPrefix::RAW_UPPER) { - token("R").fmt(f)?; - } - - if self.contains(StringPrefix::BYTE) { - token("b").fmt(f)?; - } - - if self.contains(StringPrefix::F_STRING) { - token("f").fmt(f)?; - } - - // Remove the unicode prefix `u` if any because it is meaningless in Python 3+. - - Ok(()) - } -} - -/// Choose the appropriate quote style for a raw string. -/// -/// The preferred quote style is chosen unless the string contains unescaped quotes of the -/// preferred style. For example, `r"foo"` is chosen over `r'foo'` if the preferred quote -/// style is double quotes. -fn choose_quotes_raw( - input: &str, - quotes: StringQuotes, - preferred_style: QuoteStyle, -) -> StringQuotes { - let preferred_quote_char = preferred_style.as_char(); - let mut chars = input.chars().peekable(); - let contains_unescaped_configured_quotes = loop { - match chars.next() { - Some('\\') => { - // Ignore escaped characters - chars.next(); - } - // `"` or `'` - Some(c) if c == preferred_quote_char => { - if !quotes.triple { - break true; - } - - match chars.peek() { - // We can't turn `r'''\""'''` into `r"""\"""""`, this would confuse the parser - // about where the closing triple quotes start - None => break true, - Some(next) if *next == preferred_quote_char => { - // `""` or `''` - chars.next(); - - // We can't turn `r'''""'''` into `r""""""""`, nor can we have - // `"""` or `'''` respectively inside the string - if chars.peek().is_none() || chars.peek() == Some(&preferred_quote_char) { - break true; - } - } - _ => {} - } - } - Some(_) => continue, - None => break false, - } - }; - - StringQuotes { - triple: quotes.triple, - style: if contains_unescaped_configured_quotes { - quotes.style - } else { - preferred_style - }, - } -} -/// Choose the appropriate quote style for a string. -/// -/// For single quoted strings, the preferred quote style is used, unless the alternative quote style -/// would require fewer escapes. -/// -/// For triple quoted strings, the preferred quote style is always used, unless the string contains -/// a triplet of the quote character (e.g., if double quotes are preferred, double quotes will be -/// used unless the string contains `"""`). -fn choose_quotes(input: &str, quotes: StringQuotes, preferred_style: QuoteStyle) -> StringQuotes { - let style = if quotes.triple { - // True if the string contains a triple quote sequence of the configured quote style. - let mut uses_triple_quotes = false; - let mut chars = input.chars().peekable(); +use crate::{prelude::*, FormatModuleError, QuoteStyle}; - while let Some(c) = chars.next() { - let preferred_quote_char = preferred_style.as_char(); - match c { - '\\' => { - if matches!(chars.peek(), Some('"' | '\\')) { - chars.next(); - } - } - // `"` or `'` - c if c == preferred_quote_char => { - match chars.peek().copied() { - Some(c) if c == preferred_quote_char => { - // `""` or `''` - chars.next(); - - match chars.peek().copied() { - Some(c) if c == preferred_quote_char => { - // `"""` or `'''` - chars.next(); - uses_triple_quotes = true; - break; - } - Some(_) => {} - None => { - // Handle `''' ""'''`. At this point we have consumed both - // double quotes, so on the next iteration the iterator is empty - // and we'd miss the string ending with a preferred quote - uses_triple_quotes = true; - break; - } - } - } - Some(_) => { - // A single quote char, this is ok - } - None => { - // Trailing quote at the end of the comment - uses_triple_quotes = true; - break; - } - } - } - _ => continue, - } - } - - if uses_triple_quotes { - // String contains a triple quote sequence of the configured quote style. - // Keep the existing quote style. - quotes.style - } else { - preferred_style - } - } else { - let mut single_quotes = 0u32; - let mut double_quotes = 0u32; - - for c in input.chars() { - match c { - '\'' => { - single_quotes += 1; - } - - '"' => { - double_quotes += 1; - } - - _ => continue, - } - } - - match preferred_style { - QuoteStyle::Single => { - if single_quotes > double_quotes { - QuoteStyle::Double - } else { - QuoteStyle::Single - } - } - QuoteStyle::Double => { - if double_quotes > single_quotes { - QuoteStyle::Single - } else { - QuoteStyle::Double - } - } - } - }; - - StringQuotes { - triple: quotes.triple, - style, - } -} - -#[derive(Copy, Clone, Debug)] -pub(super) struct StringQuotes { - triple: bool, - style: QuoteStyle, -} - -impl StringQuotes { - pub(super) fn parse(input: &str) -> Option { - let mut chars = input.chars(); - - let quote_char = chars.next()?; - let style = QuoteStyle::try_from(quote_char).ok()?; - - let triple = chars.next() == Some(quote_char) && chars.next() == Some(quote_char); - - Some(Self { triple, style }) - } - - pub(super) const fn is_triple(self) -> bool { - self.triple - } - - const fn text_len(self) -> TextSize { - if self.triple { - TextSize::new(3) - } else { - TextSize::new(1) - } - } -} - -impl Format> for StringQuotes { - fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { - let quotes = match (self.style, self.triple) { - (QuoteStyle::Single, false) => "'", - (QuoteStyle::Single, true) => "'''", - (QuoteStyle::Double, false) => "\"", - (QuoteStyle::Double, true) => "\"\"\"", - }; - - token(quotes).fmt(f) - } -} - -/// Adds the necessary quote escapes and removes unnecessary escape sequences when quoting `input` -/// with the provided [`StringQuotes`] style. -/// -/// Returns the normalized string and whether it contains new lines. -fn normalize_string(input: &str, quotes: StringQuotes, prefix: StringPrefix) -> Cow { - // The normalized string if `input` is not yet normalized. - // `output` must remain empty if `input` is already normalized. - let mut output = String::new(); - // Tracks the last index of `input` that has been written to `output`. - // If `last_index` is `0` at the end, then the input is already normalized and can be returned as is. - let mut last_index = 0; - - let style = quotes.style; - let preferred_quote = style.as_char(); - let opposite_quote = style.invert().as_char(); - - let mut chars = input.char_indices().peekable(); - - let is_raw = prefix.is_raw_string(); - let is_fstring = prefix.is_fstring(); - let mut formatted_value_nesting = 0u32; - - while let Some((index, c)) = chars.next() { - if is_fstring && matches!(c, '{' | '}') { - if chars.peek().copied().is_some_and(|(_, next)| next == c) { - // Skip over the second character of the double braces - chars.next(); - } else if c == '{' { - formatted_value_nesting += 1; - } else { - // Safe to assume that `c == '}'` here because of the matched pattern above - formatted_value_nesting = formatted_value_nesting.saturating_sub(1); - } - continue; - } - if c == '\r' { - output.push_str(&input[last_index..index]); - - // Skip over the '\r' character, keep the `\n` - if chars.peek().copied().is_some_and(|(_, next)| next == '\n') { - chars.next(); - } - // Replace the `\r` with a `\n` - else { - output.push('\n'); - } - - last_index = index + '\r'.len_utf8(); - } else if !quotes.triple && !is_raw { - if c == '\\' { - if let Some((_, next)) = chars.peek().copied() { - #[allow(clippy::if_same_then_else)] - if next == opposite_quote && formatted_value_nesting == 0 { - // Remove the escape by ending before the backslash and starting again with the quote - chars.next(); - output.push_str(&input[last_index..index]); - last_index = index + '\\'.len_utf8(); - } else if next == preferred_quote { - // Quote is already escaped, skip over it. - chars.next(); - } else if next == '\\' { - // Skip over escaped backslashes - chars.next(); - } - } - } else if c == preferred_quote && formatted_value_nesting == 0 { - // Escape the quote - output.push_str(&input[last_index..index]); - output.push('\\'); - output.push(c); - last_index = index + preferred_quote.len_utf8(); - } - } - } - - let normalized = if last_index == 0 { - Cow::Borrowed(input) - } else { - output.push_str(&input[last_index..]); - Cow::Owned(output) - }; - - normalized -} - -/// For docstring indentation, black counts spaces as 1 and tabs by increasing the indentation up -/// to the next multiple of 8. This is effectively a port of -/// [`str.expandtabs`](https://docs.python.org/3/library/stdtypes.html#str.expandtabs), -/// which black [calls with the default tab width of 8](https://github.com/psf/black/blob/c36e468794f9256d5e922c399240d49782ba04f1/src/black/strings.py#L61). -fn indentation_length(line: &str) -> TextSize { - let mut indentation = 0u32; - for char in line.chars() { - if char == '\t' { - // Pad to the next multiple of tab_width - indentation += 8 - (indentation.rem_euclid(8)); - } else if char.is_whitespace() { - indentation += u32::from(char.text_len()); - } else { - break; - } - } - TextSize::new(indentation) -} +use super::NormalizedString; /// Format a docstring by trimming whitespace and adjusting the indentation. /// @@ -913,7 +95,7 @@ fn indentation_length(line: &str) -> TextSize { /// line c /// """ /// ``` -fn format_docstring(normalized: &NormalizedString, f: &mut PyFormatter) -> FormatResult<()> { +pub(super) fn format(normalized: &NormalizedString, f: &mut PyFormatter) -> FormatResult<()> { let docstring = &normalized.text; // Black doesn't change the indentation of docstrings that contain an escaped newline @@ -1551,11 +733,31 @@ fn needs_chaperone_space(normalized: &NormalizedString, trim_end: &str) -> bool || trim_end.chars().rev().take_while(|c| *c == '\\').count() % 2 == 1 } +/// For docstring indentation, black counts spaces as 1 and tabs by increasing the indentation up +/// to the next multiple of 8. This is effectively a port of +/// [`str.expandtabs`](https://docs.python.org/3/library/stdtypes.html#str.expandtabs), +/// which black [calls with the default tab width of 8](https://github.com/psf/black/blob/c36e468794f9256d5e922c399240d49782ba04f1/src/black/strings.py#L61). +fn indentation_length(line: &str) -> TextSize { + let mut indentation = 0u32; + for char in line.chars() { + if char == '\t' { + // Pad to the next multiple of tab_width + indentation += 8 - (indentation.rem_euclid(8)); + } else if char.is_whitespace() { + indentation += u32::from(char.text_len()); + } else { + break; + } + } + TextSize::new(indentation) +} + #[cfg(test)] mod tests { - use crate::expression::string::indentation_length; use ruff_text_size::TextSize; + use super::indentation_length; + #[test] fn test_indentation_like_black() { assert_eq!(indentation_length("\t \t \t"), TextSize::new(24)); diff --git a/crates/ruff_python_formatter/src/expression/string/mod.rs b/crates/ruff_python_formatter/src/expression/string/mod.rs new file mode 100644 index 0000000000000..5a7a6a1b4677b --- /dev/null +++ b/crates/ruff_python_formatter/src/expression/string/mod.rs @@ -0,0 +1,811 @@ +use std::borrow::Cow; + +use bitflags::bitflags; + +use ruff_formatter::{format_args, write}; +use ruff_python_ast::AnyNodeRef; +use ruff_python_ast::{ + self as ast, ExprBytesLiteral, ExprFString, ExprStringLiteral, ExpressionRef, +}; +use ruff_source_file::Locator; +use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; + +use crate::comments::{leading_comments, trailing_comments}; +use crate::expression::parentheses::{ + in_parentheses_only_group, in_parentheses_only_soft_line_break_or_space, +}; +use crate::expression::Expr; +use crate::prelude::*; +use crate::QuoteStyle; + +mod docstring; + +#[derive(Copy, Clone, Debug)] +enum Quoting { + CanChange, + Preserve, +} + +#[derive(Clone, Debug)] +pub(super) enum AnyString<'a> { + String(&'a ExprStringLiteral), + Bytes(&'a ExprBytesLiteral), + FString(&'a ExprFString), +} + +impl<'a> AnyString<'a> { + pub(crate) fn from_expression(expression: &'a Expr) -> Option> { + match expression { + Expr::StringLiteral(string) => Some(AnyString::String(string)), + Expr::BytesLiteral(bytes) => Some(AnyString::Bytes(bytes)), + Expr::FString(fstring) => Some(AnyString::FString(fstring)), + _ => None, + } + } + + fn quoting(&self, locator: &Locator) -> Quoting { + match self { + Self::String(_) | Self::Bytes(_) => Quoting::CanChange, + Self::FString(f_string) => { + let unprefixed = locator + .slice(f_string.range) + .trim_start_matches(|c| c != '"' && c != '\''); + let triple_quoted = + unprefixed.starts_with(r#"""""#) || unprefixed.starts_with(r"'''"); + if f_string.value.elements().any(|value| match value { + Expr::FormattedValue(ast::ExprFormattedValue { range, .. }) => { + let string_content = locator.slice(*range); + if triple_quoted { + string_content.contains(r#"""""#) || string_content.contains("'''") + } else { + string_content.contains(['"', '\'']) + } + } + _ => false, + }) { + Quoting::Preserve + } else { + Quoting::CanChange + } + } + } + } + + /// Returns `true` if the string is implicitly concatenated. + pub(super) fn is_implicit_concatenated(&self) -> bool { + match self { + Self::String(ExprStringLiteral { value, .. }) => value.is_implicit_concatenated(), + Self::Bytes(ExprBytesLiteral { value, .. }) => value.is_implicit_concatenated(), + Self::FString(ExprFString { value, .. }) => value.is_implicit_concatenated(), + } + } + + fn parts(&self) -> Vec> { + match self { + Self::String(ExprStringLiteral { value, .. }) => { + value.parts().map(AnyStringPart::String).collect() + } + Self::Bytes(ExprBytesLiteral { value, .. }) => { + value.parts().map(AnyStringPart::Bytes).collect() + } + Self::FString(ExprFString { value, .. }) => value + .parts() + .map(|f_string_part| match f_string_part { + ast::FStringPart::Literal(string_literal) => { + AnyStringPart::String(string_literal) + } + ast::FStringPart::FString(f_string) => AnyStringPart::FString(f_string), + }) + .collect(), + } + } +} + +impl Ranged for AnyString<'_> { + fn range(&self) -> TextRange { + match self { + Self::String(expr) => expr.range(), + Self::Bytes(expr) => expr.range(), + Self::FString(expr) => expr.range(), + } + } +} + +impl<'a> From<&AnyString<'a>> for AnyNodeRef<'a> { + fn from(value: &AnyString<'a>) -> Self { + match value { + AnyString::String(expr) => AnyNodeRef::ExprStringLiteral(expr), + AnyString::Bytes(expr) => AnyNodeRef::ExprBytesLiteral(expr), + AnyString::FString(expr) => AnyNodeRef::ExprFString(expr), + } + } +} + +impl<'a> From<&AnyString<'a>> for ExpressionRef<'a> { + fn from(value: &AnyString<'a>) -> Self { + match value { + AnyString::String(expr) => ExpressionRef::StringLiteral(expr), + AnyString::Bytes(expr) => ExpressionRef::BytesLiteral(expr), + AnyString::FString(expr) => ExpressionRef::FString(expr), + } + } +} + +#[derive(Clone, Debug)] +enum AnyStringPart<'a> { + String(&'a ast::StringLiteral), + Bytes(&'a ast::BytesLiteral), + FString(&'a ast::FString), +} + +impl<'a> From<&AnyStringPart<'a>> for AnyNodeRef<'a> { + fn from(value: &AnyStringPart<'a>) -> Self { + match value { + AnyStringPart::String(part) => AnyNodeRef::StringLiteral(part), + AnyStringPart::Bytes(part) => AnyNodeRef::BytesLiteral(part), + AnyStringPart::FString(part) => AnyNodeRef::FString(part), + } + } +} + +impl Ranged for AnyStringPart<'_> { + fn range(&self) -> TextRange { + match self { + Self::String(part) => part.range(), + Self::Bytes(part) => part.range(), + Self::FString(part) => part.range(), + } + } +} + +pub(super) struct FormatString<'a> { + string: &'a AnyString<'a>, + layout: StringLayout, +} + +#[derive(Default, Copy, Clone, Debug)] +pub enum StringLayout { + #[default] + Default, + DocString, + /// An implicit concatenated string in a binary like (e.g. `a + b` or `a < b`) expression. + /// + /// Formats the implicit concatenated string parts without the enclosing group because the group + /// is added by the binary like formatting. + ImplicitConcatenatedStringInBinaryLike, +} + +impl<'a> FormatString<'a> { + pub(super) fn new(string: &'a AnyString<'a>) -> Self { + Self { + string, + layout: StringLayout::Default, + } + } + + pub(super) fn with_layout(mut self, layout: StringLayout) -> Self { + self.layout = layout; + self + } +} + +impl<'a> Format> for FormatString<'a> { + fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { + let parent_docstring_quote_style = f.context().docstring(); + let locator = f.context().locator(); + let result = match self.layout { + StringLayout::Default => { + if self.string.is_implicit_concatenated() { + in_parentheses_only_group(&FormatStringContinuation::new(self.string)).fmt(f) + } else { + StringPart::from_source(self.string.range(), &locator) + .normalize( + self.string.quoting(&locator), + &locator, + f.options().quote_style(), + parent_docstring_quote_style, + ) + .fmt(f) + } + } + StringLayout::DocString => { + let string_part = StringPart::from_source(self.string.range(), &locator); + let normalized = string_part.normalize( + Quoting::CanChange, + &locator, + f.options().quote_style(), + parent_docstring_quote_style, + ); + docstring::format(&normalized, f) + } + StringLayout::ImplicitConcatenatedStringInBinaryLike => { + FormatStringContinuation::new(self.string).fmt(f) + } + }; + // TODO(dhruvmanila): With PEP 701, comments can be inside f-strings. + // This is to mark all of those comments as formatted but we need to + // figure out how to handle them. Note that this needs to be done only + // after the f-string is formatted, so only for all the non-formatted + // comments. + if let AnyString::FString(fstring) = self.string { + let comments = f.context().comments(); + fstring.value.elements().for_each(|value| { + comments.mark_verbatim_node_comments_formatted(value.into()); + }); + } + result + } +} + +struct FormatStringContinuation<'a> { + string: &'a AnyString<'a>, +} + +impl<'a> FormatStringContinuation<'a> { + fn new(string: &'a AnyString<'a>) -> Self { + Self { string } + } +} + +impl Format> for FormatStringContinuation<'_> { + fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { + let comments = f.context().comments().clone(); + let locator = f.context().locator(); + let in_docstring = f.context().docstring(); + let quote_style = f.options().quote_style(); + + let mut joiner = f.join_with(in_parentheses_only_soft_line_break_or_space()); + + for part in self.string.parts() { + let normalized = StringPart::from_source(part.range(), &locator).normalize( + self.string.quoting(&locator), + &locator, + quote_style, + in_docstring, + ); + + joiner.entry(&format_args![ + line_suffix_boundary(), + leading_comments(comments.leading(&part)), + normalized, + trailing_comments(comments.trailing(&part)) + ]); + } + + joiner.finish() + } +} + +#[derive(Debug)] +struct StringPart { + /// The prefix. + prefix: StringPrefix, + + /// The actual quotes of the string in the source + quotes: StringQuotes, + + /// The range of the string's content (full range minus quotes and prefix) + content_range: TextRange, +} + +impl StringPart { + fn from_source(range: TextRange, locator: &Locator) -> Self { + let string_content = locator.slice(range); + + let prefix = StringPrefix::parse(string_content); + let after_prefix = &string_content[usize::from(prefix.text_len())..]; + + let quotes = + StringQuotes::parse(after_prefix).expect("Didn't find string quotes after prefix"); + let relative_raw_content_range = TextRange::new( + prefix.text_len() + quotes.text_len(), + string_content.text_len() - quotes.text_len(), + ); + let raw_content_range = relative_raw_content_range + range.start(); + + Self { + prefix, + content_range: raw_content_range, + quotes, + } + } + + /// Computes the strings preferred quotes and normalizes its content. + /// + /// The parent docstring quote style should be set when formatting a code + /// snippet within the docstring. The quote style should correspond to the + /// style of quotes used by said docstring. Normalization will ensure the + /// quoting styles don't conflict. + fn normalize<'a>( + self, + quoting: Quoting, + locator: &'a Locator, + configured_style: QuoteStyle, + parent_docstring_quote_style: Option, + ) -> NormalizedString<'a> { + // Per PEP 8 and PEP 257, always prefer double quotes for docstrings + // and triple-quoted strings. (We assume docstrings are always + // triple-quoted.) + let preferred_style = if self.quotes.triple { + // ... unless we're formatting a code snippet inside a docstring, + // then we specifically want to invert our quote style to avoid + // writing out invalid Python. + // + // It's worth pointing out that we can actually wind up being + // somewhat out of sync with PEP8 in this case. Consider this + // example: + // + // def foo(): + // ''' + // Something. + // + // >>> """tricksy""" + // ''' + // pass + // + // Ideally, this would be reformatted as: + // + // def foo(): + // """ + // Something. + // + // >>> '''tricksy''' + // """ + // pass + // + // But the logic here results in the original quoting being + // preserved. This is because the quoting style of the outer + // docstring is determined, in part, by looking at its contents. In + // this case, it notices that it contains a `"""` and thus infers + // that using `'''` would overall read better because it avoids + // the need to escape the interior `"""`. Except... in this case, + // the `"""` is actually part of a code snippet that could get + // reformatted to using a different quoting style itself. + // + // Fixing this would, I believe, require some fairly seismic + // changes to how formatting strings works. Namely, we would need + // to look for code snippets before normalizing the docstring, and + // then figure out the quoting style more holistically by looking + // at the various kinds of quotes used in the code snippets and + // what reformatting them might look like. + // + // Overall this is a bit of a corner case and just inverting the + // style from what the parent ultimately decided upon works, even + // if it doesn't have perfect alignment with PEP8. + if let Some(style) = parent_docstring_quote_style { + style.invert() + } else { + QuoteStyle::Double + } + } else { + configured_style + }; + + let raw_content = locator.slice(self.content_range); + + let quotes = match quoting { + Quoting::Preserve => self.quotes, + Quoting::CanChange => { + if self.prefix.is_raw_string() { + choose_quotes_raw(raw_content, self.quotes, preferred_style) + } else { + choose_quotes(raw_content, self.quotes, preferred_style) + } + } + }; + + let normalized = normalize_string(locator.slice(self.content_range), quotes, self.prefix); + + NormalizedString { + prefix: self.prefix, + content_range: self.content_range, + text: normalized, + quotes, + } + } +} + +#[derive(Debug)] +struct NormalizedString<'a> { + prefix: StringPrefix, + + /// The quotes of the normalized string (preferred quotes) + quotes: StringQuotes, + + /// The range of the string's content in the source (minus prefix and quotes). + content_range: TextRange, + + /// The normalized text + text: Cow<'a, str>, +} + +impl Ranged for NormalizedString<'_> { + fn range(&self) -> TextRange { + self.content_range + } +} + +impl Format> for NormalizedString<'_> { + fn fmt(&self, f: &mut Formatter>) -> FormatResult<()> { + write!(f, [self.prefix, self.quotes])?; + match &self.text { + Cow::Borrowed(_) => { + source_text_slice(self.range()).fmt(f)?; + } + Cow::Owned(normalized) => { + text(normalized, Some(self.start())).fmt(f)?; + } + } + self.quotes.fmt(f) + } +} + +bitflags! { + #[derive(Copy, Clone, Debug, PartialEq, Eq)] + pub(super) struct StringPrefix: u8 { + const UNICODE = 0b0000_0001; + /// `r"test"` + const RAW = 0b0000_0010; + /// `R"test" + const RAW_UPPER = 0b0000_0100; + const BYTE = 0b0000_1000; + const F_STRING = 0b0001_0000; + } +} + +impl StringPrefix { + pub(super) fn parse(input: &str) -> StringPrefix { + let chars = input.chars(); + let mut prefix = StringPrefix::empty(); + + for c in chars { + let flag = match c { + 'u' | 'U' => StringPrefix::UNICODE, + 'f' | 'F' => StringPrefix::F_STRING, + 'b' | 'B' => StringPrefix::BYTE, + 'r' => StringPrefix::RAW, + 'R' => StringPrefix::RAW_UPPER, + '\'' | '"' => break, + c => { + unreachable!( + "Unexpected character '{c}' terminating the prefix of a string literal" + ); + } + }; + + prefix |= flag; + } + + prefix + } + + pub(super) const fn text_len(self) -> TextSize { + TextSize::new(self.bits().count_ones()) + } + + pub(super) const fn is_raw_string(self) -> bool { + self.contains(StringPrefix::RAW) || self.contains(StringPrefix::RAW_UPPER) + } + + pub(super) const fn is_fstring(self) -> bool { + self.contains(StringPrefix::F_STRING) + } +} + +impl Format> for StringPrefix { + fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { + // Retain the casing for the raw prefix: + // https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#r-strings-and-r-strings + if self.contains(StringPrefix::RAW) { + token("r").fmt(f)?; + } else if self.contains(StringPrefix::RAW_UPPER) { + token("R").fmt(f)?; + } + + if self.contains(StringPrefix::BYTE) { + token("b").fmt(f)?; + } + + if self.contains(StringPrefix::F_STRING) { + token("f").fmt(f)?; + } + + // Remove the unicode prefix `u` if any because it is meaningless in Python 3+. + + Ok(()) + } +} + +/// Choose the appropriate quote style for a raw string. +/// +/// The preferred quote style is chosen unless the string contains unescaped quotes of the +/// preferred style. For example, `r"foo"` is chosen over `r'foo'` if the preferred quote +/// style is double quotes. +fn choose_quotes_raw( + input: &str, + quotes: StringQuotes, + preferred_style: QuoteStyle, +) -> StringQuotes { + let preferred_quote_char = preferred_style.as_char(); + let mut chars = input.chars().peekable(); + let contains_unescaped_configured_quotes = loop { + match chars.next() { + Some('\\') => { + // Ignore escaped characters + chars.next(); + } + // `"` or `'` + Some(c) if c == preferred_quote_char => { + if !quotes.triple { + break true; + } + + match chars.peek() { + // We can't turn `r'''\""'''` into `r"""\"""""`, this would confuse the parser + // about where the closing triple quotes start + None => break true, + Some(next) if *next == preferred_quote_char => { + // `""` or `''` + chars.next(); + + // We can't turn `r'''""'''` into `r""""""""`, nor can we have + // `"""` or `'''` respectively inside the string + if chars.peek().is_none() || chars.peek() == Some(&preferred_quote_char) { + break true; + } + } + _ => {} + } + } + Some(_) => continue, + None => break false, + } + }; + + StringQuotes { + triple: quotes.triple, + style: if contains_unescaped_configured_quotes { + quotes.style + } else { + preferred_style + }, + } +} + +/// Choose the appropriate quote style for a string. +/// +/// For single quoted strings, the preferred quote style is used, unless the alternative quote style +/// would require fewer escapes. +/// +/// For triple quoted strings, the preferred quote style is always used, unless the string contains +/// a triplet of the quote character (e.g., if double quotes are preferred, double quotes will be +/// used unless the string contains `"""`). +fn choose_quotes(input: &str, quotes: StringQuotes, preferred_style: QuoteStyle) -> StringQuotes { + let style = if quotes.triple { + // True if the string contains a triple quote sequence of the configured quote style. + let mut uses_triple_quotes = false; + let mut chars = input.chars().peekable(); + + while let Some(c) = chars.next() { + let preferred_quote_char = preferred_style.as_char(); + match c { + '\\' => { + if matches!(chars.peek(), Some('"' | '\\')) { + chars.next(); + } + } + // `"` or `'` + c if c == preferred_quote_char => { + match chars.peek().copied() { + Some(c) if c == preferred_quote_char => { + // `""` or `''` + chars.next(); + + match chars.peek().copied() { + Some(c) if c == preferred_quote_char => { + // `"""` or `'''` + chars.next(); + uses_triple_quotes = true; + break; + } + Some(_) => {} + None => { + // Handle `''' ""'''`. At this point we have consumed both + // double quotes, so on the next iteration the iterator is empty + // and we'd miss the string ending with a preferred quote + uses_triple_quotes = true; + break; + } + } + } + Some(_) => { + // A single quote char, this is ok + } + None => { + // Trailing quote at the end of the comment + uses_triple_quotes = true; + break; + } + } + } + _ => continue, + } + } + + if uses_triple_quotes { + // String contains a triple quote sequence of the configured quote style. + // Keep the existing quote style. + quotes.style + } else { + preferred_style + } + } else { + let mut single_quotes = 0u32; + let mut double_quotes = 0u32; + + for c in input.chars() { + match c { + '\'' => { + single_quotes += 1; + } + + '"' => { + double_quotes += 1; + } + + _ => continue, + } + } + + match preferred_style { + QuoteStyle::Single => { + if single_quotes > double_quotes { + QuoteStyle::Double + } else { + QuoteStyle::Single + } + } + QuoteStyle::Double => { + if double_quotes > single_quotes { + QuoteStyle::Single + } else { + QuoteStyle::Double + } + } + } + }; + + StringQuotes { + triple: quotes.triple, + style, + } +} + +#[derive(Copy, Clone, Debug)] +pub(super) struct StringQuotes { + triple: bool, + style: QuoteStyle, +} + +impl StringQuotes { + pub(super) fn parse(input: &str) -> Option { + let mut chars = input.chars(); + + let quote_char = chars.next()?; + let style = QuoteStyle::try_from(quote_char).ok()?; + + let triple = chars.next() == Some(quote_char) && chars.next() == Some(quote_char); + + Some(Self { triple, style }) + } + + pub(super) const fn is_triple(self) -> bool { + self.triple + } + + const fn text_len(self) -> TextSize { + if self.triple { + TextSize::new(3) + } else { + TextSize::new(1) + } + } +} + +impl Format> for StringQuotes { + fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { + let quotes = match (self.style, self.triple) { + (QuoteStyle::Single, false) => "'", + (QuoteStyle::Single, true) => "'''", + (QuoteStyle::Double, false) => "\"", + (QuoteStyle::Double, true) => "\"\"\"", + }; + + token(quotes).fmt(f) + } +} + +/// Adds the necessary quote escapes and removes unnecessary escape sequences when quoting `input` +/// with the provided [`StringQuotes`] style. +/// +/// Returns the normalized string and whether it contains new lines. +fn normalize_string(input: &str, quotes: StringQuotes, prefix: StringPrefix) -> Cow { + // The normalized string if `input` is not yet normalized. + // `output` must remain empty if `input` is already normalized. + let mut output = String::new(); + // Tracks the last index of `input` that has been written to `output`. + // If `last_index` is `0` at the end, then the input is already normalized and can be returned as is. + let mut last_index = 0; + + let style = quotes.style; + let preferred_quote = style.as_char(); + let opposite_quote = style.invert().as_char(); + + let mut chars = input.char_indices().peekable(); + + let is_raw = prefix.is_raw_string(); + let is_fstring = prefix.is_fstring(); + let mut formatted_value_nesting = 0u32; + + while let Some((index, c)) = chars.next() { + if is_fstring && matches!(c, '{' | '}') { + if chars.peek().copied().is_some_and(|(_, next)| next == c) { + // Skip over the second character of the double braces + chars.next(); + } else if c == '{' { + formatted_value_nesting += 1; + } else { + // Safe to assume that `c == '}'` here because of the matched pattern above + formatted_value_nesting = formatted_value_nesting.saturating_sub(1); + } + continue; + } + if c == '\r' { + output.push_str(&input[last_index..index]); + + // Skip over the '\r' character, keep the `\n` + if chars.peek().copied().is_some_and(|(_, next)| next == '\n') { + chars.next(); + } + // Replace the `\r` with a `\n` + else { + output.push('\n'); + } + + last_index = index + '\r'.len_utf8(); + } else if !quotes.triple && !is_raw { + if c == '\\' { + if let Some((_, next)) = chars.peek().copied() { + #[allow(clippy::if_same_then_else)] + if next == opposite_quote && formatted_value_nesting == 0 { + // Remove the escape by ending before the backslash and starting again with the quote + chars.next(); + output.push_str(&input[last_index..index]); + last_index = index + '\\'.len_utf8(); + } else if next == preferred_quote { + // Quote is already escaped, skip over it. + chars.next(); + } else if next == '\\' { + // Skip over escaped backslashes + chars.next(); + } + } + } else if c == preferred_quote && formatted_value_nesting == 0 { + // Escape the quote + output.push_str(&input[last_index..index]); + output.push('\\'); + output.push(c); + last_index = index + preferred_quote.len_utf8(); + } + } + } + + let normalized = if last_index == 0 { + Cow::Borrowed(input) + } else { + output.push_str(&input[last_index..]); + Cow::Owned(output) + }; + + normalized +} From 60eb11fa5066518777216c62deb59934e8621079 Mon Sep 17 00:00:00 2001 From: Tom Kuson Date: Mon, 27 Nov 2023 23:57:00 +0000 Subject: [PATCH 044/197] [`refurb`] Implement `redundant-log-base` (`FURB163`) (#8842) ## Summary Implement [`simplify-math-log`](https://github.com/dosisod/refurb/blob/master/refurb/checks/math/simplify_log.py) as `redundant-log-base` (`FURB163`). Auto-fixes ```python import math math.log(2, 2) ``` to ```python import math math.log2(2) ``` Related to #1348. ## Test Plan `cargo test` --- .../resources/test/fixtures/refurb/FURB163.py | 47 ++++ .../src/checkers/ast/analyze/expression.rs | 3 + crates/ruff_linter/src/codes.rs | 1 + crates/ruff_linter/src/rules/refurb/mod.rs | 1 + .../ruff_linter/src/rules/refurb/rules/mod.rs | 2 + .../rules/refurb/rules/redundant_log_base.rs | 149 +++++++++++ ...es__refurb__tests__FURB163_FURB163.py.snap | 233 ++++++++++++++++++ ruff.schema.json | 1 + 8 files changed, 437 insertions(+) create mode 100644 crates/ruff_linter/resources/test/fixtures/refurb/FURB163.py create mode 100644 crates/ruff_linter/src/rules/refurb/rules/redundant_log_base.rs create mode 100644 crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB163_FURB163.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/refurb/FURB163.py b/crates/ruff_linter/resources/test/fixtures/refurb/FURB163.py new file mode 100644 index 0000000000000..1f2255be8ef74 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/refurb/FURB163.py @@ -0,0 +1,47 @@ +import math + +from math import e as special_e +from math import log as special_log + +# Errors. +math.log(1, 2) +math.log(1, 10) +math.log(1, math.e) +foo = ... +math.log(foo, 2) +math.log(foo, 10) +math.log(foo, math.e) +math.log(1, special_e) +special_log(1, 2) +special_log(1, 10) +special_log(1, math.e) +special_log(1, special_e) + +# Ok. +math.log2(1) +math.log10(1) +math.log(1) +math.log(1, 3) +math.log(1, math.pi) + +two = 2 +math.log(1, two) + +ten = 10 +math.log(1, ten) + +e = math.e +math.log(1, e) + +math.log2(1, 10) # math.log2 takes only one argument. +math.log10(1, 2) # math.log10 takes only one argument. + +math.log(1, base=2) # math.log does not accept keyword arguments. + +def log(*args): + print(f"Logging: {args}") + + +log(1, 2) +log(1, 10) +log(1, math.e) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index e5ca3bbee31f6..f3e8bbaecfe6e 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -928,6 +928,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::PrintEmptyString) { refurb::rules::print_empty_string(checker, call); } + if checker.enabled(Rule::RedundantLogBase) { + refurb::rules::redundant_log_base(checker, call); + } if checker.enabled(Rule::QuadraticListSummation) { ruff::rules::quadratic_list_summation(checker, call); } diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index 1e04278e0f15b..4dc1f13c55e05 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -955,6 +955,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Refurb, "145") => (RuleGroup::Preview, rules::refurb::rules::SliceCopy), (Refurb, "148") => (RuleGroup::Preview, rules::refurb::rules::UnnecessaryEnumerate), (Refurb, "152") => (RuleGroup::Preview, rules::refurb::rules::MathConstant), + (Refurb, "163") => (RuleGroup::Preview, rules::refurb::rules::RedundantLogBase), (Refurb, "168") => (RuleGroup::Preview, rules::refurb::rules::IsinstanceTypeNone), (Refurb, "169") => (RuleGroup::Preview, rules::refurb::rules::TypeNoneComparison), (Refurb, "171") => (RuleGroup::Preview, rules::refurb::rules::SingleItemMembershipTest), diff --git a/crates/ruff_linter/src/rules/refurb/mod.rs b/crates/ruff_linter/src/rules/refurb/mod.rs index 49a2c49bfe6c2..a7640bcd4c72b 100644 --- a/crates/ruff_linter/src/rules/refurb/mod.rs +++ b/crates/ruff_linter/src/rules/refurb/mod.rs @@ -28,6 +28,7 @@ mod tests { #[test_case(Rule::SingleItemMembershipTest, Path::new("FURB171.py"))] #[test_case(Rule::IsinstanceTypeNone, Path::new("FURB168.py"))] #[test_case(Rule::TypeNoneComparison, Path::new("FURB169.py"))] + #[test_case(Rule::RedundantLogBase, Path::new("FURB163.py"))] fn rules(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/refurb/rules/mod.rs b/crates/ruff_linter/src/rules/refurb/rules/mod.rs index 6729202272905..d43f87bced0aa 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/mod.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/mod.rs @@ -6,6 +6,7 @@ pub(crate) use isinstance_type_none::*; pub(crate) use math_constant::*; pub(crate) use print_empty_string::*; pub(crate) use read_whole_file::*; +pub(crate) use redundant_log_base::*; pub(crate) use reimplemented_starmap::*; pub(crate) use repeated_append::*; pub(crate) use single_item_membership_test::*; @@ -21,6 +22,7 @@ mod isinstance_type_none; mod math_constant; mod print_empty_string; mod read_whole_file; +mod redundant_log_base; mod reimplemented_starmap; mod repeated_append; mod single_item_membership_test; diff --git a/crates/ruff_linter/src/rules/refurb/rules/redundant_log_base.rs b/crates/ruff_linter/src/rules/refurb/rules/redundant_log_base.rs new file mode 100644 index 0000000000000..a4a6e58959326 --- /dev/null +++ b/crates/ruff_linter/src/rules/refurb/rules/redundant_log_base.rs @@ -0,0 +1,149 @@ +use anyhow::Result; +use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; +use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::{self as ast, Expr, Number}; +use ruff_text_size::Ranged; + +use crate::checkers::ast::Checker; +use crate::importer::ImportRequest; + +/// ## What it does +/// Checks for `math.log` calls with a redundant base. +/// +/// ## Why is this bad? +/// The default base of `math.log` is `e`, so specifying it explicitly is +/// redundant. +/// +/// Instead of passing 2 or 10 as the base, use `math.log2` or `math.log10` +/// respectively, as these dedicated variants are typically more accurate +/// than `math.log`. +/// +/// ## Example +/// ```python +/// import math +/// +/// math.log(4, math.e) +/// math.log(4, 2) +/// math.log(4, 10) +/// ``` +/// +/// Use instead: +/// ```python +/// import math +/// +/// math.log(4) +/// math.log2(4) +/// math.log10(4) +/// ``` +/// +/// ## References +/// - [Python documentation: `math.log`](https://docs.python.org/3/library/math.html#math.log) +/// - [Python documentation: `math.log2`](https://docs.python.org/3/library/math.html#math.log2) +/// - [Python documentation: `math.log10`](https://docs.python.org/3/library/math.html#math.log10) +/// - [Python documentation: `math.e`](https://docs.python.org/3/library/math.html#math.e) +#[violation] +pub struct RedundantLogBase { + base: Base, + arg: String, +} + +impl Violation for RedundantLogBase { + const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes; + + #[derive_message_formats] + fn message(&self) -> String { + let RedundantLogBase { base, arg } = self; + let log_function = base.to_log_function(); + format!("Prefer `math.{log_function}({arg})` over `math.log` with a redundant base") + } + + fn fix_title(&self) -> Option { + let RedundantLogBase { base, arg } = self; + let log_function = base.to_log_function(); + Some(format!("Replace with `math.{log_function}({arg})`")) + } +} + +/// FURB163 +pub(crate) fn redundant_log_base(checker: &mut Checker, call: &ast::ExprCall) { + if !call.arguments.keywords.is_empty() { + return; + } + + let [arg, base] = &call.arguments.args.as_slice() else { + return; + }; + + if !checker + .semantic() + .resolve_call_path(&call.func) + .as_ref() + .is_some_and(|call_path| matches!(call_path.as_slice(), ["math", "log"])) + { + return; + } + + let base = if is_number_literal(base, 2) { + Base::Two + } else if is_number_literal(base, 10) { + Base::Ten + } else if checker + .semantic() + .resolve_call_path(base) + .as_ref() + .is_some_and(|call_path| matches!(call_path.as_slice(), ["math", "e"])) + { + Base::E + } else { + return; + }; + + let mut diagnostic = Diagnostic::new( + RedundantLogBase { + base, + arg: checker.locator().slice(arg).into(), + }, + call.range(), + ); + diagnostic.try_set_fix(|| generate_fix(checker, call, base, arg)); + checker.diagnostics.push(diagnostic); +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Base { + E, + Two, + Ten, +} + +impl Base { + fn to_log_function(self) -> &'static str { + match self { + Base::E => "log", + Base::Two => "log2", + Base::Ten => "log10", + } + } +} + +fn is_number_literal(expr: &Expr, value: i8) -> bool { + if let Expr::NumberLiteral(number_literal) = expr { + if let Number::Int(number) = &number_literal.value { + return number.as_i8().is_some_and(|number| number == value); + } + } + false +} + +fn generate_fix(checker: &Checker, call: &ast::ExprCall, base: Base, arg: &Expr) -> Result { + let (edit, binding) = checker.importer().get_or_import_symbol( + &ImportRequest::import("math", base.to_log_function()), + call.start(), + checker.semantic(), + )?; + let number = checker.locator().slice(arg); + Ok(Fix::safe_edits( + Edit::range_replacement(format!("{binding}({number})"), call.range()), + [edit], + )) +} diff --git a/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB163_FURB163.py.snap b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB163_FURB163.py.snap new file mode 100644 index 0000000000000..e6441a4c1e3e0 --- /dev/null +++ b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB163_FURB163.py.snap @@ -0,0 +1,233 @@ +--- +source: crates/ruff_linter/src/rules/refurb/mod.rs +--- +FURB163.py:7:1: FURB163 [*] Prefer `math.log2(1)` over `math.log` with a redundant base + | +6 | # Errors. +7 | math.log(1, 2) + | ^^^^^^^^^^^^^^ FURB163 +8 | math.log(1, 10) +9 | math.log(1, math.e) + | + = help: Replace with `math.log2(1)` + +ℹ Safe fix +4 4 | from math import log as special_log +5 5 | +6 6 | # Errors. +7 |-math.log(1, 2) + 7 |+math.log2(1) +8 8 | math.log(1, 10) +9 9 | math.log(1, math.e) +10 10 | foo = ... + +FURB163.py:8:1: FURB163 [*] Prefer `math.log10(1)` over `math.log` with a redundant base + | + 6 | # Errors. + 7 | math.log(1, 2) + 8 | math.log(1, 10) + | ^^^^^^^^^^^^^^^ FURB163 + 9 | math.log(1, math.e) +10 | foo = ... + | + = help: Replace with `math.log10(1)` + +ℹ Safe fix +5 5 | +6 6 | # Errors. +7 7 | math.log(1, 2) +8 |-math.log(1, 10) + 8 |+math.log10(1) +9 9 | math.log(1, math.e) +10 10 | foo = ... +11 11 | math.log(foo, 2) + +FURB163.py:9:1: FURB163 [*] Prefer `math.log(1)` over `math.log` with a redundant base + | + 7 | math.log(1, 2) + 8 | math.log(1, 10) + 9 | math.log(1, math.e) + | ^^^^^^^^^^^^^^^^^^^ FURB163 +10 | foo = ... +11 | math.log(foo, 2) + | + = help: Replace with `math.log(1)` + +ℹ Safe fix +6 6 | # Errors. +7 7 | math.log(1, 2) +8 8 | math.log(1, 10) +9 |-math.log(1, math.e) + 9 |+math.log(1) +10 10 | foo = ... +11 11 | math.log(foo, 2) +12 12 | math.log(foo, 10) + +FURB163.py:11:1: FURB163 [*] Prefer `math.log2(foo)` over `math.log` with a redundant base + | + 9 | math.log(1, math.e) +10 | foo = ... +11 | math.log(foo, 2) + | ^^^^^^^^^^^^^^^^ FURB163 +12 | math.log(foo, 10) +13 | math.log(foo, math.e) + | + = help: Replace with `math.log2(foo)` + +ℹ Safe fix +8 8 | math.log(1, 10) +9 9 | math.log(1, math.e) +10 10 | foo = ... +11 |-math.log(foo, 2) + 11 |+math.log2(foo) +12 12 | math.log(foo, 10) +13 13 | math.log(foo, math.e) +14 14 | math.log(1, special_e) + +FURB163.py:12:1: FURB163 [*] Prefer `math.log10(foo)` over `math.log` with a redundant base + | +10 | foo = ... +11 | math.log(foo, 2) +12 | math.log(foo, 10) + | ^^^^^^^^^^^^^^^^^ FURB163 +13 | math.log(foo, math.e) +14 | math.log(1, special_e) + | + = help: Replace with `math.log10(foo)` + +ℹ Safe fix +9 9 | math.log(1, math.e) +10 10 | foo = ... +11 11 | math.log(foo, 2) +12 |-math.log(foo, 10) + 12 |+math.log10(foo) +13 13 | math.log(foo, math.e) +14 14 | math.log(1, special_e) +15 15 | special_log(1, 2) + +FURB163.py:13:1: FURB163 [*] Prefer `math.log(foo)` over `math.log` with a redundant base + | +11 | math.log(foo, 2) +12 | math.log(foo, 10) +13 | math.log(foo, math.e) + | ^^^^^^^^^^^^^^^^^^^^^ FURB163 +14 | math.log(1, special_e) +15 | special_log(1, 2) + | + = help: Replace with `math.log(foo)` + +ℹ Safe fix +10 10 | foo = ... +11 11 | math.log(foo, 2) +12 12 | math.log(foo, 10) +13 |-math.log(foo, math.e) + 13 |+math.log(foo) +14 14 | math.log(1, special_e) +15 15 | special_log(1, 2) +16 16 | special_log(1, 10) + +FURB163.py:14:1: FURB163 [*] Prefer `math.log(1)` over `math.log` with a redundant base + | +12 | math.log(foo, 10) +13 | math.log(foo, math.e) +14 | math.log(1, special_e) + | ^^^^^^^^^^^^^^^^^^^^^^ FURB163 +15 | special_log(1, 2) +16 | special_log(1, 10) + | + = help: Replace with `math.log(1)` + +ℹ Safe fix +11 11 | math.log(foo, 2) +12 12 | math.log(foo, 10) +13 13 | math.log(foo, math.e) +14 |-math.log(1, special_e) + 14 |+math.log(1) +15 15 | special_log(1, 2) +16 16 | special_log(1, 10) +17 17 | special_log(1, math.e) + +FURB163.py:15:1: FURB163 [*] Prefer `math.log2(1)` over `math.log` with a redundant base + | +13 | math.log(foo, math.e) +14 | math.log(1, special_e) +15 | special_log(1, 2) + | ^^^^^^^^^^^^^^^^^ FURB163 +16 | special_log(1, 10) +17 | special_log(1, math.e) + | + = help: Replace with `math.log2(1)` + +ℹ Safe fix +12 12 | math.log(foo, 10) +13 13 | math.log(foo, math.e) +14 14 | math.log(1, special_e) +15 |-special_log(1, 2) + 15 |+math.log2(1) +16 16 | special_log(1, 10) +17 17 | special_log(1, math.e) +18 18 | special_log(1, special_e) + +FURB163.py:16:1: FURB163 [*] Prefer `math.log10(1)` over `math.log` with a redundant base + | +14 | math.log(1, special_e) +15 | special_log(1, 2) +16 | special_log(1, 10) + | ^^^^^^^^^^^^^^^^^^ FURB163 +17 | special_log(1, math.e) +18 | special_log(1, special_e) + | + = help: Replace with `math.log10(1)` + +ℹ Safe fix +13 13 | math.log(foo, math.e) +14 14 | math.log(1, special_e) +15 15 | special_log(1, 2) +16 |-special_log(1, 10) + 16 |+math.log10(1) +17 17 | special_log(1, math.e) +18 18 | special_log(1, special_e) +19 19 | + +FURB163.py:17:1: FURB163 [*] Prefer `math.log(1)` over `math.log` with a redundant base + | +15 | special_log(1, 2) +16 | special_log(1, 10) +17 | special_log(1, math.e) + | ^^^^^^^^^^^^^^^^^^^^^^ FURB163 +18 | special_log(1, special_e) + | + = help: Replace with `math.log(1)` + +ℹ Safe fix +14 14 | math.log(1, special_e) +15 15 | special_log(1, 2) +16 16 | special_log(1, 10) +17 |-special_log(1, math.e) + 17 |+math.log(1) +18 18 | special_log(1, special_e) +19 19 | +20 20 | # Ok. + +FURB163.py:18:1: FURB163 [*] Prefer `math.log(1)` over `math.log` with a redundant base + | +16 | special_log(1, 10) +17 | special_log(1, math.e) +18 | special_log(1, special_e) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ FURB163 +19 | +20 | # Ok. + | + = help: Replace with `math.log(1)` + +ℹ Safe fix +15 15 | special_log(1, 2) +16 16 | special_log(1, 10) +17 17 | special_log(1, math.e) +18 |-special_log(1, special_e) + 18 |+math.log(1) +19 19 | +20 20 | # Ok. +21 21 | math.log2(1) + + diff --git a/ruff.schema.json b/ruff.schema.json index 8ae7c3fe37fb2..38b1dbc5319ac 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -2849,6 +2849,7 @@ "FURB15", "FURB152", "FURB16", + "FURB163", "FURB168", "FURB169", "FURB17", From ed14fd91637bfd526b2c47cc6532dddfda712014 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 27 Nov 2023 21:47:35 -0800 Subject: [PATCH 045/197] [`pydocstyle`] Avoid non-character breaks in `over-indentation` (`D208`) (#8866) Closes https://github.com/astral-sh/ruff/issues/8844. --- .../test/fixtures/pydocstyle/D208.py | 5 ++ .../ruff_linter/src/rules/pydocstyle/mod.rs | 1 + .../src/rules/pydocstyle/rules/indent.rs | 20 +++++-- ...ules__pydocstyle__tests__D208_D208.py.snap | 57 +++++++++++++++++++ 4 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/pydocstyle/D208.py create mode 100644 crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D208.py b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D208.py new file mode 100644 index 0000000000000..f0515248abb5c --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D208.py @@ -0,0 +1,5 @@ +class Platform: + """ Remove sampler + Args: +     Returns: + """ diff --git a/crates/ruff_linter/src/rules/pydocstyle/mod.rs b/crates/ruff_linter/src/rules/pydocstyle/mod.rs index 205d16abd615f..5c08ee88dba7b 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/mod.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/mod.rs @@ -46,6 +46,7 @@ mod tests { #[test_case(Rule::NoBlankLineBeforeFunction, Path::new("D.py"))] #[test_case(Rule::BlankLinesBetweenHeaderAndContent, Path::new("sections.py"))] #[test_case(Rule::OverIndentation, Path::new("D.py"))] + #[test_case(Rule::OverIndentation, Path::new("D208.py"))] #[test_case(Rule::NoSignature, Path::new("D.py"))] #[test_case(Rule::SurroundingWhitespace, Path::new("D.py"))] #[test_case(Rule::DocstringStartsWithThis, Path::new("D.py"))] diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs index 497dd816e1367..f56bc1bed47b2 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs @@ -172,7 +172,7 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { let mut has_seen_tab = docstring.indentation.contains('\t'); let mut is_over_indented = true; let mut over_indented_lines = vec![]; - let mut over_indented_offset = TextSize::from(u32::MAX); + let mut over_indented_offset = usize::MAX; for i in 0..lines.len() { // First lines and continuations doesn't need any indentation. @@ -220,9 +220,9 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { if line_indent.len() > docstring.indentation.len() { over_indented_lines.push(line); - // Track the _smallest_ offset we see + // Track the _smallest_ offset we see, in terms of characters. over_indented_offset = std::cmp::min( - line_indent.text_len() - docstring.indentation.text_len(), + line_indent.chars().count() - docstring.indentation.chars().count(), over_indented_offset, ); } else { @@ -247,15 +247,23 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { let indent = clean_space(docstring.indentation); // We report over-indentation on every line. This isn't great, but - // enables fix. + // enables the fix capability. let mut diagnostic = Diagnostic::new(OverIndentation, TextRange::empty(line.start())); let edit = if indent.is_empty() { - Edit::range_deletion(TextRange::at(line.start(), line_indent.text_len())) + Edit::deletion(line.start(), line_indent.text_len()) } else { + // Convert the character count to an offset within the source. + let offset = checker + .locator() + .after(line.start() + indent.text_len()) + .chars() + .take(over_indented_offset) + .map(TextLen::text_len) + .sum::(); Edit::range_replacement( indent.clone(), - TextRange::at(line.start(), indent.text_len() + over_indented_offset), + TextRange::at(line.start(), indent.text_len() + offset), ) }; diagnostic.set_fix(Fix::safe_edit(edit)); diff --git a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap new file mode 100644 index 0000000000000..ca8b68bcbeee5 --- /dev/null +++ b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap @@ -0,0 +1,57 @@ +--- +source: crates/ruff_linter/src/rules/pydocstyle/mod.rs +--- +D208.py:3:1: D208 [*] Docstring is over-indented + | +1 | class Platform: +2 | """ Remove sampler +3 | Args: + | D208 +4 |     Returns: +5 | """ + | + = help: Remove over-indentation + +ℹ Safe fix +1 1 | class Platform: +2 2 | """ Remove sampler +3 |- Args: + 3 |+ Args: +4 4 |     Returns: +5 5 | """ + +D208.py:4:1: D208 [*] Docstring is over-indented + | +2 | """ Remove sampler +3 | Args: +4 |     Returns: + | D208 +5 | """ + | + = help: Remove over-indentation + +ℹ Safe fix +1 1 | class Platform: +2 2 | """ Remove sampler +3 3 | Args: +4 |-     Returns: + 4 |+ Returns: +5 5 | """ + +D208.py:5:1: D208 [*] Docstring is over-indented + | +3 | Args: +4 |     Returns: +5 | """ + | D208 + | + = help: Remove over-indentation + +ℹ Safe fix +2 2 | """ Remove sampler +3 3 | Args: +4 4 |     Returns: +5 |- """ + 5 |+ """ + + From 578ddf1bb1e8edef50cda9981744ba5fe825867d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joffrey=20Bluth=C3=A9?= Date: Tue, 28 Nov 2023 07:00:37 +0100 Subject: [PATCH 046/197] [`isort`] Add support for length-sort settings (#8841) ## Summary Closes #1567. Add both `length-sort` and `length-sort-straight` settings for isort. Here are a few notable points: - The length is determined using the [`unicode_width`](https://crates.io/crates/unicode-width) crate, i.e. we are talking about displayed length (this is explicitly mentioned in the description of the setting) - The dots are taken into account in the length to be compatible with the original isort - I had to reorder a few fields of the module key struct for it all to make sense (notably the `force_to_top` field is now the first one) ## Test Plan I added tests for the following cases: - Basic tests for length-sort with ASCII characters only - Tests with non-ASCII characters - Tests with relative imports - Tests for length-sort-straight --- .../isort/length_sort_from_imports.py | 3 ++ .../isort/length_sort_non_ascii_members.py | 11 +++++ .../isort/length_sort_non_ascii_modules.py | 9 ++++ .../length_sort_straight_and_from_imports.py | 6 +++ .../isort/length_sort_straight_imports.py | 4 ++ .../length_sort_with_relative_imports.py | 7 +++ .../isort/length_sort_with_star_import.py | 3 ++ crates/ruff_linter/src/rules/isort/mod.rs | 43 +++++++++++++++++++ crates/ruff_linter/src/rules/isort/order.rs | 23 ++++++++-- .../ruff_linter/src/rules/isort/settings.rs | 4 ++ ...gth_sort__length_sort_from_imports.py.snap | 18 ++++++++ ...ort__length_sort_non_ascii_members.py.snap | 37 ++++++++++++++++ ...ort__length_sort_non_ascii_modules.py.snap | 32 ++++++++++++++ ...gth_sort_straight_and_from_imports.py.snap | 26 +++++++++++ ...sort__length_sort_straight_imports.py.snap | 21 +++++++++ ..._length_sort_with_relative_imports.py.snap | 28 ++++++++++++ ...straight__length_sort_from_imports.py.snap | 18 ++++++++ ...gth_sort_straight_and_from_imports.py.snap | 23 ++++++++++ ...ight__length_sort_straight_imports.py.snap | 21 +++++++++ crates/ruff_linter/src/rules/isort/sorting.rs | 42 ++++++++++++++---- crates/ruff_workspace/src/options.rs | 36 ++++++++++++++++ ruff.schema.json | 14 ++++++ 22 files changed, 417 insertions(+), 12 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/isort/length_sort_from_imports.py create mode 100644 crates/ruff_linter/resources/test/fixtures/isort/length_sort_non_ascii_members.py create mode 100644 crates/ruff_linter/resources/test/fixtures/isort/length_sort_non_ascii_modules.py create mode 100644 crates/ruff_linter/resources/test/fixtures/isort/length_sort_straight_and_from_imports.py create mode 100644 crates/ruff_linter/resources/test/fixtures/isort/length_sort_straight_imports.py create mode 100644 crates/ruff_linter/resources/test/fixtures/isort/length_sort_with_relative_imports.py create mode 100644 crates/ruff_linter/resources/test/fixtures/isort/length_sort_with_star_import.py create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_from_imports.py.snap create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_non_ascii_members.py.snap create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_non_ascii_modules.py.snap create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_straight_and_from_imports.py.snap create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_straight_imports.py.snap create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_with_relative_imports.py.snap create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort_straight__length_sort_from_imports.py.snap create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort_straight__length_sort_straight_and_from_imports.py.snap create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort_straight__length_sort_straight_imports.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/isort/length_sort_from_imports.py b/crates/ruff_linter/resources/test/fixtures/isort/length_sort_from_imports.py new file mode 100644 index 0000000000000..bf6a5732d2236 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/isort/length_sort_from_imports.py @@ -0,0 +1,3 @@ +from mediuuuuuuuuuuum import a +from short import b +from loooooooooooooooooooooog import c diff --git a/crates/ruff_linter/resources/test/fixtures/isort/length_sort_non_ascii_members.py b/crates/ruff_linter/resources/test/fixtures/isort/length_sort_non_ascii_members.py new file mode 100644 index 0000000000000..6419d6251196c --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/isort/length_sort_non_ascii_members.py @@ -0,0 +1,11 @@ +from module1 import ( + loooooooooooooong, + σηορτ, + mediuuuuum, + shoort, + looooooooooooooong, + μεδιυυυυυμ, + short, + mediuuuuuum, + λοοοοοοοοοοοοοονγ, +) diff --git a/crates/ruff_linter/resources/test/fixtures/isort/length_sort_non_ascii_modules.py b/crates/ruff_linter/resources/test/fixtures/isort/length_sort_non_ascii_modules.py new file mode 100644 index 0000000000000..e7895a0d2becb --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/isort/length_sort_non_ascii_modules.py @@ -0,0 +1,9 @@ +import loooooooooooooong +import mediuuuuuum +import short +import σηορτ +import shoort +import mediuuuuum +import λοοοοοοοοοοοοοονγ +import μεδιυυυυυμ +import looooooooooooooong diff --git a/crates/ruff_linter/resources/test/fixtures/isort/length_sort_straight_and_from_imports.py b/crates/ruff_linter/resources/test/fixtures/isort/length_sort_straight_and_from_imports.py new file mode 100644 index 0000000000000..738efb3549339 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/isort/length_sort_straight_and_from_imports.py @@ -0,0 +1,6 @@ +import mediuuuuuum +import short +import looooooooooooooooong +from looooooooooooooong import a +from mediuuuum import c +from short import b diff --git a/crates/ruff_linter/resources/test/fixtures/isort/length_sort_straight_imports.py b/crates/ruff_linter/resources/test/fixtures/isort/length_sort_straight_imports.py new file mode 100644 index 0000000000000..70aabd043b021 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/isort/length_sort_straight_imports.py @@ -0,0 +1,4 @@ +import mediuuuuuumb +import short +import looooooooooooooooong +import mediuuuuuuma diff --git a/crates/ruff_linter/resources/test/fixtures/isort/length_sort_with_relative_imports.py b/crates/ruff_linter/resources/test/fixtures/isort/length_sort_with_relative_imports.py new file mode 100644 index 0000000000000..ca0b97065ecad --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/isort/length_sort_with_relative_imports.py @@ -0,0 +1,7 @@ +from ..looooooooooooooong import a +from ...mediuuuum import b +from .short import c +from ....short import c +from . import d +from .mediuuuum import a +from ......short import b diff --git a/crates/ruff_linter/resources/test/fixtures/isort/length_sort_with_star_import.py b/crates/ruff_linter/resources/test/fixtures/isort/length_sort_with_star_import.py new file mode 100644 index 0000000000000..3dbf73c4d2974 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/isort/length_sort_with_star_import.py @@ -0,0 +1,3 @@ +from looooooooooooooong import a +from mediuuuum import * +from short import * diff --git a/crates/ruff_linter/src/rules/isort/mod.rs b/crates/ruff_linter/src/rules/isort/mod.rs index 5fce5a86acfc8..60b511847c909 100644 --- a/crates/ruff_linter/src/rules/isort/mod.rs +++ b/crates/ruff_linter/src/rules/isort/mod.rs @@ -1138,4 +1138,47 @@ mod tests { assert_messages!(diagnostics); Ok(()) } + + #[test_case(Path::new("length_sort_straight_imports.py"))] + #[test_case(Path::new("length_sort_from_imports.py"))] + #[test_case(Path::new("length_sort_straight_and_from_imports.py"))] + #[test_case(Path::new("length_sort_non_ascii_members.py"))] + #[test_case(Path::new("length_sort_non_ascii_modules.py"))] + #[test_case(Path::new("length_sort_with_relative_imports.py"))] + fn length_sort(path: &Path) -> Result<()> { + let snapshot = format!("length_sort__{}", path.to_string_lossy()); + let diagnostics = test_path( + Path::new("isort").join(path).as_path(), + &LinterSettings { + isort: super::settings::Settings { + length_sort: true, + ..super::settings::Settings::default() + }, + src: vec![test_resource_path("fixtures/isort")], + ..LinterSettings::for_rule(Rule::UnsortedImports) + }, + )?; + assert_messages!(snapshot, diagnostics); + Ok(()) + } + + #[test_case(Path::new("length_sort_straight_imports.py"))] + #[test_case(Path::new("length_sort_from_imports.py"))] + #[test_case(Path::new("length_sort_straight_and_from_imports.py"))] + fn length_sort_straight(path: &Path) -> Result<()> { + let snapshot = format!("length_sort_straight__{}", path.to_string_lossy()); + let diagnostics = test_path( + Path::new("isort").join(path).as_path(), + &LinterSettings { + isort: super::settings::Settings { + length_sort_straight: true, + ..super::settings::Settings::default() + }, + src: vec![test_resource_path("fixtures/isort")], + ..LinterSettings::for_rule(Rule::UnsortedImports) + }, + )?; + assert_messages!(snapshot, diagnostics); + Ok(()) + } } diff --git a/crates/ruff_linter/src/rules/isort/order.rs b/crates/ruff_linter/src/rules/isort/order.rs index 1d7102b3cae35..25430b84ad6f9 100644 --- a/crates/ruff_linter/src/rules/isort/order.rs +++ b/crates/ruff_linter/src/rules/isort/order.rs @@ -1,3 +1,4 @@ +use crate::rules::isort::sorting::ImportStyle; use itertools::Itertools; use super::settings::Settings; @@ -56,21 +57,34 @@ pub(crate) fn order_imports<'a>( .map(Import) .chain(from_imports.map(ImportFrom)) .sorted_by_cached_key(|import| match import { - Import((alias, _)) => { - ModuleKey::from_module(Some(alias.name), alias.asname, None, None, settings) - } + Import((alias, _)) => ModuleKey::from_module( + Some(alias.name), + alias.asname, + None, + None, + ImportStyle::Straight, + settings, + ), ImportFrom((import_from, _, _, aliases)) => ModuleKey::from_module( import_from.module, None, import_from.level, aliases.first().map(|(alias, _)| (alias.name, alias.asname)), + ImportStyle::From, settings, ), }) .collect() } else { let ordered_straight_imports = straight_imports.sorted_by_cached_key(|(alias, _)| { - ModuleKey::from_module(Some(alias.name), alias.asname, None, None, settings) + ModuleKey::from_module( + Some(alias.name), + alias.asname, + None, + None, + ImportStyle::Straight, + settings, + ) }); let ordered_from_imports = from_imports.sorted_by_cached_key(|(import_from, _, _, aliases)| { @@ -79,6 +93,7 @@ pub(crate) fn order_imports<'a>( None, import_from.level, aliases.first().map(|(alias, _)| (alias.name, alias.asname)), + ImportStyle::From, settings, ) }); diff --git a/crates/ruff_linter/src/rules/isort/settings.rs b/crates/ruff_linter/src/rules/isort/settings.rs index d4937520fa7aa..2a28a3c8b396b 100644 --- a/crates/ruff_linter/src/rules/isort/settings.rs +++ b/crates/ruff_linter/src/rules/isort/settings.rs @@ -58,6 +58,8 @@ pub struct Settings { pub section_order: Vec, pub no_sections: bool, pub from_first: bool, + pub length_sort: bool, + pub length_sort_straight: bool, } impl Default for Settings { @@ -86,6 +88,8 @@ impl Default for Settings { section_order: ImportType::iter().map(ImportSection::Known).collect(), no_sections: false, from_first: false, + length_sort: false, + length_sort_straight: false, } } } diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_from_imports.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_from_imports.py.snap new file mode 100644 index 0000000000000..a2183e7de32c7 --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_from_imports.py.snap @@ -0,0 +1,18 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- +length_sort_from_imports.py:1:1: I001 [*] Import block is un-sorted or un-formatted + | +1 | / from mediuuuuuuuuuuum import a +2 | | from short import b +3 | | from loooooooooooooooooooooog import c + | + = help: Organize imports + +ℹ Safe fix + 1 |+from short import b +1 2 | from mediuuuuuuuuuuum import a +2 |-from short import b +3 3 | from loooooooooooooooooooooog import c + + diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_non_ascii_members.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_non_ascii_members.py.snap new file mode 100644 index 0000000000000..d6cfc0e340920 --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_non_ascii_members.py.snap @@ -0,0 +1,37 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- +length_sort_non_ascii_members.py:1:1: I001 [*] Import block is un-sorted or un-formatted + | + 1 | / from module1 import ( + 2 | | loooooooooooooong, + 3 | | σηορτ, + 4 | | mediuuuuum, + 5 | | shoort, + 6 | | looooooooooooooong, + 7 | | μεδιυυυυυμ, + 8 | | short, + 9 | | mediuuuuuum, +10 | | λοοοοοοοοοοοοοονγ, +11 | | ) + | + = help: Organize imports + +ℹ Safe fix +1 1 | from module1 import ( +2 |- loooooooooooooong, + 2 |+ short, +3 3 | σηορτ, + 4 |+ shoort, +4 5 | mediuuuuum, +5 |- shoort, +6 |- looooooooooooooong, +7 6 | μεδιυυυυυμ, +8 |- short, +9 7 | mediuuuuuum, + 8 |+ loooooooooooooong, +10 9 | λοοοοοοοοοοοοοονγ, + 10 |+ looooooooooooooong, +11 11 | ) + + diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_non_ascii_modules.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_non_ascii_modules.py.snap new file mode 100644 index 0000000000000..e1d66bd9a7bb9 --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_non_ascii_modules.py.snap @@ -0,0 +1,32 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- +length_sort_non_ascii_modules.py:1:1: I001 [*] Import block is un-sorted or un-formatted + | +1 | / import loooooooooooooong +2 | | import mediuuuuuum +3 | | import short +4 | | import σηορτ +5 | | import shoort +6 | | import mediuuuuum +7 | | import λοοοοοοοοοοοοοονγ +8 | | import μεδιυυυυυμ +9 | | import looooooooooooooong + | + = help: Organize imports + +ℹ Safe fix +1 |-import loooooooooooooong +2 |-import mediuuuuuum +3 1 | import short +4 2 | import σηορτ +5 3 | import shoort +6 4 | import mediuuuuum + 5 |+import μεδιυυυυυμ + 6 |+import mediuuuuuum + 7 |+import loooooooooooooong +7 8 | import λοοοοοοοοοοοοοονγ +8 |-import μεδιυυυυυμ +9 9 | import looooooooooooooong + + diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_straight_and_from_imports.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_straight_and_from_imports.py.snap new file mode 100644 index 0000000000000..7acc627804180 --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_straight_and_from_imports.py.snap @@ -0,0 +1,26 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- +length_sort_straight_and_from_imports.py:1:1: I001 [*] Import block is un-sorted or un-formatted + | +1 | / import mediuuuuuum +2 | | import short +3 | | import looooooooooooooooong +4 | | from looooooooooooooong import a +5 | | from mediuuuum import c +6 | | from short import b + | + = help: Organize imports + +ℹ Safe fix + 1 |+import short +1 2 | import mediuuuuuum +2 |-import short +3 3 | import looooooooooooooooong +4 |-from looooooooooooooong import a + 4 |+from short import b +5 5 | from mediuuuum import c +6 |-from short import b + 6 |+from looooooooooooooong import a + + diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_straight_imports.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_straight_imports.py.snap new file mode 100644 index 0000000000000..6c73af3a2a8fa --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_straight_imports.py.snap @@ -0,0 +1,21 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- +length_sort_straight_imports.py:1:1: I001 [*] Import block is un-sorted or un-formatted + | +1 | / import mediuuuuuumb +2 | | import short +3 | | import looooooooooooooooong +4 | | import mediuuuuuuma + | + = help: Organize imports + +ℹ Safe fix + 1 |+import short + 2 |+import mediuuuuuuma +1 3 | import mediuuuuuumb +2 |-import short +3 4 | import looooooooooooooooong +4 |-import mediuuuuuuma + + diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_with_relative_imports.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_with_relative_imports.py.snap new file mode 100644 index 0000000000000..20531ecd26d43 --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort__length_sort_with_relative_imports.py.snap @@ -0,0 +1,28 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- +length_sort_with_relative_imports.py:1:1: I001 [*] Import block is un-sorted or un-formatted + | +1 | / from ..looooooooooooooong import a +2 | | from ...mediuuuum import b +3 | | from .short import c +4 | | from ....short import c +5 | | from . import d +6 | | from .mediuuuum import a +7 | | from ......short import b + | + = help: Organize imports + +ℹ Safe fix +1 |-from ..looooooooooooooong import a +2 |-from ...mediuuuum import b + 1 |+from . import d +3 2 | from .short import c +4 3 | from ....short import c +5 |-from . import d +6 4 | from .mediuuuum import a +7 5 | from ......short import b + 6 |+from ...mediuuuum import b + 7 |+from ..looooooooooooooong import a + + diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort_straight__length_sort_from_imports.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort_straight__length_sort_from_imports.py.snap new file mode 100644 index 0000000000000..35bdec18f120c --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort_straight__length_sort_from_imports.py.snap @@ -0,0 +1,18 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- +length_sort_from_imports.py:1:1: I001 [*] Import block is un-sorted or un-formatted + | +1 | / from mediuuuuuuuuuuum import a +2 | | from short import b +3 | | from loooooooooooooooooooooog import c + | + = help: Organize imports + +ℹ Safe fix + 1 |+from loooooooooooooooooooooog import c +1 2 | from mediuuuuuuuuuuum import a +2 3 | from short import b +3 |-from loooooooooooooooooooooog import c + + diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort_straight__length_sort_straight_and_from_imports.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort_straight__length_sort_straight_and_from_imports.py.snap new file mode 100644 index 0000000000000..3cd80a04effd9 --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort_straight__length_sort_straight_and_from_imports.py.snap @@ -0,0 +1,23 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- +length_sort_straight_and_from_imports.py:1:1: I001 [*] Import block is un-sorted or un-formatted + | +1 | / import mediuuuuuum +2 | | import short +3 | | import looooooooooooooooong +4 | | from looooooooooooooong import a +5 | | from mediuuuum import c +6 | | from short import b + | + = help: Organize imports + +ℹ Safe fix + 1 |+import short +1 2 | import mediuuuuuum +2 |-import short +3 3 | import looooooooooooooooong +4 4 | from looooooooooooooong import a +5 5 | from mediuuuum import c + + diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort_straight__length_sort_straight_imports.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort_straight__length_sort_straight_imports.py.snap new file mode 100644 index 0000000000000..6c73af3a2a8fa --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__length_sort_straight__length_sort_straight_imports.py.snap @@ -0,0 +1,21 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- +length_sort_straight_imports.py:1:1: I001 [*] Import block is un-sorted or un-formatted + | +1 | / import mediuuuuuumb +2 | | import short +3 | | import looooooooooooooooong +4 | | import mediuuuuuuma + | + = help: Organize imports + +ℹ Safe fix + 1 |+import short + 2 |+import mediuuuuuuma +1 3 | import mediuuuuuumb +2 |-import short +3 4 | import looooooooooooooooong +4 |-import mediuuuuuuma + + diff --git a/crates/ruff_linter/src/rules/isort/sorting.rs b/crates/ruff_linter/src/rules/isort/sorting.rs index cb6f01f730054..aa979fc90c89e 100644 --- a/crates/ruff_linter/src/rules/isort/sorting.rs +++ b/crates/ruff_linter/src/rules/isort/sorting.rs @@ -3,6 +3,7 @@ use std::{borrow::Cow, cmp::Ordering, cmp::Reverse}; use natord; +use unicode_width::UnicodeWidthStr; use ruff_python_stdlib::str; @@ -64,18 +65,27 @@ impl<'a> From for NatOrdStr<'a> { } } -#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] pub(crate) enum Distance { Nearest(u32), Furthest(Reverse), } +#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] +pub(crate) enum ImportStyle { + // Ex) `import foo` + Straight, + // Ex) `from foo import bar` + From, +} + /// A comparable key to capture the desired sorting order for an imported module (e.g., /// `foo` in `from foo import bar`). #[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub(crate) struct ModuleKey<'a> { + force_to_top: bool, + maybe_length: Option, distance: Distance, - force_to_top: Option, maybe_lowercase_name: Option>, module_name: Option>, first_alias: Option>, @@ -88,26 +98,39 @@ impl<'a> ModuleKey<'a> { asname: Option<&'a str>, level: Option, first_alias: Option<(&'a str, Option<&'a str>)>, + style: ImportStyle, settings: &Settings, ) -> Self { + let level = level.unwrap_or_default(); + + let force_to_top = !name + .map(|name| settings.force_to_top.contains(name)) + .unwrap_or_default(); // `false` < `true` so we get forced to top first + + let maybe_length = (settings.length_sort + || (settings.length_sort_straight && style == ImportStyle::Straight)) + .then_some(name.map(str::width).unwrap_or_default() + level as usize); + let distance = match settings.relative_imports_order { - RelativeImportsOrder::ClosestToFurthest => Distance::Nearest(level.unwrap_or_default()), - RelativeImportsOrder::FurthestToClosest => { - Distance::Furthest(Reverse(level.unwrap_or_default())) - } + RelativeImportsOrder::ClosestToFurthest => Distance::Nearest(level), + RelativeImportsOrder::FurthestToClosest => Distance::Furthest(Reverse(level)), }; - let force_to_top = name.map(|name| !settings.force_to_top.contains(name)); // `false` < `true` so we get forced to top first + let maybe_lowercase_name = name.and_then(|name| { (!settings.case_sensitive).then_some(NatOrdStr(maybe_lowercase(name))) }); + let module_name = name.map(NatOrdStr::from); + let asname = asname.map(NatOrdStr::from); + let first_alias = first_alias.map(|(name, asname)| MemberKey::from_member(name, asname, settings)); Self { - distance, force_to_top, + maybe_length, + distance, maybe_lowercase_name, module_name, first_alias, @@ -122,6 +145,7 @@ impl<'a> ModuleKey<'a> { pub(crate) struct MemberKey<'a> { not_star_import: bool, member_type: Option, + maybe_length: Option, maybe_lowercase_name: Option>, module_name: NatOrdStr<'a>, asname: Option>, @@ -133,6 +157,7 @@ impl<'a> MemberKey<'a> { let member_type = settings .order_by_type .then_some(member_type(name, settings)); + let maybe_length = settings.length_sort.then_some(name.width()); let maybe_lowercase_name = (!settings.case_sensitive).then_some(NatOrdStr(maybe_lowercase(name))); let module_name = NatOrdStr::from(name); @@ -141,6 +166,7 @@ impl<'a> MemberKey<'a> { Self { not_star_import, member_type, + maybe_length, maybe_lowercase_name, module_name, asname, diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index 6d8569dca4bd1..05f4522710cd9 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -2047,6 +2047,40 @@ pub struct IsortOptions { )] pub from_first: Option, + /// Sort imports by their string length, such that shorter imports appear + /// before longer imports. For example, by default, imports will be sorted + /// alphabetically, as in: + /// ```python + /// import collections + /// import os + /// ``` + /// + /// Setting `length-sort = true` will instead sort such that shorter imports + /// appear before longer imports, as in: + /// ```python + /// import os + /// import collections + /// ``` + #[option( + default = r#"false"#, + value_type = "bool", + example = r#" + length-sort = true + "# + )] + pub length_sort: Option, + + /// Sort straight imports by their string length. Similar to `length-sort`, + /// but applies only to straight imports and doesn't affect `from` imports. + #[option( + default = r#"false"#, + value_type = "bool", + example = r#" + length-sort-straight = true + "# + )] + pub length_sort_straight: Option, + // Tables are required to go last. /// A list of mappings from section names to modules. /// By default custom sections are output last, but this can be overridden with `section-order`. @@ -2234,6 +2268,8 @@ impl IsortOptions { section_order, no_sections, from_first, + length_sort: self.length_sort.unwrap_or(false), + length_sort_straight: self.length_sort_straight.unwrap_or(false), }) } } diff --git a/ruff.schema.json b/ruff.schema.json index 38b1dbc5319ac..cb37f44161c40 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -1477,6 +1477,20 @@ "type": "string" } }, + "length-sort": { + "description": "Sort imports by their string length, such that shorter imports appear before longer imports. For example, by default, imports will be sorted alphabetically, as in: ```python import collections import os ```\n\nSetting `length-sort = true` will instead sort such that shorter imports appear before longer imports, as in: ```python import os import collections ```", + "type": [ + "boolean", + "null" + ] + }, + "length-sort-straight": { + "description": "Sort straight imports by their string length. Similar to `length-sort`, but applies only to straight imports and doesn't affect `from` imports.", + "type": [ + "boolean", + "null" + ] + }, "lines-after-imports": { "description": "The number of blank lines to place after imports. Use `-1` for automatic determination.\n\nWhen using the formatter, only the values `-1`, `1`, and `2` are compatible because it enforces at least one empty and at most two empty lines after imports.", "type": [ From f585e3e2dc09eeb061e2cfbb459f63d212c74232 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Tue, 28 Nov 2023 09:50:03 -0500 Subject: [PATCH 047/197] remove several uses of `unsafe` (#8600) This PR removes several uses of `unsafe`. I generally limited myself to low hanging fruit that I could see. There are still a few remaining uses of `unsafe` that looked a bit more difficult to remove (if possible at all). But this gets rid of a good chunk of them. I put each `unsafe` removal into its own commit with a justification for why I did it. So I would encourage reviewing this PR commit-by-commit. That way, we can legislate them independently. It's no problem to drop a commit if we feel the `unsafe` should stay in that case. --- crates/ruff_formatter/src/arguments.rs | 41 ++++--------------- crates/ruff_formatter/src/builders.rs | 30 +++++++------- crates/ruff_formatter/src/format_element.rs | 38 +++++++++++++---- crates/ruff_formatter/src/macros.rs | 6 +-- crates/ruff_macros/src/newtype_index.rs | 6 +++ .../ruff_python_formatter/src/comments/map.rs | 6 +-- .../src/expression/binary_like.rs | 5 +-- crates/ruff_python_literal/src/escape.rs | 8 ++-- crates/ruff_python_parser/src/string.rs | 6 +-- crates/ruff_source_file/src/newlines.rs | 6 +-- 10 files changed, 69 insertions(+), 83 deletions(-) diff --git a/crates/ruff_formatter/src/arguments.rs b/crates/ruff_formatter/src/arguments.rs index 8fa70d73db8d8..d26306c4ea502 100644 --- a/crates/ruff_formatter/src/arguments.rs +++ b/crates/ruff_formatter/src/arguments.rs @@ -1,23 +1,9 @@ use super::{Buffer, Format, Formatter}; use crate::FormatResult; -use std::ffi::c_void; -use std::marker::PhantomData; -/// Mono-morphed type to format an object. Used by the [`crate::format`!], [`crate::format_args`!], and -/// [`crate::write`!] macros. -/// -/// This struct is similar to a dynamic dispatch (using `dyn Format`) because it stores a pointer to the value. -/// However, it doesn't store the pointer to `dyn Format`'s vtable, instead it statically resolves the function -/// pointer of `Format::format` and stores it in `formatter`. +/// A convenience wrapper for representing a formattable argument. pub struct Argument<'fmt, Context> { - /// The value to format stored as a raw pointer where `lifetime` stores the value's lifetime. - value: *const c_void, - - /// Stores the lifetime of the value. To get the most out of our dear borrow checker. - lifetime: PhantomData<&'fmt ()>, - - /// The function pointer to `value`'s `Format::format` method - formatter: fn(*const c_void, &mut Formatter<'_, Context>) -> FormatResult<()>, + value: &'fmt dyn Format, } impl Clone for Argument<'_, Context> { @@ -28,32 +14,19 @@ impl Clone for Argument<'_, Context> { impl Copy for Argument<'_, Context> {} impl<'fmt, Context> Argument<'fmt, Context> { - /// Called by the [ruff_formatter::format_args] macro. Creates a mono-morphed value for formatting - /// an object. + /// Called by the [ruff_formatter::format_args] macro. #[doc(hidden)] #[inline] pub fn new>(value: &'fmt F) -> Self { - #[inline] - fn formatter, Context>( - ptr: *const c_void, - fmt: &mut Formatter, - ) -> FormatResult<()> { - // SAFETY: Safe because the 'fmt lifetime is captured by the 'lifetime' field. - #[allow(unsafe_code)] - F::fmt(unsafe { &*ptr.cast::() }, fmt) - } - - Self { - value: (value as *const F).cast::(), - lifetime: PhantomData, - formatter: formatter::, - } + Self { value } } /// Formats the value stored by this argument using the given formatter. #[inline] + // Seems to only be triggered on wasm32 and looks like a false positive? + #[allow(clippy::trivially_copy_pass_by_ref)] pub(super) fn format(&self, f: &mut Formatter) -> FormatResult<()> { - (self.formatter)(self.value, f) + self.value.fmt(f) } } diff --git a/crates/ruff_formatter/src/builders.rs b/crates/ruff_formatter/src/builders.rs index 7eadba123a207..fdf87e6327daf 100644 --- a/crates/ruff_formatter/src/builders.rs +++ b/crates/ruff_formatter/src/builders.rs @@ -2555,17 +2555,17 @@ pub struct BestFitting<'a, Context> { } impl<'a, Context> BestFitting<'a, Context> { - /// Creates a new best fitting IR with the given variants. The method itself isn't unsafe - /// but it is to discourage people from using it because the printer will panic if - /// the slice doesn't contain at least the least and most expanded variants. + /// Creates a new best fitting IR with the given variants. + /// + /// Callers are required to ensure that the number of variants given + /// is at least 2. /// /// You're looking for a way to create a `BestFitting` object, use the `best_fitting![least_expanded, most_expanded]` macro. /// - /// ## Safety - - /// The slice must contain at least two variants. - #[allow(unsafe_code)] - pub unsafe fn from_arguments_unchecked(variants: Arguments<'a, Context>) -> Self { + /// # Panics + /// + /// When the slice contains less than two variants. + pub fn from_arguments_unchecked(variants: Arguments<'a, Context>) -> Self { assert!( variants.0.len() >= 2, "Requires at least the least expanded and most expanded variants" @@ -2696,14 +2696,12 @@ impl Format for BestFitting<'_, Context> { buffer.write_element(FormatElement::Tag(EndBestFittingEntry)); } - // SAFETY: The constructor guarantees that there are always at least two variants. It's, therefore, - // safe to call into the unsafe `from_vec_unchecked` function - #[allow(unsafe_code)] - let element = unsafe { - FormatElement::BestFitting { - variants: BestFittingVariants::from_vec_unchecked(buffer.into_vec()), - mode: self.mode, - } + // OK because the constructor guarantees that there are always at + // least two variants. + let variants = BestFittingVariants::from_vec_unchecked(buffer.into_vec()); + let element = FormatElement::BestFitting { + variants, + mode: self.mode, }; f.write_element(element); diff --git a/crates/ruff_formatter/src/format_element.rs b/crates/ruff_formatter/src/format_element.rs index f9fe281df3fde..0adcf7dda4338 100644 --- a/crates/ruff_formatter/src/format_element.rs +++ b/crates/ruff_formatter/src/format_element.rs @@ -332,17 +332,14 @@ pub enum BestFittingMode { pub struct BestFittingVariants(Box<[FormatElement]>); impl BestFittingVariants { - /// Creates a new best fitting IR with the given variants. The method itself isn't unsafe - /// but it is to discourage people from using it because the printer will panic if - /// the slice doesn't contain at least the least and most expanded variants. + /// Creates a new best fitting IR with the given variants. /// - /// You're looking for a way to create a `BestFitting` object, use the `best_fitting![least_expanded, most_expanded]` macro. + /// Callers are required to ensure that the number of variants given + /// is at least 2 when using `most_expanded` or `most_flag`. /// - /// ## Safety - /// The slice must contain at least two variants. + /// You're looking for a way to create a `BestFitting` object, use the `best_fitting![least_expanded, most_expanded]` macro. #[doc(hidden)] - #[allow(unsafe_code)] - pub unsafe fn from_vec_unchecked(variants: Vec) -> Self { + pub fn from_vec_unchecked(variants: Vec) -> Self { debug_assert!( variants .iter() @@ -351,12 +348,23 @@ impl BestFittingVariants { >= 2, "Requires at least the least expanded and most expanded variants" ); - Self(variants.into_boxed_slice()) } /// Returns the most expanded variant + /// + /// # Panics + /// + /// When the number of variants is less than two. pub fn most_expanded(&self) -> &[FormatElement] { + assert!( + self.as_slice() + .iter() + .filter(|element| matches!(element, FormatElement::Tag(Tag::StartBestFittingEntry))) + .count() + >= 2, + "Requires at least the least expanded and most expanded variants" + ); self.into_iter().last().unwrap() } @@ -365,7 +373,19 @@ impl BestFittingVariants { } /// Returns the least expanded variant + /// + /// # Panics + /// + /// When the number of variants is less than two. pub fn most_flat(&self) -> &[FormatElement] { + assert!( + self.as_slice() + .iter() + .filter(|element| matches!(element, FormatElement::Tag(Tag::StartBestFittingEntry))) + .count() + >= 2, + "Requires at least the least expanded and most expanded variants" + ); self.into_iter().next().unwrap() } } diff --git a/crates/ruff_formatter/src/macros.rs b/crates/ruff_formatter/src/macros.rs index 97a4cc696115d..2e327739a9091 100644 --- a/crates/ruff_formatter/src/macros.rs +++ b/crates/ruff_formatter/src/macros.rs @@ -329,10 +329,8 @@ macro_rules! format { #[macro_export] macro_rules! best_fitting { ($least_expanded:expr, $($tail:expr),+ $(,)?) => {{ - #[allow(unsafe_code)] - unsafe { - $crate::BestFitting::from_arguments_unchecked($crate::format_args!($least_expanded, $($tail),+)) - } + // OK because the macro syntax requires at least two variants. + $crate::BestFitting::from_arguments_unchecked($crate::format_args!($least_expanded, $($tail),+)) }} } diff --git a/crates/ruff_macros/src/newtype_index.rs b/crates/ruff_macros/src/newtype_index.rs index 2c1f6e14eca05..4ddc76c2e6838 100644 --- a/crates/ruff_macros/src/newtype_index.rs +++ b/crates/ruff_macros/src/newtype_index.rs @@ -45,6 +45,9 @@ pub(super) fn generate_newtype_index(item: ItemStruct) -> syn::Result syn::Result Self { assert!(value < u32::MAX as usize); - // SAFETY: + // OK because: // * The `value < u32::MAX` guarantees that the add doesn't overflow. // * The `+ 1` guarantees that the index is not zero - #[allow(unsafe_code, clippy::cast_possible_truncation)] - Self(unsafe { std::num::NonZeroU32::new_unchecked((value as u32) + 1) }) + #[allow(clippy::cast_possible_truncation)] + Self(std::num::NonZeroU32::new((value as u32) + 1).expect("valid value")) } fn value(self) -> usize { diff --git a/crates/ruff_python_formatter/src/expression/binary_like.rs b/crates/ruff_python_formatter/src/expression/binary_like.rs index f77851e395cb5..6c88db34f6e0f 100644 --- a/crates/ruff_python_formatter/src/expression/binary_like.rs +++ b/crates/ruff_python_formatter/src/expression/binary_like.rs @@ -1105,9 +1105,8 @@ impl OperatorIndex { fn new(index: usize) -> Self { assert_eq!(index % 2, 1, "Operator indices must be odd positions"); - // SAFETY A value with a module 0 is guaranteed to never equal 0 - #[allow(unsafe_code)] - Self(unsafe { NonZeroUsize::new_unchecked(index) }) + // OK because a value with a modulo 1 is guaranteed to never equal 0 + Self(NonZeroUsize::new(index).expect("valid index")) } const fn value(self) -> usize { diff --git a/crates/ruff_python_literal/src/escape.rs b/crates/ruff_python_literal/src/escape.rs index 01de325f102d7..1894bbff952af 100644 --- a/crates/ruff_python_literal/src/escape.rs +++ b/crates/ruff_python_literal/src/escape.rs @@ -415,12 +415,10 @@ impl<'a> Escape for AsciiEscape<'a> { fn layout(&self) -> &EscapeLayout { &self.layout } - #[allow(unsafe_code)] fn write_source(&self, formatter: &mut impl std::fmt::Write) -> std::fmt::Result { - formatter.write_str(unsafe { - // SAFETY: this function must be called only when source is printable ascii characters - std::str::from_utf8_unchecked(self.source) - }) + // OK because function must be called only when source is printable ascii characters. + let string = std::str::from_utf8(self.source).expect("ASCII bytes"); + formatter.write_str(string) } #[cold] diff --git a/crates/ruff_python_parser/src/string.rs b/crates/ruff_python_parser/src/string.rs index 2d64e66bd2ec4..2d4f2c5df926a 100644 --- a/crates/ruff_python_parser/src/string.rs +++ b/crates/ruff_python_parser/src/string.rs @@ -120,10 +120,8 @@ impl<'a> StringParser<'a> { len += 1; } - // SAFETY: radix_bytes is always going to be in the ASCII range. - #[allow(unsafe_code)] - let radix_str = unsafe { std::str::from_utf8_unchecked(&radix_bytes[..len]) }; - + // OK because radix_bytes is always going to be in the ASCII range. + let radix_str = std::str::from_utf8(&radix_bytes[..len]).expect("ASCII bytes"); let value = u32::from_str_radix(radix_str, 8).unwrap(); char::from_u32(value).unwrap() } diff --git a/crates/ruff_source_file/src/newlines.rs b/crates/ruff_source_file/src/newlines.rs index 6a79878fe4399..4e4d4e09a4a3e 100644 --- a/crates/ruff_source_file/src/newlines.rs +++ b/crates/ruff_source_file/src/newlines.rs @@ -58,11 +58,7 @@ impl<'a> UniversalNewlineIterator<'a> { pub fn find_newline(text: &str) -> Option<(usize, LineEnding)> { let bytes = text.as_bytes(); if let Some(position) = memchr2(b'\n', b'\r', bytes) { - // SAFETY: memchr guarantees to return valid positions - #[allow(unsafe_code)] - let newline_character = unsafe { *bytes.get_unchecked(position) }; - - let line_ending = match newline_character { + let line_ending = match bytes[position] { // Explicit branch for `\n` as this is the most likely path b'\n' => LineEnding::Lf, // '\r\n' From 9dee1883ce8e8271af81603c24b3bfc861389eff Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Tue, 28 Nov 2023 14:27:35 -0600 Subject: [PATCH 048/197] Update `ruff-dev` to use `SourceKind` (#8878) Just a small quality of life improvement to be able to pass in the Jupyter Notebook to `ruff-dev` CLI. --- crates/ruff_dev/src/print_ast.rs | 28 ++++++++++++++++------------ crates/ruff_dev/src/print_tokens.rs | 24 ++++++++++++------------ 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/crates/ruff_dev/src/print_ast.rs b/crates/ruff_dev/src/print_ast.rs index eddf8f9d05609..c4ddd97338cb4 100644 --- a/crates/ruff_dev/src/print_ast.rs +++ b/crates/ruff_dev/src/print_ast.rs @@ -1,30 +1,34 @@ //! Print the AST for a given Python file. #![allow(clippy::print_stdout, clippy::print_stderr)] -use std::fs; use std::path::PathBuf; use anyhow::Result; -use ruff_python_parser::{parse, Mode}; + +use ruff_linter::source_kind::SourceKind; +use ruff_python_ast::PySourceType; +use ruff_python_parser::{parse, AsMode}; #[derive(clap::Args)] pub(crate) struct Args { /// Python file for which to generate the AST. #[arg(required = true)] file: PathBuf, - /// Run in Jupyter mode i.e., allow line magics. - #[arg(long)] - jupyter: bool, } pub(crate) fn main(args: &Args) -> Result<()> { - let contents = fs::read_to_string(&args.file)?; - let mode = if args.jupyter { - Mode::Ipython - } else { - Mode::Module - }; - let python_ast = parse(&contents, mode, &args.file.to_string_lossy())?; + let source_type = PySourceType::from(&args.file); + let source_kind = SourceKind::from_path(&args.file, source_type)?.ok_or_else(|| { + anyhow::anyhow!( + "Could not determine source kind for file: {}", + args.file.display() + ) + })?; + let python_ast = parse( + source_kind.source_code(), + source_type.as_mode(), + &args.file.to_string_lossy(), + )?; println!("{python_ast:#?}"); Ok(()) } diff --git a/crates/ruff_dev/src/print_tokens.rs b/crates/ruff_dev/src/print_tokens.rs index 1498ee81a5fd7..a36f9a2c60f49 100644 --- a/crates/ruff_dev/src/print_tokens.rs +++ b/crates/ruff_dev/src/print_tokens.rs @@ -1,30 +1,30 @@ //! Print the token stream for a given Python file. #![allow(clippy::print_stdout, clippy::print_stderr)] -use std::fs; use std::path::PathBuf; use anyhow::Result; -use ruff_python_parser::{lexer, Mode}; + +use ruff_linter::source_kind::SourceKind; +use ruff_python_ast::PySourceType; +use ruff_python_parser::{lexer, AsMode}; #[derive(clap::Args)] pub(crate) struct Args { /// Python file for which to generate the AST. #[arg(required = true)] file: PathBuf, - /// Run in Jupyter mode i.e., allow line magics (`%`, `!`, `?`, `/`, `,`, `;`). - #[arg(long)] - jupyter: bool, } pub(crate) fn main(args: &Args) -> Result<()> { - let contents = fs::read_to_string(&args.file)?; - let mode = if args.jupyter { - Mode::Ipython - } else { - Mode::Module - }; - for (tok, range) in lexer::lex(&contents, mode).flatten() { + let source_type = PySourceType::from(&args.file); + let source_kind = SourceKind::from_path(&args.file, source_type)?.ok_or_else(|| { + anyhow::anyhow!( + "Could not determine source kind for file: {}", + args.file.display() + ) + })?; + for (tok, range) in lexer::lex(source_kind.source_code(), source_type.as_mode()).flatten() { println!( "{start:#?} {tok:#?} {end:#?}", start = range.start(), From 47d80f29a7bb4f9fdf7153b112f4b5fde6b45a14 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Tue, 28 Nov 2023 14:38:25 -0600 Subject: [PATCH 049/197] Lexer start of line is false only for `Mode::Expression` (#8880) ## Summary This PR fixes the bug in the lexer where the `Mode::Ipython` wasn't being considered when initializing the soft keyword transformer which wraps the lexer. This means that if the source code starts with either `match` or `type` keyword, then the keywords were being considered as name tokens instead. For example, ```python match foo: case bar: pass ``` This would transform the `match` keyword into an identifier if the mode is `Ipython`. The fix is to reverse the condition in the soft keyword initializer so that any new modes are by default considered as the lexer being at start of line. ## Test Plan Add a new test case for `Mode::Ipython` and verify the snapshot. fixes: #8870 --- crates/ruff_python_parser/src/lexer.rs | 8 +++ ..._tests__match_softkeyword_in_notebook.snap | 66 +++++++++++++++++++ .../ruff_python_parser/src/soft_keywords.rs | 2 +- 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 crates/ruff_python_parser/src/snapshots/ruff_python_parser__lexer__tests__match_softkeyword_in_notebook.snap diff --git a/crates/ruff_python_parser/src/lexer.rs b/crates/ruff_python_parser/src/lexer.rs index 2ce3d17c8e449..3831bc28d0315 100644 --- a/crates/ruff_python_parser/src/lexer.rs +++ b/crates/ruff_python_parser/src/lexer.rs @@ -2160,6 +2160,14 @@ f"{(lambda x:{x})}" assert_debug_snapshot!(lex_source(source)); } + #[test] + fn test_match_softkeyword_in_notebook() { + let source = r"match foo: + case bar: + pass"; + assert_debug_snapshot!(lex_jupyter_source(source)); + } + fn lex_fstring_error(source: &str) -> FStringErrorType { match lex(source, Mode::Module).find_map(std::result::Result::err) { Some(err) => match err.error { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__lexer__tests__match_softkeyword_in_notebook.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__lexer__tests__match_softkeyword_in_notebook.snap new file mode 100644 index 0000000000000..0512714bd466a --- /dev/null +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__lexer__tests__match_softkeyword_in_notebook.snap @@ -0,0 +1,66 @@ +--- +source: crates/ruff_python_parser/src/lexer.rs +expression: lex_jupyter_source(source) +--- +[ + ( + Match, + 0..5, + ), + ( + Name { + name: "foo", + }, + 6..9, + ), + ( + Colon, + 9..10, + ), + ( + Newline, + 10..11, + ), + ( + Indent, + 11..15, + ), + ( + Case, + 15..19, + ), + ( + Name { + name: "bar", + }, + 20..23, + ), + ( + Colon, + 23..24, + ), + ( + Newline, + 24..25, + ), + ( + Indent, + 25..33, + ), + ( + Pass, + 33..37, + ), + ( + Newline, + 37..37, + ), + ( + Dedent, + 37..37, + ), + ( + Dedent, + 37..37, + ), +] diff --git a/crates/ruff_python_parser/src/soft_keywords.rs b/crates/ruff_python_parser/src/soft_keywords.rs index f7aab9c1137a6..6d14dc7f37d72 100644 --- a/crates/ruff_python_parser/src/soft_keywords.rs +++ b/crates/ruff_python_parser/src/soft_keywords.rs @@ -31,7 +31,7 @@ where pub fn new(lexer: I, mode: Mode) -> Self { Self { underlying: lexer.multipeek(), // spell-checker:ignore multipeek - start_of_line: matches!(mode, Mode::Module), + start_of_line: !matches!(mode, Mode::Expression), } } } From 412688826c4bf9cfa68177fbe3e3f8119749fb59 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 28 Nov 2023 13:10:42 -0800 Subject: [PATCH 050/197] Avoid filtering out un-representable types in return annotation (#8881) ## Summary Given `Union[Dict, None]` (in our internal representation), we were filtering out `Dict` since we treat it as un-representable (i.e., we can't convert it to an expression), returning just `None` as the type annotation. We should require that all members of the union are representable. Closes https://github.com/astral-sh/ruff/issues/8879. --- .../flake8_annotations/auto_return_type.py | 17 +++++++++ .../src/rules/flake8_annotations/helpers.rs | 4 +- ..._annotations__tests__auto_return_type.snap | 38 +++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py b/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py index b7d58a6f94302..32d0cc2094523 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py @@ -30,3 +30,20 @@ def func(x: int): def func(x: int): return 1 + 2.5 if x > 0 else 1.5 or "str" + + +def func(x: int): + if not x: + return None + return {"foo": 1} + + +def func(x: int): + return {"foo": 1} + + +def func(): + if not x: + return 1 + else: + return True diff --git a/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs b/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs index 318ebf053fac9..8308d9a06569a 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs @@ -74,8 +74,8 @@ pub(crate) fn auto_return_type( let names = python_types .iter() .sorted_unstable() - .filter_map(|python_type| type_expr(*python_type)) - .collect::>(); + .map(|python_type| type_expr(*python_type)) + .collect::>>()?; // Wrap in a bitwise union (e.g., `int | float`). Some(pep_604_union(&names)) diff --git a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap index 108a1483004c7..c5508c652a894 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap +++ b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap @@ -123,5 +123,43 @@ auto_return_type.py:31:5: ANN201 [*] Missing return type annotation for public f 31 |-def func(x: int): 31 |+def func(x: int) -> str | float: 32 32 | return 1 + 2.5 if x > 0 else 1.5 or "str" +33 33 | +34 34 | + +auto_return_type.py:35:5: ANN201 Missing return type annotation for public function `func` + | +35 | def func(x: int): + | ^^^^ ANN201 +36 | if not x: +37 | return None + | + = help: Add return type annotation + +auto_return_type.py:41:5: ANN201 Missing return type annotation for public function `func` + | +41 | def func(x: int): + | ^^^^ ANN201 +42 | return {"foo": 1} + | + = help: Add return type annotation + +auto_return_type.py:45:5: ANN201 [*] Missing return type annotation for public function `func` + | +45 | def func(): + | ^^^^ ANN201 +46 | if not x: +47 | return 1 + | + = help: Add return type annotation: `int` + +ℹ Unsafe fix +42 42 | return {"foo": 1} +43 43 | +44 44 | +45 |-def func(): + 45 |+def func() -> int: +46 46 | if not x: +47 47 | return 1 +48 48 | else: From 5d554edace07447bffffd6325bdbed8ba8ca609b Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 28 Nov 2023 13:42:31 -0800 Subject: [PATCH 051/197] Allow booleans in `@override` methods (#8882) Closes #8867. --- .../test/fixtures/flake8_boolean_trap/FBT.py | 8 ++++++ ...olean_default_value_positional_argument.rs | 24 ++++++++++++----- .../boolean_type_hint_positional_argument.rs | 26 ++++++++++++++----- 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_boolean_trap/FBT.py b/crates/ruff_linter/resources/test/fixtures/flake8_boolean_trap/FBT.py index 58dcb4b5164b5..2c48a7d629fda 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_boolean_trap/FBT.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_boolean_trap/FBT.py @@ -106,3 +106,11 @@ def func(x: bool | str): def func(x: int | str): pass + + +from typing import override + + +@override +def func(x: bool): + pass diff --git a/crates/ruff_linter/src/rules/flake8_boolean_trap/rules/boolean_default_value_positional_argument.rs b/crates/ruff_linter/src/rules/flake8_boolean_trap/rules/boolean_default_value_positional_argument.rs index 3a3618fa4d588..61134cd316b32 100644 --- a/crates/ruff_linter/src/rules/flake8_boolean_trap/rules/boolean_default_value_positional_argument.rs +++ b/crates/ruff_linter/src/rules/flake8_boolean_trap/rules/boolean_default_value_positional_argument.rs @@ -2,6 +2,7 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::call_path::collect_call_path; use ruff_python_ast::{Decorator, ParameterWithDefault, Parameters}; +use ruff_python_semantic::analyze::visibility; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -94,23 +95,18 @@ impl Violation for BooleanDefaultValuePositionalArgument { } } +/// FBT002 pub(crate) fn boolean_default_value_positional_argument( checker: &mut Checker, name: &str, decorator_list: &[Decorator], parameters: &Parameters, ) { + // Allow Boolean defaults in explicitly-allowed functions. if is_allowed_func_def(name) { return; } - if decorator_list.iter().any(|decorator| { - collect_call_path(&decorator.expression) - .is_some_and(|call_path| call_path.as_slice() == [name, "setter"]) - }) { - return; - } - for ParameterWithDefault { parameter, default, @@ -121,6 +117,20 @@ pub(crate) fn boolean_default_value_positional_argument( .as_ref() .is_some_and(|default| default.is_boolean_literal_expr()) { + // Allow Boolean defaults in setters. + if decorator_list.iter().any(|decorator| { + collect_call_path(&decorator.expression) + .is_some_and(|call_path| call_path.as_slice() == [name, "setter"]) + }) { + return; + } + + // Allow Boolean defaults in `@override` methods, since they're required to adhere to + // the parent signature. + if visibility::is_override(decorator_list, checker.semantic()) { + return; + } + checker.diagnostics.push(Diagnostic::new( BooleanDefaultValuePositionalArgument, parameter.name.range(), diff --git a/crates/ruff_linter/src/rules/flake8_boolean_trap/rules/boolean_type_hint_positional_argument.rs b/crates/ruff_linter/src/rules/flake8_boolean_trap/rules/boolean_type_hint_positional_argument.rs index 1ba9a680d20fe..8cfefd02f8eac 100644 --- a/crates/ruff_linter/src/rules/flake8_boolean_trap/rules/boolean_type_hint_positional_argument.rs +++ b/crates/ruff_linter/src/rules/flake8_boolean_trap/rules/boolean_type_hint_positional_argument.rs @@ -4,6 +4,7 @@ use ruff_diagnostics::Diagnostic; use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::call_path::collect_call_path; +use ruff_python_semantic::analyze::visibility; use ruff_python_semantic::SemanticModel; use ruff_text_size::Ranged; @@ -109,17 +110,11 @@ pub(crate) fn boolean_type_hint_positional_argument( decorator_list: &[Decorator], parameters: &Parameters, ) { + // Allow Boolean type hints in explicitly-allowed functions. if is_allowed_func_def(name) { return; } - if decorator_list.iter().any(|decorator| { - collect_call_path(&decorator.expression) - .is_some_and(|call_path| call_path.as_slice() == [name, "setter"]) - }) { - return; - } - for ParameterWithDefault { parameter, default: _, @@ -138,9 +133,26 @@ pub(crate) fn boolean_type_hint_positional_argument( continue; } } + + // Allow Boolean type hints in setters. + if decorator_list.iter().any(|decorator| { + collect_call_path(&decorator.expression) + .is_some_and(|call_path| call_path.as_slice() == [name, "setter"]) + }) { + return; + } + + // Allow Boolean defaults in `@override` methods, since they're required to adhere to + // the parent signature. + if visibility::is_override(decorator_list, checker.semantic()) { + return; + } + + // If `bool` isn't actually a reference to the `bool` built-in, return. if !checker.semantic().is_builtin("bool") { return; } + checker.diagnostics.push(Diagnostic::new( BooleanTypeHintPositionalArgument, parameter.name.range(), From 4957d94beb2bed71312efa6f5e51bd3f71971b65 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Tue, 28 Nov 2023 18:43:07 -0500 Subject: [PATCH 052/197] ruff_python_formatter: small cleanups in doctest formatting (#8871) This PR contains a few small clean-ups that are responses to @MichaReiser's review of my #8811 PR. --- .../src/expression/string/docstring.rs | 14 ++++++++++---- .../ruff_python_formatter/tests/normalizer.rs | 19 ++++++++++++------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/crates/ruff_python_formatter/src/expression/string/docstring.rs b/crates/ruff_python_formatter/src/expression/string/docstring.rs index 8f1f335218f6d..21057e4645ceb 100644 --- a/crates/ruff_python_formatter/src/expression/string/docstring.rs +++ b/crates/ruff_python_formatter/src/expression/string/docstring.rs @@ -457,6 +457,10 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { #[derive(Clone, Debug)] struct DocstringLine<'src> { /// The actual text of the line, not including the line terminator. + /// + /// In practice, this line is borrowed when it corresponds to an original + /// unformatted line in a docstring, and owned when it corresponds to a + /// reformatted line (e.g., from a code snippet) in a docstring. line: Cow<'src, str>, /// The offset into the source document which this line corresponds to. offset: TextSize, @@ -561,8 +565,10 @@ enum CodeExampleKind { /// found as part of the Python standard library: /// https://docs.python.org/3/library/doctest.html. /// - /// (You'll likely need to read the regex matching used internally by the + /// (You'll likely need to read the [regex matching] used internally by the /// doctest module to determine more precisely how it works.) + /// + /// [regex matching]: https://github.com/python/cpython/blob/0ff6368519ed7542ad8b443de01108690102420a/Lib/doctest.py#L611-L622 Doctest(CodeExampleDoctest), } @@ -631,11 +637,11 @@ enum CodeExampleAddAction<'src> { /// /// This is guaranteed to be non-empty. code: Vec>, - /// When set, the line is considered not part of any code example - /// and should be formatted as if the `Ignore` action were returned. + /// When set, the line is considered not part of any code example and + /// should be formatted as if the [`Print`] action were returned. /// Otherwise, if there is no line, then either one does not exist /// or it is part of another code example and should be treated as a - /// `Kept` action. + /// [`Kept`] action. original: Option>, }, } diff --git a/crates/ruff_python_formatter/tests/normalizer.rs b/crates/ruff_python_formatter/tests/normalizer.rs index d6f6454ed397a..d0f2ba0b9c234 100644 --- a/crates/ruff_python_formatter/tests/normalizer.rs +++ b/crates/ruff_python_formatter/tests/normalizer.rs @@ -63,12 +63,14 @@ impl Transformer for Normalizer { static STRIP_CODE_SNIPPETS: Lazy = Lazy::new(|| { Regex::new( r#"(?mx) - # strip doctest PS1 prompt lines - ^\s*>>>\s.*(\n|$) - | - # strip doctest PS2 prompt lines - # Also handles the case of an empty ... line. - ^\s*\.\.\.((\n|$)|\s.*(\n|$)) + ( + # strip doctest PS1 prompt lines + ^\s*>>>\s.*(\n|$) + | + # strip doctest PS2 prompt lines + # Also handles the case of an empty ... line. + ^\s*\.\.\.((\n|$)|\s.*(\n|$)) + )+ "#, ) .unwrap() @@ -78,7 +80,10 @@ impl Transformer for Normalizer { // snippet, since code snippets may be completely reformatted if // they are Python code. string_literal.value = STRIP_CODE_SNIPPETS - .replace_all(&string_literal.value, "") + .replace_all( + &string_literal.value, + "\n", + ) .into_owned(); // Normalize a string by (2) stripping any leading and trailing space from each // line, and (3) removing any blank lines from the start and end of the string. From b28556d7397e6c81819df5d4b3cfa12b284f11bb Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Tue, 28 Nov 2023 18:32:35 -0600 Subject: [PATCH 053/197] Update `E402` to work at cell level for notebooks (#8872) ## Summary This PR updates the `E402` rule to work at cell level for Jupyter notebooks. This is enabled only in preview to gather feedback. The implementation basically resets the import boundary flag on the semantic model when we encounter the first statement in a cell. Another potential solution is to introduce `E403` rule that is specifically for notebooks that works at cell level while `E402` will be disabled for notebooks. ## Test Plan Add a notebook with imports in multiple cells and verify that the rule works as expected. resolves: #8669 --- .../test/fixtures/pycodestyle/E402.ipynb | 113 ++++++++++++++++++ crates/ruff_linter/src/checkers/ast/mod.rs | 16 +++ .../ruff_linter/src/rules/pycodestyle/mod.rs | 1 + .../src/rules/pycodestyle/rules/imports.rs | 24 ++-- ...__pycodestyle__tests__E402_E402.ipynb.snap | 29 +++++ crates/ruff_notebook/src/cell.rs | 28 ++++- crates/ruff_python_ast/src/lib.rs | 2 +- 7 files changed, 204 insertions(+), 9 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/pycodestyle/E402.ipynb create mode 100644 crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E402_E402.ipynb.snap diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E402.ipynb b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E402.ipynb new file mode 100644 index 0000000000000..9f9579e77e5dd --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E402.ipynb @@ -0,0 +1,113 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "33faf7ad-a3fd-4ac4-a0c3-52e507ed49df", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "\n", + "sys.path" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1331140f-2741-4661-9086-0764368710c9", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a4113383-725d-4f04-80b8-a3080b2b8c4b", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "os.path\n", + "\n", + "import pathlib" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5d2ef63-ae60-4311-bae3-42e845afba3f", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79599475-a5ee-4f60-80d1-6efa77693da0", + "metadata": {}, + "outputs": [], + "source": [ + "import a\n", + "\n", + "try:\n", + " import b\n", + "except ImportError:\n", + " pass\n", + "else:\n", + " pass\n", + "\n", + "__some__magic = 1\n", + "\n", + "import c" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "863dcc35-5c8d-4d05-8b4a-91059e944112", + "metadata": {}, + "outputs": [], + "source": [ + "import ok\n", + "\n", + "\n", + "def foo() -> None:\n", + " import e\n", + "\n", + "\n", + "import no_ok" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b2377d0-b814-4057-83ec-d443d8e19401", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (ruff-playground)", + "language": "python", + "name": "ruff-playground" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index bf0eba8e4fd86..e1b276936e5cf 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -107,6 +107,8 @@ pub(crate) struct Checker<'a> { pub(crate) diagnostics: Vec, /// The list of names already seen by flake8-bugbear diagnostics, to avoid duplicate violations.. pub(crate) flake8_bugbear_seen: Vec, + /// The end offset of the last visited statement. + last_stmt_end: TextSize, } impl<'a> Checker<'a> { @@ -142,6 +144,7 @@ impl<'a> Checker<'a> { diagnostics: Vec::default(), flake8_bugbear_seen: Vec::default(), cell_offsets, + last_stmt_end: TextSize::default(), } } } @@ -268,6 +271,18 @@ where // Step 0: Pre-processing self.semantic.push_node(stmt); + // For Jupyter Notebooks, we'll reset the `IMPORT_BOUNDARY` flag when + // we encounter a cell boundary. + if self.source_type.is_ipynb() + && self.semantic.at_top_level() + && self.semantic.seen_import_boundary() + && self.cell_offsets.is_some_and(|cell_offsets| { + cell_offsets.has_cell_boundary(TextRange::new(self.last_stmt_end, stmt.start())) + }) + { + self.semantic.flags -= SemanticModelFlags::IMPORT_BOUNDARY; + } + // Track whether we've seen docstrings, non-imports, etc. match stmt { Stmt::ImportFrom(ast::StmtImportFrom { module, names, .. }) => { @@ -779,6 +794,7 @@ where self.semantic.flags = flags_snapshot; self.semantic.pop_node(); + self.last_stmt_end = stmt.end(); } fn visit_annotation(&mut self, expr: &'b Expr) { diff --git a/crates/ruff_linter/src/rules/pycodestyle/mod.rs b/crates/ruff_linter/src/rules/pycodestyle/mod.rs index 112be16261155..b2a02f5e23c55 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/mod.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/mod.rs @@ -37,6 +37,7 @@ mod tests { #[test_case(Rule::MixedSpacesAndTabs, Path::new("E101.py"))] #[test_case(Rule::ModuleImportNotAtTopOfFile, Path::new("E40.py"))] #[test_case(Rule::ModuleImportNotAtTopOfFile, Path::new("E402.py"))] + #[test_case(Rule::ModuleImportNotAtTopOfFile, Path::new("E402.ipynb"))] #[test_case(Rule::MultipleImportsOnOneLine, Path::new("E40.py"))] #[test_case(Rule::MultipleStatementsOnOneLineColon, Path::new("E70.py"))] #[test_case(Rule::MultipleStatementsOnOneLineSemicolon, Path::new("E70.py"))] diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/imports.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/imports.rs index 4a037d7d0d438..443e044498b75 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/imports.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/imports.rs @@ -1,6 +1,6 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{Alias, Stmt}; +use ruff_python_ast::{Alias, PySourceType, Stmt}; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -34,7 +34,8 @@ impl Violation for MultipleImportsOnOneLine { } /// ## What it does -/// Checks for imports that are not at the top of the file. +/// Checks for imports that are not at the top of the file. For Jupyter notebooks, this +/// checks for imports that are not at the top of the cell. /// /// ## Why is this bad? /// According to [PEP 8], "imports are always put at the top of the file, just after any @@ -61,12 +62,18 @@ impl Violation for MultipleImportsOnOneLine { /// /// [PEP 8]: https://peps.python.org/pep-0008/#imports #[violation] -pub struct ModuleImportNotAtTopOfFile; +pub struct ModuleImportNotAtTopOfFile { + source_type: PySourceType, +} impl Violation for ModuleImportNotAtTopOfFile { #[derive_message_formats] fn message(&self) -> String { - format!("Module level import not at top of file") + if self.source_type.is_ipynb() { + format!("Module level import not at top of cell") + } else { + format!("Module level import not at top of file") + } } } @@ -82,8 +89,11 @@ pub(crate) fn multiple_imports_on_one_line(checker: &mut Checker, stmt: &Stmt, n /// E402 pub(crate) fn module_import_not_at_top_of_file(checker: &mut Checker, stmt: &Stmt) { if checker.semantic().seen_import_boundary() && checker.semantic().at_top_level() { - checker - .diagnostics - .push(Diagnostic::new(ModuleImportNotAtTopOfFile, stmt.range())); + checker.diagnostics.push(Diagnostic::new( + ModuleImportNotAtTopOfFile { + source_type: checker.source_type, + }, + stmt.range(), + )); } } diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E402_E402.ipynb.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E402_E402.ipynb.snap new file mode 100644 index 0000000000000..70562983d36e0 --- /dev/null +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E402_E402.ipynb.snap @@ -0,0 +1,29 @@ +--- +source: crates/ruff_linter/src/rules/pycodestyle/mod.rs +--- +E402.ipynb:9:1: E402 Module level import not at top of cell + | + 7 | os.path + 8 | + 9 | import pathlib + | ^^^^^^^^^^^^^^ E402 +10 | +11 | import a + | + +E402.ipynb:22:1: E402 Module level import not at top of cell + | +20 | __some__magic = 1 +21 | +22 | import c + | ^^^^^^^^ E402 +23 | import ok + | + +E402.ipynb:30:1: E402 Module level import not at top of cell + | +30 | import no_ok + | ^^^^^^^^^^^^ E402 + | + + diff --git a/crates/ruff_notebook/src/cell.rs b/crates/ruff_notebook/src/cell.rs index 1d039e7a67483..d80ef336de02e 100644 --- a/crates/ruff_notebook/src/cell.rs +++ b/crates/ruff_notebook/src/cell.rs @@ -175,7 +175,7 @@ impl Cell { } /// Cell offsets are used to keep track of the start and end offsets of each -/// cell in the concatenated source code. +/// cell in the concatenated source code. These offsets are in sorted order. #[derive(Clone, Debug, Default, PartialEq)] pub struct CellOffsets(Vec); @@ -186,7 +186,17 @@ impl CellOffsets { } /// Push a new offset to the end of the [`CellOffsets`]. + /// + /// # Panics + /// + /// Panics if the offset is less than the last offset pushed. pub(crate) fn push(&mut self, offset: TextSize) { + if let Some(last_offset) = self.0.last() { + assert!( + *last_offset <= offset, + "Offsets must be pushed in sorted order" + ); + } self.0.push(offset); } @@ -200,6 +210,22 @@ impl CellOffsets { } }) } + + /// Returns `true` if the given range contains a cell boundary. + pub fn has_cell_boundary(&self, range: TextRange) -> bool { + self.binary_search_by(|offset| { + if range.start() <= *offset { + if range.end() < *offset { + std::cmp::Ordering::Greater + } else { + std::cmp::Ordering::Equal + } + } else { + std::cmp::Ordering::Less + } + }) + .is_ok() + } } impl Deref for CellOffsets { diff --git a/crates/ruff_python_ast/src/lib.rs b/crates/ruff_python_ast/src/lib.rs index 210e287eed372..1fb53dc8c7bf6 100644 --- a/crates/ruff_python_ast/src/lib.rs +++ b/crates/ruff_python_ast/src/lib.rs @@ -68,7 +68,7 @@ pub enum TomlSourceType { Unrecognized, } -#[derive(Clone, Copy, Debug, Default, PartialEq, is_macro::Is)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, is_macro::Is)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum PySourceType { /// The source is a Python file (`.py`). From ec7456bac049d1d4f4763f8c7ad764d27dd383bd Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Tue, 28 Nov 2023 18:50:42 -0600 Subject: [PATCH 054/197] Rename `as_str` to `to_str` (#8886) This PR renames the method on `StringLiteralValue` from `as_str` to `to_str`. The main motivation is to follow the naming convention as described in the [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv). This method can perform a string allocation in case the string is implicitly concatenated. --- .../src/checkers/ast/analyze/expression.rs | 8 ++++---- crates/ruff_linter/src/checkers/ast/mod.rs | 4 ++-- .../src/rules/flake8_annotations/rules/definition.rs | 2 +- .../ruff_linter/src/rules/flake8_bandit/helpers.rs | 2 +- .../rules/hardcoded_bind_all_interfaces.rs | 2 +- .../flake8_bandit/rules/hardcoded_password_string.rs | 2 +- .../flake8_bandit/rules/hardcoded_sql_expression.rs | 4 ++-- .../flake8_bandit/rules/hardcoded_tmp_directory.rs | 2 +- .../flake8_bandit/rules/suspicious_function_call.rs | 2 +- .../flake8_bandit/rules/tarfile_unsafe_members.rs | 2 +- .../flake8_bugbear/rules/getattr_with_constant.rs | 4 ++-- .../flake8_bugbear/rules/setattr_with_constant.rs | 6 +++--- .../rules/call_datetime_strptime_without_zone.rs | 2 +- .../flake8_logging_format/rules/logging_call.rs | 2 +- .../flake8_pie/rules/unnecessary_dict_kwargs.rs | 4 ++-- .../rules/flake8_pyi/rules/unrecognized_platform.rs | 2 +- .../rules/flake8_pytest_style/rules/parametrize.rs | 6 +++--- .../src/rules/flake8_simplify/rules/ast_expr.rs | 12 ++++++------ .../rules/path_constructor_current_directory.rs | 2 +- .../src/rules/flynt/rules/static_join_to_fstring.rs | 2 +- .../ruff_linter/src/rules/pyflakes/rules/strings.rs | 6 +++--- crates/ruff_linter/src/rules/pylint/helpers.rs | 2 +- .../src/rules/pylint/rules/bad_string_format_type.rs | 2 +- crates/ruff_linter/src/rules/pylint/rules/logging.rs | 2 +- .../src/rules/pylint/rules/magic_value_comparison.rs | 2 +- .../rules/pylint/rules/repeated_keyword_argument.rs | 2 +- .../rules/convert_named_tuple_functional_to_class.rs | 6 +++--- .../rules/convert_typed_dict_functional_to_class.rs | 6 +++--- .../pyupgrade/rules/printf_string_formatting.rs | 6 +++--- .../rules/pyupgrade/rules/redundant_open_modes.rs | 4 ++-- .../rules/pyupgrade/rules/unnecessary_encode_utf8.rs | 4 ++-- .../src/rules/refurb/rules/implicit_cwd.rs | 2 +- .../src/rules/refurb/rules/read_whole_file.rs | 2 +- .../src/rules/ruff/rules/implicit_optional.rs | 2 +- crates/ruff_linter/src/rules/ruff/typing.rs | 2 +- crates/ruff_python_ast/src/all.rs | 2 +- crates/ruff_python_ast/src/nodes.rs | 10 +++++----- crates/ruff_python_codegen/src/generator.rs | 2 +- 38 files changed, 68 insertions(+), 68 deletions(-) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index f3e8bbaecfe6e..7a158449bfcc1 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -380,13 +380,13 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { flynt::rules::static_join_to_fstring( checker, expr, - string_value.as_str(), + string_value.to_str(), ); } } else if attr == "format" { // "...".format(...) call let location = expr.range(); - match pyflakes::format::FormatSummary::try_from(string_value.as_str()) { + match pyflakes::format::FormatSummary::try_from(string_value.to_str()) { Err(e) => { if checker.enabled(Rule::StringDotFormatInvalidFormat) { checker.diagnostics.push(Diagnostic::new( @@ -432,7 +432,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::BadStringFormatCharacter) { pylint::rules::bad_string_format_character::call( checker, - string_value.as_str(), + string_value.to_str(), location, ); } @@ -1045,7 +1045,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { Rule::PercentFormatUnsupportedFormatCharacter, ]) { let location = expr.range(); - match pyflakes::cformat::CFormatSummary::try_from(value.as_str()) { + match pyflakes::cformat::CFormatSummary::try_from(value.to_str()) { Err(CFormatError { typ: CFormatErrorType::UnsupportedFormatChar(c), .. diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index e1b276936e5cf..d24154badb6f7 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -815,7 +815,7 @@ where if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = expr { self.deferred.string_type_definitions.push(( expr.range(), - value.as_str(), + value.to_str(), self.semantic.snapshot(), )); } else { @@ -1235,7 +1235,7 @@ where { self.deferred.string_type_definitions.push(( expr.range(), - value.as_str(), + value.to_str(), self.semantic.snapshot(), )); } diff --git a/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs b/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs index b1bfc9df67021..9acf52c8e8fef 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs +++ b/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs @@ -508,7 +508,7 @@ fn check_dynamically_typed( if let Expr::StringLiteral(ast::ExprStringLiteral { range, value }) = annotation { // Quoted annotations if let Ok((parsed_annotation, _)) = - parse_type_annotation(value.as_str(), *range, checker.locator().contents()) + parse_type_annotation(value.to_str(), *range, checker.locator().contents()) { if type_hint_resolves_to_any( &parsed_annotation, diff --git a/crates/ruff_linter/src/rules/flake8_bandit/helpers.rs b/crates/ruff_linter/src/rules/flake8_bandit/helpers.rs index ac1bfefe1a2fd..53ba6eddbfd4f 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/helpers.rs @@ -10,7 +10,7 @@ static PASSWORD_CANDIDATE_REGEX: Lazy = Lazy::new(|| { pub(super) fn string_literal(expr: &Expr) -> Option<&str> { match expr { - Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => Some(value.as_str()), + Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => Some(value.to_str()), _ => None, } } diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs index af96341a093cf..49b16b66cd7fa 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs @@ -35,7 +35,7 @@ impl Violation for HardcodedBindAllInterfaces { /// S104 pub(crate) fn hardcoded_bind_all_interfaces(string: &ExprStringLiteral) -> Option { - if string.value.as_str() == "0.0.0.0" { + if string.value.to_str() == "0.0.0.0" { Some(Diagnostic::new(HardcodedBindAllInterfaces, string.range)) } else { None diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_password_string.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_password_string.rs index 0509986804873..07cbea8c9fbc6 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_password_string.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_password_string.rs @@ -55,7 +55,7 @@ fn password_target(target: &Expr) -> Option<&str> { Expr::Name(ast::ExprName { id, .. }) => id.as_str(), // d["password"] = "s3cr3t" Expr::Subscript(ast::ExprSubscript { slice, .. }) => match slice.as_ref() { - Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => value.as_str(), + Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => value.to_str(), _ => return None, }, // obj.password = "s3cr3t" diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs index e132e806d8f06..25d0f3e7103d4 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs @@ -93,7 +93,7 @@ pub(crate) fn hardcoded_sql_expression(checker: &mut Checker, expr: &Expr) { let Some(string) = left.as_string_literal_expr() else { return; }; - string.value.as_str().escape_default().to_string() + string.value.to_str().escape_default().to_string() } Expr::Call(ast::ExprCall { func, .. }) => { let Expr::Attribute(ast::ExprAttribute { attr, value, .. }) = func.as_ref() else { @@ -106,7 +106,7 @@ pub(crate) fn hardcoded_sql_expression(checker: &mut Checker, expr: &Expr) { let Some(string) = value.as_string_literal_expr() else { return; }; - string.value.as_str().escape_default().to_string() + string.value.to_str().escape_default().to_string() } // f"select * from table where val = {val}" Expr::FString(f_string) => concatenated_f_string(f_string, checker.locator()), diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs index 9b5a913dd7a3f..09de15f20b91e 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs @@ -57,7 +57,7 @@ pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, string: &ast::ExprS .flake8_bandit .hardcoded_tmp_directory .iter() - .any(|prefix| string.value.as_str().starts_with(prefix)) + .any(|prefix| string.value.to_str().starts_with(prefix)) { return; } diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs index 46fbec7612be2..2589b9514f2dd 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs @@ -855,7 +855,7 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, call: &ExprCall) { // If the `url` argument is a string literal, allow `http` and `https` schemes. if call.arguments.args.iter().all(|arg| !arg.is_starred_expr()) && call.arguments.keywords.iter().all(|keyword| keyword.arg.is_some()) { if let Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) = &call.arguments.find_argument("url", 0) { - let url = value.as_str().trim_start(); + let url = value.to_str().trim_start(); if url.starts_with("http://") || url.starts_with("https://") { return None; } diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/tarfile_unsafe_members.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/tarfile_unsafe_members.rs index 1fd35e3c7ad35..b70083c8533c4 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/tarfile_unsafe_members.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/tarfile_unsafe_members.rs @@ -60,7 +60,7 @@ pub(crate) fn tarfile_unsafe_members(checker: &mut Checker, call: &ast::ExprCall .arguments .find_keyword("filter") .and_then(|keyword| keyword.value.as_string_literal_expr()) - .is_some_and(|value| matches!(value.value.as_str(), "data" | "tar")) + .is_some_and(|value| matches!(value.value.to_str(), "data" | "tar")) { return; } diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/getattr_with_constant.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/getattr_with_constant.rs index 66f563a234769..9ef089807f6e2 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/getattr_with_constant.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/getattr_with_constant.rs @@ -69,10 +69,10 @@ pub(crate) fn getattr_with_constant( let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = arg else { return; }; - if !is_identifier(value.as_str()) { + if !is_identifier(value.to_str()) { return; } - if is_mangled_private(value.as_str()) { + if is_mangled_private(value.to_str()) { return; } if !checker.semantic().is_builtin("getattr") { diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/setattr_with_constant.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/setattr_with_constant.rs index bc17ed3ffddd5..e31d0cdc1a781 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/setattr_with_constant.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/setattr_with_constant.rs @@ -83,10 +83,10 @@ pub(crate) fn setattr_with_constant( let Expr::StringLiteral(ast::ExprStringLiteral { value: name, .. }) = name else { return; }; - if !is_identifier(name.as_str()) { + if !is_identifier(name.to_str()) { return; } - if is_mangled_private(name.as_str()) { + if is_mangled_private(name.to_str()) { return; } if !checker.semantic().is_builtin("setattr") { @@ -104,7 +104,7 @@ pub(crate) fn setattr_with_constant( if expr == child.as_ref() { let mut diagnostic = Diagnostic::new(SetAttrWithConstant, expr.range()); diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - assignment(obj, name.as_str(), value, checker.generator()), + assignment(obj, name.to_str(), value, checker.generator()), expr.range(), ))); checker.diagnostics.push(diagnostic); diff --git a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs index 0a9fe6c0e7a55..8390fc9a7c969 100644 --- a/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs +++ b/crates/ruff_linter/src/rules/flake8_datetimez/rules/call_datetime_strptime_without_zone.rs @@ -78,7 +78,7 @@ pub(crate) fn call_datetime_strptime_without_zone(checker: &mut Checker, call: & if let Some(Expr::StringLiteral(ast::ExprStringLiteral { value: format, .. })) = call.arguments.args.get(1).as_ref() { - if format.as_str().contains("%z") { + if format.to_str().contains("%z") { return; } }; diff --git a/crates/ruff_linter/src/rules/flake8_logging_format/rules/logging_call.rs b/crates/ruff_linter/src/rules/flake8_logging_format/rules/logging_call.rs index db56255ff4df9..bd1e6399df596 100644 --- a/crates/ruff_linter/src/rules/flake8_logging_format/rules/logging_call.rs +++ b/crates/ruff_linter/src/rules/flake8_logging_format/rules/logging_call.rs @@ -93,7 +93,7 @@ fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) { for key in keys { if let Some(key) = &key { if let Expr::StringLiteral(ast::ExprStringLiteral { value: attr, .. }) = key { - if is_reserved_attr(attr.as_str()) { + if is_reserved_attr(attr.to_str()) { checker.diagnostics.push(Diagnostic::new( LoggingExtraAttrClash(attr.to_string()), key.range(), diff --git a/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs b/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs index fcf5707fe700a..c4625444f7bde 100644 --- a/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs +++ b/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs @@ -110,8 +110,8 @@ pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, expr: &Expr, kwargs /// Return `Some` if a key is a valid keyword argument name, or `None` otherwise. fn as_kwarg(key: &Expr) -> Option<&str> { if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = key { - if is_identifier(value.as_str()) { - return Some(value.as_str()); + if is_identifier(value.to_str()) { + return Some(value.to_str()); } } None diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/unrecognized_platform.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/unrecognized_platform.rs index c46ffa19e27b0..17c82b398a635 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/unrecognized_platform.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/unrecognized_platform.rs @@ -127,7 +127,7 @@ pub(crate) fn unrecognized_platform(checker: &mut Checker, test: &Expr) { // Other values are possible but we don't need them right now. // This protects against typos. if checker.enabled(Rule::UnrecognizedPlatformName) { - if !matches!(value.as_str(), "linux" | "win32" | "cygwin" | "darwin") { + if !matches!(value.to_str(), "linux" | "win32" | "cygwin" | "darwin") { checker.diagnostics.push(Diagnostic::new( UnrecognizedPlatformName { platform: value.to_string(), diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs index cead79a028412..c023674cdcf16 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs @@ -258,7 +258,7 @@ fn elts_to_csv(elts: &[Expr], generator: Generator) -> Option { if !acc.is_empty() { acc.push(','); } - acc.push_str(value.as_str()); + acc.push_str(value.to_str()); } acc }), @@ -301,7 +301,7 @@ fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) { match expr { Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { - let names = split_names(value.as_str()); + let names = split_names(value.to_str()); if names.len() > 1 { match names_type { types::ParametrizeNameType::Tuple => { @@ -476,7 +476,7 @@ fn check_values(checker: &mut Checker, names: &Expr, values: &Expr) { .parametrize_values_row_type; let is_multi_named = if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &names { - split_names(value.as_str()).len() > 1 + split_names(value.to_str()).len() > 1 } else { true }; diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_expr.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_expr.rs index 392b2507ce69e..5f2d278474cc2 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_expr.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/ast_expr.rs @@ -161,12 +161,12 @@ pub(crate) fn use_capital_environment_variables(checker: &mut Checker, expr: &Ex return; } - if is_lowercase_allowed(env_var.as_str()) { + if is_lowercase_allowed(env_var.to_str()) { return; } - let capital_env_var = env_var.as_str().to_ascii_uppercase(); - if capital_env_var == env_var.as_str() { + let capital_env_var = env_var.to_str().to_ascii_uppercase(); + if capital_env_var == env_var.to_str() { return; } @@ -201,12 +201,12 @@ fn check_os_environ_subscript(checker: &mut Checker, expr: &Expr) { return; }; - if is_lowercase_allowed(env_var.as_str()) { + if is_lowercase_allowed(env_var.to_str()) { return; } - let capital_env_var = env_var.as_str().to_ascii_uppercase(); - if capital_env_var == env_var.as_str() { + let capital_env_var = env_var.to_str().to_ascii_uppercase(); + if capital_env_var == env_var.to_str() { return; } diff --git a/crates/ruff_linter/src/rules/flake8_use_pathlib/rules/path_constructor_current_directory.rs b/crates/ruff_linter/src/rules/flake8_use_pathlib/rules/path_constructor_current_directory.rs index c4a31a47c1909..dc598dbb9f8ff 100644 --- a/crates/ruff_linter/src/rules/flake8_use_pathlib/rules/path_constructor_current_directory.rs +++ b/crates/ruff_linter/src/rules/flake8_use_pathlib/rules/path_constructor_current_directory.rs @@ -69,7 +69,7 @@ pub(crate) fn path_constructor_current_directory(checker: &mut Checker, expr: &E return; }; - if matches!(value.as_str(), "" | ".") { + if matches!(value.to_str(), "" | ".") { let mut diagnostic = Diagnostic::new(PathConstructorCurrentDirectory, *range); diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(*range))); checker.diagnostics.push(diagnostic); diff --git a/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs b/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs index 1704ca020c618..4f37fafe35994 100644 --- a/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs +++ b/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs @@ -67,7 +67,7 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option { .iter() .filter_map(|expr| { if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = expr { - Some(value.as_str()) + Some(value.to_str()) } else { None } diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs b/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs index 5aacba2f765dd..e4545e139b79f 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs @@ -583,10 +583,10 @@ pub(crate) fn percent_format_extra_named_arguments( .enumerate() .filter_map(|(index, key)| match key { Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) => { - if summary.keywords.contains(value.as_str()) { + if summary.keywords.contains(value.to_str()) { None } else { - Some((index, value.as_str())) + Some((index, value.to_str())) } } _ => None, @@ -641,7 +641,7 @@ pub(crate) fn percent_format_missing_arguments( for key in keys.iter().flatten() { match key { Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { - keywords.insert(value.as_str()); + keywords.insert(value.to_str()); } _ => { return; // Dynamic keys present diff --git a/crates/ruff_linter/src/rules/pylint/helpers.rs b/crates/ruff_linter/src/rules/pylint/helpers.rs index 562b5e2304b9b..027272d03c004 100644 --- a/crates/ruff_linter/src/rules/pylint/helpers.rs +++ b/crates/ruff_linter/src/rules/pylint/helpers.rs @@ -12,7 +12,7 @@ pub(super) fn type_param_name(arguments: &Arguments) -> Option<&str> { // Handle both `TypeVar("T")` and `TypeVar(name="T")`. let name_param = arguments.find_argument("name", 0)?; if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &name_param { - Some(value.as_str()) + Some(value.to_str()) } else { None } diff --git a/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_type.rs b/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_type.rs index 60b6b9bc5b05f..b41e4f59d9249 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_type.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_type.rs @@ -201,7 +201,7 @@ fn is_valid_dict( value: mapping_key, .. }) = key { - let Some(format) = formats_hash.get(mapping_key.as_str()) else { + let Some(format) = formats_hash.get(mapping_key.to_str()) else { return true; }; if !equivalent(format, value) { diff --git a/crates/ruff_linter/src/rules/pylint/rules/logging.rs b/crates/ruff_linter/src/rules/pylint/rules/logging.rs index 0765b5a4c7337..823bf8bdfcb7e 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/logging.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/logging.rs @@ -134,7 +134,7 @@ pub(crate) fn logging_call(checker: &mut Checker, call: &ast::ExprCall) { return; }; - let Ok(summary) = CFormatSummary::try_from(value.as_str()) else { + let Ok(summary) = CFormatSummary::try_from(value.to_str()) else { return; }; diff --git a/crates/ruff_linter/src/rules/pylint/rules/magic_value_comparison.rs b/crates/ruff_linter/src/rules/pylint/rules/magic_value_comparison.rs index c47f91ff62a2f..ad1309b317d98 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/magic_value_comparison.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/magic_value_comparison.rs @@ -83,7 +83,7 @@ fn is_magic_value(literal_expr: LiteralExpressionRef, allowed_types: &[ConstantT | LiteralExpressionRef::EllipsisLiteral(_) => false, // Special-case some common string and integer types. LiteralExpressionRef::StringLiteral(ast::ExprStringLiteral { value, .. }) => { - !matches!(value.as_str(), "" | "__main__") + !matches!(value.to_str(), "" | "__main__") } LiteralExpressionRef::NumberLiteral(ast::ExprNumberLiteral { value, .. }) => match value { ast::Number::Int(value) => !matches!(*value, Int::ZERO | Int::ONE), diff --git a/crates/ruff_linter/src/rules/pylint/rules/repeated_keyword_argument.rs b/crates/ruff_linter/src/rules/pylint/rules/repeated_keyword_argument.rs index f3a45e5694ae2..b65f8fd6b4ac9 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/repeated_keyword_argument.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/repeated_keyword_argument.rs @@ -60,7 +60,7 @@ pub(crate) fn repeated_keyword_argument(checker: &mut Checker, call: &ExprCall) // Ex) `func(**{"a": 1, "a": 2})` for key in keys.iter().flatten() { if let Expr::StringLiteral(ExprStringLiteral { value, .. }) = key { - if !seen.insert(value.as_str()) { + if !seen.insert(value.to_str()) { checker.diagnostics.push(Diagnostic::new( RepeatedKeywordArgument { duplicate_keyword: value.to_string(), diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs index 70e50d0c2288b..dcc6a01ab64c8 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs @@ -185,13 +185,13 @@ fn create_fields_from_fields_arg(fields: &Expr) -> Option> { return None; } let ast::ExprStringLiteral { value: field, .. } = field.as_string_literal_expr()?; - if !is_identifier(field.as_str()) { + if !is_identifier(field.to_str()) { return None; } - if is_dunder(field.as_str()) { + if is_dunder(field.to_str()) { return None; } - Some(create_field_assignment_stmt(field.as_str(), annotation)) + Some(create_field_assignment_stmt(field.to_str(), annotation)) }) .collect() } diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs index a61ac82245bfe..4f98f6e5fa365 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs @@ -174,13 +174,13 @@ fn fields_from_dict_literal(keys: &[Option], values: &[Expr]) -> Option { - if !is_identifier(field.as_str()) { + if !is_identifier(field.to_str()) { return None; } - if is_dunder(field.as_str()) { + if is_dunder(field.to_str()) { return None; } - Some(create_field_assignment_stmt(field.as_str(), value)) + Some(create_field_assignment_stmt(field.to_str(), value)) } _ => None, }) diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs index ec9cae1295734..576b0dacbcf91 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs @@ -228,14 +228,14 @@ fn clean_params_dictionary(right: &Expr, locator: &Locator, stylist: &Stylist) - }) = key { // If the dictionary key is not a valid variable name, abort. - if !is_identifier(key_string.as_str()) { + if !is_identifier(key_string.to_str()) { return None; } // If there are multiple entries of the same key, abort. - if seen.contains(&key_string.as_str()) { + if seen.contains(&key_string.to_str()) { return None; } - seen.push(key_string.as_str()); + seen.push(key_string.to_str()); if is_multi_line { if indent.is_none() { indent = indentation(locator, key); diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/redundant_open_modes.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/redundant_open_modes.rs index 7a87d03948d5b..2e9d63766e65b 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/redundant_open_modes.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/redundant_open_modes.rs @@ -76,7 +76,7 @@ pub(crate) fn redundant_open_modes(checker: &mut Checker, call: &ast::ExprCall) .. }) = &keyword.value { - if let Ok(mode) = OpenMode::from_str(mode_param_value.as_str()) { + if let Ok(mode) = OpenMode::from_str(mode_param_value.to_str()) { checker.diagnostics.push(create_check( call, &keyword.value, @@ -91,7 +91,7 @@ pub(crate) fn redundant_open_modes(checker: &mut Checker, call: &ast::ExprCall) } Some(mode_param) => { if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &mode_param { - if let Ok(mode) = OpenMode::from_str(value.as_str()) { + if let Ok(mode) = OpenMode::from_str(value.to_str()) { checker.diagnostics.push(create_check( call, mode_param, diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/unnecessary_encode_utf8.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/unnecessary_encode_utf8.rs index 1f9e5ff7ebc4f..4bb5dd82fb041 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/unnecessary_encode_utf8.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/unnecessary_encode_utf8.rs @@ -74,7 +74,7 @@ fn match_encoded_variable(func: &Expr) -> Option<&Expr> { fn is_utf8_encoding_arg(arg: &Expr) -> bool { if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &arg { - UTF8_LITERALS.contains(&value.as_str().to_lowercase().as_str()) + UTF8_LITERALS.contains(&value.to_str().to_lowercase().as_str()) } else { false } @@ -161,7 +161,7 @@ pub(crate) fn unnecessary_encode_utf8(checker: &mut Checker, call: &ast::ExprCal Expr::StringLiteral(ast::ExprStringLiteral { value: literal, .. }) => { // Ex) `"str".encode()`, `"str".encode("utf-8")` if let Some(encoding_arg) = match_encoding_arg(&call.arguments) { - if literal.as_str().is_ascii() { + if literal.to_str().is_ascii() { // Ex) Convert `"foo".encode()` to `b"foo"`. let mut diagnostic = Diagnostic::new( UnnecessaryEncodeUTF8 { diff --git a/crates/ruff_linter/src/rules/refurb/rules/implicit_cwd.rs b/crates/ruff_linter/src/rules/refurb/rules/implicit_cwd.rs index 3b14b62b78009..8b24c361ab200 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/implicit_cwd.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/implicit_cwd.rs @@ -66,7 +66,7 @@ pub(crate) fn no_implicit_cwd(checker: &mut Checker, call: &ExprCall) { let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = arg else { return; }; - if !matches!(value.as_str(), "" | ".") { + if !matches!(value.to_str(), "" | ".") { return; } } diff --git a/crates/ruff_linter/src/rules/refurb/rules/read_whole_file.rs b/crates/ruff_linter/src/rules/refurb/rules/read_whole_file.rs index f90f3d114f28b..8bf1e6b6bccfb 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/read_whole_file.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/read_whole_file.rs @@ -248,7 +248,7 @@ fn match_open_mode(mode: &Expr) -> Option { if value.is_implicit_concatenated() { return None; } - match value.as_str() { + match value.to_str() { "r" => Some(ReadMode::Text), "rb" => Some(ReadMode::Bytes), _ => None, diff --git a/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs b/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs index 36259cdc86076..c9e3b06e0df04 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs @@ -184,7 +184,7 @@ pub(crate) fn implicit_optional(checker: &mut Checker, parameters: &Parameters) if let Expr::StringLiteral(ast::ExprStringLiteral { range, value }) = annotation.as_ref() { // Quoted annotation. if let Ok((annotation, kind)) = - parse_type_annotation(value.as_str(), *range, checker.locator().contents()) + parse_type_annotation(value.to_str(), *range, checker.locator().contents()) { let Some(expr) = type_hint_explicitly_allows_none( &annotation, diff --git a/crates/ruff_linter/src/rules/ruff/typing.rs b/crates/ruff_linter/src/rules/ruff/typing.rs index de898ff285d16..f01e89c3fd0c2 100644 --- a/crates/ruff_linter/src/rules/ruff/typing.rs +++ b/crates/ruff_linter/src/rules/ruff/typing.rs @@ -109,7 +109,7 @@ impl<'a> TypingTarget<'a> { }) => Some(TypingTarget::PEP604Union(left, right)), Expr::NoneLiteral(_) => Some(TypingTarget::None), Expr::StringLiteral(ast::ExprStringLiteral { value, range }) => { - parse_type_annotation(value.as_str(), *range, locator.contents()) + parse_type_annotation(value.to_str(), *range, locator.contents()) .map_or(None, |(expr, _)| Some(TypingTarget::ForwardReference(expr))) } _ => semantic.resolve_call_path(expr).map_or( diff --git a/crates/ruff_python_ast/src/all.rs b/crates/ruff_python_ast/src/all.rs index 5ac523cf1b8cf..b55858d66fe84 100644 --- a/crates/ruff_python_ast/src/all.rs +++ b/crates/ruff_python_ast/src/all.rs @@ -24,7 +24,7 @@ where fn add_to_names<'a>(elts: &'a [Expr], names: &mut Vec<&'a str>, flags: &mut DunderAllFlags) { for elt in elts { if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = elt { - names.push(value.as_str()); + names.push(value.to_str()); } else { *flags |= DunderAllFlags::INVALID_OBJECT; } diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index 23faaa9419939..eaf9881a3706c 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -1233,10 +1233,10 @@ impl StringLiteralValue { /// /// Note that this will perform an allocation on the first invocation if the /// string value is implicitly concatenated. - pub fn as_str(&self) -> &str { + pub fn to_str(&self) -> &str { match &self.inner { StringLiteralValueInner::Single(value) => value.as_str(), - StringLiteralValueInner::Concatenated(value) => value.as_str(), + StringLiteralValueInner::Concatenated(value) => value.to_str(), } } } @@ -1259,7 +1259,7 @@ impl PartialEq for StringLiteralValue { impl fmt::Display for StringLiteralValue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) + f.write_str(self.to_str()) } } @@ -1331,7 +1331,7 @@ struct ConcatenatedStringLiteral { impl ConcatenatedStringLiteral { /// Extracts a string slice containing the entire concatenated string. - fn as_str(&self) -> &str { + fn to_str(&self) -> &str { self.value .get_or_init(|| self.strings.iter().map(StringLiteral::as_str).collect()) } @@ -1354,7 +1354,7 @@ impl Debug for ConcatenatedStringLiteral { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ConcatenatedStringLiteral") .field("strings", &self.strings) - .field("value", &self.as_str()) + .field("value", &self.to_str()) .finish() } } diff --git a/crates/ruff_python_codegen/src/generator.rs b/crates/ruff_python_codegen/src/generator.rs index ac5abc2e8a6cc..cb1a8fedabf5d 100644 --- a/crates/ruff_python_codegen/src/generator.rs +++ b/crates/ruff_python_codegen/src/generator.rs @@ -1356,7 +1356,7 @@ impl<'a> Generator<'a> { fn unparse_f_string_elem(&mut self, expr: &Expr, is_spec: bool) { match expr { Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { - self.unparse_f_string_literal(value.as_str()); + self.unparse_f_string_literal(value.to_str()); } Expr::FString(ast::ExprFString { value, .. }) => { self.unparse_f_string_value(value, is_spec); From 6435e4e4aa165f662732b17da5ccf6ad39965959 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 28 Nov 2023 18:35:55 -0800 Subject: [PATCH 055/197] Enable auto-return-type involving `Optional` and `Union` annotations (#8885) ## Summary Previously, this was only supported for Python 3.10 and later, since we always use the PEP 604-style unions. --- .../flake8_annotations/auto_return_type.py | 18 +- .../src/rules/flake8_annotations/helpers.rs | 110 +++++++-- .../src/rules/flake8_annotations/mod.rs | 20 ++ .../flake8_annotations/rules/definition.rs | 116 ++++++--- ..._annotations__tests__auto_return_type.snap | 44 +++- ...tations__tests__auto_return_type_py38.snap | 223 ++++++++++++++++++ .../flake8_pytest_style/rules/parametrize.rs | 2 +- crates/ruff_python_ast/src/helpers.rs | 44 ++++ crates/ruff_python_parser/src/python.lalrpop | 8 +- crates/ruff_python_parser/src/python.rs | 10 +- 10 files changed, 526 insertions(+), 69 deletions(-) create mode 100644 crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type_py38.snap diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py b/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py index 32d0cc2094523..81ce953ed11e0 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py @@ -42,8 +42,24 @@ def func(x: int): return {"foo": 1} -def func(): +def func(x: int): if not x: return 1 else: return True + + +def func(x: int): + if not x: + return 1 + else: + return None + + +def func(x: int): + if not x: + return 1 + elif x > 5: + return "str" + else: + return None diff --git a/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs b/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs index 8308d9a06569a..9dc7e896dd106 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs @@ -1,12 +1,17 @@ use itertools::Itertools; +use ruff_diagnostics::Edit; +use rustc_hash::FxHashSet; -use ruff_python_ast::helpers::{pep_604_union, ReturnStatementVisitor}; +use crate::importer::{ImportRequest, Importer}; +use ruff_python_ast::helpers::{ + pep_604_union, typing_optional, typing_union, ReturnStatementVisitor, +}; use ruff_python_ast::visitor::Visitor; use ruff_python_ast::{self as ast, Expr, ExprContext}; use ruff_python_semantic::analyze::type_inference::{NumberLike, PythonType, ResolvedPythonType}; use ruff_python_semantic::analyze::visibility; use ruff_python_semantic::{Definition, SemanticModel}; -use ruff_text_size::TextRange; +use ruff_text_size::{TextRange, TextSize}; use crate::settings::types::PythonVersion; @@ -38,10 +43,7 @@ pub(crate) fn is_overload_impl( } /// Given a function, guess its return type. -pub(crate) fn auto_return_type( - function: &ast::StmtFunctionDef, - target_version: PythonVersion, -) -> Option { +pub(crate) fn auto_return_type(function: &ast::StmtFunctionDef) -> Option { // Collect all the `return` statements. let returns = { let mut visitor = ReturnStatementVisitor::default(); @@ -68,24 +70,94 @@ pub(crate) fn auto_return_type( } match return_type { - ResolvedPythonType::Atom(python_type) => type_expr(python_type), - ResolvedPythonType::Union(python_types) if target_version >= PythonVersion::Py310 => { - // Aggregate all the individual types (e.g., `int`, `float`). - let names = python_types - .iter() - .sorted_unstable() - .map(|python_type| type_expr(*python_type)) - .collect::>>()?; - - // Wrap in a bitwise union (e.g., `int | float`). - Some(pep_604_union(&names)) - } - ResolvedPythonType::Union(_) => None, + ResolvedPythonType::Atom(python_type) => Some(AutoPythonType::Atom(python_type)), + ResolvedPythonType::Union(python_types) => Some(AutoPythonType::Union(python_types)), ResolvedPythonType::Unknown => None, ResolvedPythonType::TypeError => None, } } +#[derive(Debug)] +pub(crate) enum AutoPythonType { + Atom(PythonType), + Union(FxHashSet), +} + +impl AutoPythonType { + /// Convert an [`AutoPythonType`] into an [`Expr`]. + /// + /// If the [`Expr`] relies on importing any external symbols, those imports will be returned as + /// additional edits. + pub(crate) fn into_expression( + self, + importer: &Importer, + at: TextSize, + semantic: &SemanticModel, + target_version: PythonVersion, + ) -> Option<(Expr, Vec)> { + match self { + AutoPythonType::Atom(python_type) => { + let expr = type_expr(python_type)?; + Some((expr, vec![])) + } + AutoPythonType::Union(python_types) => { + if target_version >= PythonVersion::Py310 { + // Aggregate all the individual types (e.g., `int`, `float`). + let names = python_types + .iter() + .sorted_unstable() + .map(|python_type| type_expr(*python_type)) + .collect::>>()?; + + // Wrap in a bitwise union (e.g., `int | float`). + let expr = pep_604_union(&names); + + Some((expr, vec![])) + } else { + let python_types = python_types + .into_iter() + .sorted_unstable() + .collect::>(); + + match python_types.as_slice() { + [python_type, PythonType::None] | [PythonType::None, python_type] => { + let element = type_expr(*python_type)?; + + // Ex) `Optional[int]` + let (optional_edit, binding) = importer + .get_or_import_symbol( + &ImportRequest::import_from("typing", "Optional"), + at, + semantic, + ) + .ok()?; + let expr = typing_optional(element, binding); + Some((expr, vec![optional_edit])) + } + _ => { + let elements = python_types + .into_iter() + .map(type_expr) + .collect::>>()?; + + // Ex) `Union[int, str]` + let (union_edit, binding) = importer + .get_or_import_symbol( + &ImportRequest::import_from("typing", "Union"), + at, + semantic, + ) + .ok()?; + let expr = typing_union(&elements, binding); + Some((expr, vec![union_edit])) + } + } + } + } + } + } +} + /// Given a [`PythonType`], return an [`Expr`] that resolves to that type. fn type_expr(python_type: PythonType) -> Option { fn name(name: &str) -> Expr { diff --git a/crates/ruff_linter/src/rules/flake8_annotations/mod.rs b/crates/ruff_linter/src/rules/flake8_annotations/mod.rs index b7dbf012035aa..859f8588c5311 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_annotations/mod.rs @@ -11,6 +11,7 @@ mod tests { use crate::assert_messages; use crate::registry::Rule; + use crate::settings::types::PythonVersion; use crate::settings::LinterSettings; use crate::test::test_path; @@ -128,6 +129,25 @@ mod tests { Ok(()) } + #[test] + fn auto_return_type_py38() -> Result<()> { + let diagnostics = test_path( + Path::new("flake8_annotations/auto_return_type.py"), + &LinterSettings { + target_version: PythonVersion::Py38, + ..LinterSettings::for_rules(vec![ + Rule::MissingReturnTypeUndocumentedPublicFunction, + Rule::MissingReturnTypePrivateFunction, + Rule::MissingReturnTypeSpecialMethod, + Rule::MissingReturnTypeStaticMethod, + Rule::MissingReturnTypeClassMethod, + ]) + }, + )?; + assert_messages!(diagnostics); + Ok(()) + } + #[test] fn suppress_none_returning() -> Result<()> { let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs b/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs index 9acf52c8e8fef..9360d0dfdd258 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs +++ b/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs @@ -725,39 +725,55 @@ pub(crate) fn definition( ) { if is_method && visibility::is_classmethod(decorator_list, checker.semantic()) { if checker.enabled(Rule::MissingReturnTypeClassMethod) { - let return_type = auto_return_type(function, checker.settings.target_version) - .map(|return_type| checker.generator().expr(&return_type)); + let return_type = auto_return_type(function) + .and_then(|return_type| { + return_type.into_expression( + checker.importer(), + function.parameters.start(), + checker.semantic(), + checker.settings.target_version, + ) + }) + .map(|(return_type, edits)| (checker.generator().expr(&return_type), edits)); let mut diagnostic = Diagnostic::new( MissingReturnTypeClassMethod { name: name.to_string(), - annotation: return_type.clone(), + annotation: return_type.clone().map(|(return_type, ..)| return_type), }, function.identifier(), ); - if let Some(return_type) = return_type { - diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion( - format!(" -> {return_type}"), - function.parameters.range().end(), - ))); + if let Some((return_type, edits)) = return_type { + diagnostic.set_fix(Fix::unsafe_edits( + Edit::insertion(format!(" -> {return_type}"), function.parameters.end()), + edits, + )); } diagnostics.push(diagnostic); } } else if is_method && visibility::is_staticmethod(decorator_list, checker.semantic()) { if checker.enabled(Rule::MissingReturnTypeStaticMethod) { - let return_type = auto_return_type(function, checker.settings.target_version) - .map(|return_type| checker.generator().expr(&return_type)); + let return_type = auto_return_type(function) + .and_then(|return_type| { + return_type.into_expression( + checker.importer(), + function.parameters.start(), + checker.semantic(), + checker.settings.target_version, + ) + }) + .map(|(return_type, edits)| (checker.generator().expr(&return_type), edits)); let mut diagnostic = Diagnostic::new( MissingReturnTypeStaticMethod { name: name.to_string(), - annotation: return_type.clone(), + annotation: return_type.clone().map(|(return_type, ..)| return_type), }, function.identifier(), ); - if let Some(return_type) = return_type { - diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion( - format!(" -> {return_type}"), - function.parameters.range().end(), - ))); + if let Some((return_type, edits)) = return_type { + diagnostic.set_fix(Fix::unsafe_edits( + Edit::insertion(format!(" -> {return_type}"), function.parameters.end()), + edits, + )); } diagnostics.push(diagnostic); } @@ -775,7 +791,7 @@ pub(crate) fn definition( ); diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion( " -> None".to_string(), - function.parameters.range().end(), + function.parameters.end(), ))); diagnostics.push(diagnostic); } @@ -793,7 +809,7 @@ pub(crate) fn definition( if let Some(return_type) = return_type { diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion( format!(" -> {return_type}"), - function.parameters.range().end(), + function.parameters.end(), ))); } diagnostics.push(diagnostic); @@ -802,42 +818,70 @@ pub(crate) fn definition( match visibility { visibility::Visibility::Public => { if checker.enabled(Rule::MissingReturnTypeUndocumentedPublicFunction) { - let return_type = - auto_return_type(function, checker.settings.target_version) - .map(|return_type| checker.generator().expr(&return_type)); + let return_type = auto_return_type(function) + .and_then(|return_type| { + return_type.into_expression( + checker.importer(), + function.parameters.start(), + checker.semantic(), + checker.settings.target_version, + ) + }) + .map(|(return_type, edits)| { + (checker.generator().expr(&return_type), edits) + }); let mut diagnostic = Diagnostic::new( MissingReturnTypeUndocumentedPublicFunction { name: name.to_string(), - annotation: return_type.clone(), + annotation: return_type + .clone() + .map(|(return_type, ..)| return_type), }, function.identifier(), ); - if let Some(return_type) = return_type { - diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion( - format!(" -> {return_type}"), - function.parameters.range().end(), - ))); + if let Some((return_type, edits)) = return_type { + diagnostic.set_fix(Fix::unsafe_edits( + Edit::insertion( + format!(" -> {return_type}"), + function.parameters.end(), + ), + edits, + )); } diagnostics.push(diagnostic); } } visibility::Visibility::Private => { if checker.enabled(Rule::MissingReturnTypePrivateFunction) { - let return_type = - auto_return_type(function, checker.settings.target_version) - .map(|return_type| checker.generator().expr(&return_type)); + let return_type = auto_return_type(function) + .and_then(|return_type| { + return_type.into_expression( + checker.importer(), + function.parameters.start(), + checker.semantic(), + checker.settings.target_version, + ) + }) + .map(|(return_type, edits)| { + (checker.generator().expr(&return_type), edits) + }); let mut diagnostic = Diagnostic::new( MissingReturnTypePrivateFunction { name: name.to_string(), - annotation: return_type.clone(), + annotation: return_type + .clone() + .map(|(return_type, ..)| return_type), }, function.identifier(), ); - if let Some(return_type) = return_type { - diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion( - format!(" -> {return_type}"), - function.parameters.range().end(), - ))); + if let Some((return_type, edits)) = return_type { + diagnostic.set_fix(Fix::unsafe_edits( + Edit::insertion( + format!(" -> {return_type}"), + function.parameters.end(), + ), + edits, + )); } diagnostics.push(diagnostic); } diff --git a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap index c5508c652a894..021e1b520766a 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap +++ b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap @@ -145,7 +145,7 @@ auto_return_type.py:41:5: ANN201 Missing return type annotation for public funct auto_return_type.py:45:5: ANN201 [*] Missing return type annotation for public function `func` | -45 | def func(): +45 | def func(x: int): | ^^^^ ANN201 46 | if not x: 47 | return 1 @@ -156,10 +156,48 @@ auto_return_type.py:45:5: ANN201 [*] Missing return type annotation for public f 42 42 | return {"foo": 1} 43 43 | 44 44 | -45 |-def func(): - 45 |+def func() -> int: +45 |-def func(x: int): + 45 |+def func(x: int) -> int: 46 46 | if not x: 47 47 | return 1 48 48 | else: +auto_return_type.py:52:5: ANN201 [*] Missing return type annotation for public function `func` + | +52 | def func(x: int): + | ^^^^ ANN201 +53 | if not x: +54 | return 1 + | + = help: Add return type annotation: `int | None` + +ℹ Unsafe fix +49 49 | return True +50 50 | +51 51 | +52 |-def func(x: int): + 52 |+def func(x: int) -> int | None: +53 53 | if not x: +54 54 | return 1 +55 55 | else: + +auto_return_type.py:59:5: ANN201 [*] Missing return type annotation for public function `func` + | +59 | def func(x: int): + | ^^^^ ANN201 +60 | if not x: +61 | return 1 + | + = help: Add return type annotation: `str | int | None` + +ℹ Unsafe fix +56 56 | return None +57 57 | +58 58 | +59 |-def func(x: int): + 59 |+def func(x: int) -> str | int | None: +60 60 | if not x: +61 61 | return 1 +62 62 | elif x > 5: + diff --git a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type_py38.snap b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type_py38.snap new file mode 100644 index 0000000000000..0831fcffa3e09 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type_py38.snap @@ -0,0 +1,223 @@ +--- +source: crates/ruff_linter/src/rules/flake8_annotations/mod.rs +--- +auto_return_type.py:1:5: ANN201 [*] Missing return type annotation for public function `func` + | +1 | def func(): + | ^^^^ ANN201 +2 | return 1 + | + = help: Add return type annotation: `int` + +ℹ Unsafe fix +1 |-def func(): + 1 |+def func() -> int: +2 2 | return 1 +3 3 | +4 4 | + +auto_return_type.py:5:5: ANN201 [*] Missing return type annotation for public function `func` + | +5 | def func(): + | ^^^^ ANN201 +6 | return 1.5 + | + = help: Add return type annotation: `float` + +ℹ Unsafe fix +2 2 | return 1 +3 3 | +4 4 | +5 |-def func(): + 5 |+def func() -> float: +6 6 | return 1.5 +7 7 | +8 8 | + +auto_return_type.py:9:5: ANN201 [*] Missing return type annotation for public function `func` + | + 9 | def func(x: int): + | ^^^^ ANN201 +10 | if x > 0: +11 | return 1 + | + = help: Add return type annotation: `float` + +ℹ Unsafe fix +6 6 | return 1.5 +7 7 | +8 8 | +9 |-def func(x: int): + 9 |+def func(x: int) -> float: +10 10 | if x > 0: +11 11 | return 1 +12 12 | else: + +auto_return_type.py:16:5: ANN201 [*] Missing return type annotation for public function `func` + | +16 | def func(): + | ^^^^ ANN201 +17 | return True + | + = help: Add return type annotation: `bool` + +ℹ Unsafe fix +13 13 | return 1.5 +14 14 | +15 15 | +16 |-def func(): + 16 |+def func() -> bool: +17 17 | return True +18 18 | +19 19 | + +auto_return_type.py:20:5: ANN201 [*] Missing return type annotation for public function `func` + | +20 | def func(x: int): + | ^^^^ ANN201 +21 | if x > 0: +22 | return None + | + = help: Add return type annotation: `None` + +ℹ Unsafe fix +17 17 | return True +18 18 | +19 19 | +20 |-def func(x: int): + 20 |+def func(x: int) -> None: +21 21 | if x > 0: +22 22 | return None +23 23 | else: + +auto_return_type.py:27:5: ANN201 [*] Missing return type annotation for public function `func` + | +27 | def func(x: int): + | ^^^^ ANN201 +28 | return 1 or 2.5 if x > 0 else 1.5 or "str" + | + = help: Add return type annotation: `Union[str | float]` + +ℹ Unsafe fix + 1 |+from typing import Union +1 2 | def func(): +2 3 | return 1 +3 4 | +-------------------------------------------------------------------------------- +24 25 | return +25 26 | +26 27 | +27 |-def func(x: int): + 28 |+def func(x: int) -> Union[str | float]: +28 29 | return 1 or 2.5 if x > 0 else 1.5 or "str" +29 30 | +30 31 | + +auto_return_type.py:31:5: ANN201 [*] Missing return type annotation for public function `func` + | +31 | def func(x: int): + | ^^^^ ANN201 +32 | return 1 + 2.5 if x > 0 else 1.5 or "str" + | + = help: Add return type annotation: `Union[str | float]` + +ℹ Unsafe fix + 1 |+from typing import Union +1 2 | def func(): +2 3 | return 1 +3 4 | +-------------------------------------------------------------------------------- +28 29 | return 1 or 2.5 if x > 0 else 1.5 or "str" +29 30 | +30 31 | +31 |-def func(x: int): + 32 |+def func(x: int) -> Union[str | float]: +32 33 | return 1 + 2.5 if x > 0 else 1.5 or "str" +33 34 | +34 35 | + +auto_return_type.py:35:5: ANN201 Missing return type annotation for public function `func` + | +35 | def func(x: int): + | ^^^^ ANN201 +36 | if not x: +37 | return None + | + = help: Add return type annotation + +auto_return_type.py:41:5: ANN201 Missing return type annotation for public function `func` + | +41 | def func(x: int): + | ^^^^ ANN201 +42 | return {"foo": 1} + | + = help: Add return type annotation + +auto_return_type.py:45:5: ANN201 [*] Missing return type annotation for public function `func` + | +45 | def func(x: int): + | ^^^^ ANN201 +46 | if not x: +47 | return 1 + | + = help: Add return type annotation: `int` + +ℹ Unsafe fix +42 42 | return {"foo": 1} +43 43 | +44 44 | +45 |-def func(x: int): + 45 |+def func(x: int) -> int: +46 46 | if not x: +47 47 | return 1 +48 48 | else: + +auto_return_type.py:52:5: ANN201 [*] Missing return type annotation for public function `func` + | +52 | def func(x: int): + | ^^^^ ANN201 +53 | if not x: +54 | return 1 + | + = help: Add return type annotation: `Optional[int]` + +ℹ Unsafe fix + 1 |+from typing import Optional +1 2 | def func(): +2 3 | return 1 +3 4 | +-------------------------------------------------------------------------------- +49 50 | return True +50 51 | +51 52 | +52 |-def func(x: int): + 53 |+def func(x: int) -> Optional[int]: +53 54 | if not x: +54 55 | return 1 +55 56 | else: + +auto_return_type.py:59:5: ANN201 [*] Missing return type annotation for public function `func` + | +59 | def func(x: int): + | ^^^^ ANN201 +60 | if not x: +61 | return 1 + | + = help: Add return type annotation: `Union[str | int | None]` + +ℹ Unsafe fix + 1 |+from typing import Union +1 2 | def func(): +2 3 | return 1 +3 4 | +-------------------------------------------------------------------------------- +56 57 | return None +57 58 | +58 59 | +59 |-def func(x: int): + 60 |+def func(x: int) -> Union[str | int | None]: +60 61 | if not x: +61 62 | return 1 +62 63 | elif x > 5: + + diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs index c023674cdcf16..0f5a621f01eac 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs @@ -550,7 +550,7 @@ fn check_duplicates(checker: &mut Checker, values: &Expr) { element.range(), ); if let Some(prev) = prev { - let values_end = values.range().end() - TextSize::new(1); + let values_end = values.end() - TextSize::new(1); let previous_end = trailing_comma(prev, checker.locator().contents()).unwrap_or(values_end); let element_end = diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index a82b5677df7fa..5d065fa30fc11 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -1293,6 +1293,50 @@ pub fn pep_604_union(elts: &[Expr]) -> Expr { } } +pub fn typing_optional(elt: Expr, binding: String) -> Expr { + Expr::Subscript(ast::ExprSubscript { + value: Box::new(Expr::Name(ast::ExprName { + id: binding, + range: TextRange::default(), + ctx: ExprContext::Load, + })), + slice: Box::new(elt), + ctx: ExprContext::Load, + range: TextRange::default(), + }) +} + +pub fn typing_union(elts: &[Expr], binding: String) -> Expr { + fn tuple(elts: &[Expr]) -> Expr { + match elts { + [] => Expr::Tuple(ast::ExprTuple { + elts: vec![], + ctx: ExprContext::Load, + range: TextRange::default(), + }), + [Expr::Tuple(ast::ExprTuple { elts, .. })] => pep_604_union(elts), + [elt] => elt.clone(), + [rest @ .., elt] => Expr::BinOp(ast::ExprBinOp { + left: Box::new(tuple(rest)), + op: Operator::BitOr, + right: Box::new(elt.clone()), + range: TextRange::default(), + }), + } + } + + Expr::Subscript(ast::ExprSubscript { + value: Box::new(Expr::Name(ast::ExprName { + id: binding, + range: TextRange::default(), + ctx: ExprContext::Load, + })), + slice: Box::new(tuple(elts)), + ctx: ExprContext::Load, + range: TextRange::default(), + }) +} + #[cfg(test)] mod tests { use std::borrow::Cow; diff --git a/crates/ruff_python_parser/src/python.lalrpop b/crates/ruff_python_parser/src/python.lalrpop index 20a924fb0ffd6..67c49a7b644ab 100644 --- a/crates/ruff_python_parser/src/python.lalrpop +++ b/crates/ruff_python_parser/src/python.lalrpop @@ -399,7 +399,7 @@ IpyHelpEndEscapeCommandStatement: ast::Stmt = { _ => { return Err(LexicalError { error: LexicalErrorType::OtherError("only Name, Subscript and Attribute expressions are allowed in help end escape command".to_string()), - location: expr.range().start(), + location: expr.start(), }); } } @@ -1642,12 +1642,12 @@ FStringReplacementField: ast::Expr = { } else { format_spec.as_ref().map_or_else( || end_location - "}".text_len(), - |spec| spec.range().start() - ":".text_len(), + |spec| spec.start() - ":".text_len(), ) }; ast::DebugText { - leading: source_code[TextRange::new(start_offset, value.range().start())].to_string(), - trailing: source_code[TextRange::new(value.range().end(), end_offset)].to_string(), + leading: source_code[TextRange::new(start_offset, value.start())].to_string(), + trailing: source_code[TextRange::new(value.end(), end_offset)].to_string(), } }); Ok( diff --git a/crates/ruff_python_parser/src/python.rs b/crates/ruff_python_parser/src/python.rs index 89968c167273c..3452ede4e59d8 100644 --- a/crates/ruff_python_parser/src/python.rs +++ b/crates/ruff_python_parser/src/python.rs @@ -1,5 +1,5 @@ // auto-generated: "lalrpop 0.20.0" -// sha3: e78a653b50980f07fcb78bfa43c9f023870e26514f59acdec0bec5bf84c2a133 +// sha3: e999c9c9ca8fe5a29655244aa995b8cf4e639f0bda95099d8f2a395bc06b6408 use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; use ruff_python_ast::{self as ast, Int, IpyEscapeKind}; use crate::{ @@ -33700,7 +33700,7 @@ fn __action76< _ => { return Err(LexicalError { error: LexicalErrorType::OtherError("only Name, Subscript and Attribute expressions are allowed in help end escape command".to_string()), - location: expr.range().start(), + location: expr.start(), }); } } @@ -36420,12 +36420,12 @@ fn __action221< } else { format_spec.as_ref().map_or_else( || end_location - "}".text_len(), - |spec| spec.range().start() - ":".text_len(), + |spec| spec.start() - ":".text_len(), ) }; ast::DebugText { - leading: source_code[TextRange::new(start_offset, value.range().start())].to_string(), - trailing: source_code[TextRange::new(value.range().end(), end_offset)].to_string(), + leading: source_code[TextRange::new(start_offset, value.start())].to_string(), + trailing: source_code[TextRange::new(value.end(), end_offset)].to_string(), } }); Ok( From cddc6968961730fe3c270e20a36e1bacc4d1e057 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Wed, 29 Nov 2023 13:21:07 +0900 Subject: [PATCH 056/197] Stop at the first resolved parent configuration (#8864) --- crates/ruff_cli/tests/lint.rs | 40 +++++++++++++++++++++++++++ crates/ruff_workspace/src/resolver.rs | 2 ++ 2 files changed, 42 insertions(+) diff --git a/crates/ruff_cli/tests/lint.rs b/crates/ruff_cli/tests/lint.rs index f36f612ba8919..5dfbd56f83c55 100644 --- a/crates/ruff_cli/tests/lint.rs +++ b/crates/ruff_cli/tests/lint.rs @@ -396,3 +396,43 @@ if __name__ == "__main__": "###); Ok(()) } + +/// Regression test for [#8858](https://github.com/astral-sh/ruff/issues/8858) +#[test] +fn parent_configuration_override() -> Result<()> { + let tempdir = TempDir::new()?; + let root_ruff = tempdir.path().join("ruff.toml"); + fs::write( + root_ruff, + r#" +[lint] +select = ["ALL"] +"#, + )?; + + let sub_dir = tempdir.path().join("subdirectory"); + fs::create_dir(&sub_dir)?; + + let subdirectory_ruff = sub_dir.join("ruff.toml"); + fs::write( + subdirectory_ruff, + r#" +[lint] +ignore = ["D203", "D212"] +"#, + )?; + + assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) + .current_dir(sub_dir) + .arg("check") + .args(STDIN_BASE_OPTIONS) + , @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + warning: No Python files found under the given path(s) + "###); + Ok(()) +} diff --git a/crates/ruff_workspace/src/resolver.rs b/crates/ruff_workspace/src/resolver.rs index fc12feaad3ace..93df74b1e2aad 100644 --- a/crates/ruff_workspace/src/resolver.rs +++ b/crates/ruff_workspace/src/resolver.rs @@ -294,6 +294,7 @@ pub fn python_files_in_path( let (root, settings) = resolve_scoped_settings(&pyproject, Relativity::Parent, transformer)?; resolver.add(root, settings); + break; } } } @@ -494,6 +495,7 @@ pub fn python_file_at_path( let (root, settings) = resolve_scoped_settings(&pyproject, Relativity::Parent, transformer)?; resolver.add(root, settings); + break; } } } From 2314b9aaca59d1eef1171fc3fe76b50082b22d9f Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Wed, 29 Nov 2023 13:26:25 +0900 Subject: [PATCH 057/197] Add benchmark for running all rules including preview rules (#8865) --- crates/ruff_benchmark/benches/linter.rs | 37 +++++++++++++++++++++---- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/crates/ruff_benchmark/benches/linter.rs b/crates/ruff_benchmark/benches/linter.rs index 9a5e01f2bf589..a98061fc822a8 100644 --- a/crates/ruff_benchmark/benches/linter.rs +++ b/crates/ruff_benchmark/benches/linter.rs @@ -3,7 +3,9 @@ use ruff_benchmark::criterion::{ }; use ruff_benchmark::{TestCase, TestFile, TestFileDownloadError}; use ruff_linter::linter::lint_only; +use ruff_linter::rule_selector::PreviewOptions; use ruff_linter::settings::rule_table::RuleTable; +use ruff_linter::settings::types::PreviewMode; use ruff_linter::settings::{flags, LinterSettings}; use ruff_linter::source_kind::SourceKind; use ruff_linter::{registry::Rule, RuleSelector}; @@ -78,12 +80,21 @@ fn benchmark_default_rules(criterion: &mut Criterion) { benchmark_linter(group, &LinterSettings::default()); } -fn benchmark_all_rules(criterion: &mut Criterion) { - let mut rules: RuleTable = RuleSelector::All.all_rules().collect(); - - // Disable IO based rules because it is a source of flakiness +/// Disables IO based rules because they are a source of flakiness +fn disable_io_rules(rules: &mut RuleTable) { rules.disable(Rule::ShebangMissingExecutableFile); rules.disable(Rule::ShebangNotExecutable); +} + +fn benchmark_all_rules(criterion: &mut Criterion) { + let mut rules: RuleTable = RuleSelector::All + .rules(&PreviewOptions { + mode: PreviewMode::Disabled, + require_explicit: false, + }) + .collect(); + + disable_io_rules(&mut rules); let settings = LinterSettings { rules, @@ -94,6 +105,22 @@ fn benchmark_all_rules(criterion: &mut Criterion) { benchmark_linter(group, &settings); } +fn benchmark_preview_rules(criterion: &mut Criterion) { + let mut rules: RuleTable = RuleSelector::All.all_rules().collect(); + + disable_io_rules(&mut rules); + + let settings = LinterSettings { + rules, + preview: PreviewMode::Enabled, + ..LinterSettings::default() + }; + + let group = criterion.benchmark_group("linter/all-with-preview-rules"); + benchmark_linter(group, &settings); +} + criterion_group!(default_rules, benchmark_default_rules); criterion_group!(all_rules, benchmark_all_rules); -criterion_main!(default_rules, all_rules); +criterion_group!(preview_rules, benchmark_preview_rules); +criterion_main!(default_rules, all_rules, preview_rules); From 08f3110f1e7992a7dd1d43aa9d06e98b2cd51346 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 30 Nov 2023 01:09:33 +0100 Subject: [PATCH 058/197] Optimize workflow run (#8225) --- .github/workflows/ci.yaml | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3f8c3d3a1a15c..32d803aa1407c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -23,8 +23,13 @@ jobs: name: "Determine changes" runs-on: ubuntu-latest outputs: + # Flag that is raised when any code that affects linter is changed linter: ${{ steps.changed.outputs.linter_any_changed }} + # Flag that is raised when any code that affects formatter is changed formatter: ${{ steps.changed.outputs.formatter_any_changed }} + # Flag that is raised when any code is changed + # This is superset of the linter and formatter + code: ${{ steps.changed.outputs.code_any_changed }} steps: - uses: actions/checkout@v4 with: @@ -62,6 +67,12 @@ jobs: - python/** - .github/workflows/ci.yaml + code: + - "*/**" + - "!**/*.md" + - "!docs/**" + - "!assets/**" + cargo-fmt: name: "cargo fmt" runs-on: ubuntu-latest @@ -74,6 +85,8 @@ jobs: cargo-clippy: name: "cargo clippy" runs-on: ubuntu-latest + needs: determine_changes + if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4 - name: "Install Rust toolchain" @@ -88,6 +101,8 @@ jobs: cargo-test-linux: runs-on: ubuntu-latest + needs: determine_changes + if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' name: "cargo test (linux)" steps: - uses: actions/checkout@v4 @@ -112,6 +127,8 @@ jobs: cargo-test-windows: runs-on: windows-latest + needs: determine_changes + if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' name: "cargo test (windows)" steps: - uses: actions/checkout@v4 @@ -129,6 +146,8 @@ jobs: cargo-test-wasm: runs-on: ubuntu-latest + needs: determine_changes + if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' name: "cargo test (wasm)" steps: - uses: actions/checkout@v4 @@ -148,6 +167,8 @@ jobs: cargo-fuzz: runs-on: ubuntu-latest + needs: determine_changes + if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' name: "cargo fuzz" steps: - uses: actions/checkout@v4 @@ -165,6 +186,8 @@ jobs: scripts: name: "test scripts" runs-on: ubuntu-latest + needs: determine_changes + if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4 - name: "Install Rust toolchain" @@ -188,8 +211,7 @@ jobs: # Only runs on pull requests, since that is the only we way we can find the base version for comparison. # Ecosystem check needs linter and/or formatter changes. if: github.event_name == 'pull_request' && ${{ - needs.determine_changes.outputs.linter == 'true' || - needs.determine_changes.outputs.formatter == 'true' + needs.determine_changes.outputs.code == 'true' }} steps: - uses: actions/checkout@v4 @@ -298,6 +320,8 @@ jobs: cargo-udeps: name: "cargo udeps" runs-on: ubuntu-latest + needs: determine_changes + if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4 - name: "Install nightly Rust toolchain" @@ -417,7 +441,10 @@ jobs: check-ruff-lsp: name: "test ruff-lsp" runs-on: ubuntu-latest - needs: cargo-test-linux + needs: + - cargo-test-linux + - determine_changes + if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' steps: - uses: extractions/setup-just@v1 env: @@ -455,6 +482,8 @@ jobs: benchmarks: runs-on: ubuntu-latest + needs: determine_changes + if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' steps: - name: "Checkout Branch" uses: actions/checkout@v4 From fd70cd789ffa5da4aff658b39b6df1bbfcedd4ae Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Thu, 30 Nov 2023 09:09:55 +0900 Subject: [PATCH 059/197] Update Black tests (#8901) --- .../attribute_access_on_number_literals.py | 0 ...ribute_access_on_number_literals.py.expect | 0 .../beginning_backslash.py | 0 .../beginning_backslash.py.expect | 0 .../{simple_cases => cases}/bracketmatch.py | 0 .../bracketmatch.py.expect | 0 .../fixtures/black/cases/bytes_docstring.py | 14 + .../black/cases/bytes_docstring.py.expect | 18 + .../class_blank_parentheses.py | 0 .../class_blank_parentheses.py.expect | 0 .../class_methods_new_line.py | 0 .../class_methods_new_line.py.expect | 0 .../{simple_cases => cases}/collections.py | 0 .../collections.py.expect | 0 .../comment_after_escaped_newline.py | 0 .../comment_after_escaped_newline.py.expect | 0 .../black/{simple_cases => cases}/comments.py | 0 .../comments.py.expect | 0 .../{simple_cases => cases}/comments2.py | 0 .../comments2.py.expect | 0 .../{simple_cases => cases}/comments3.py | 0 .../comments3.py.expect | 0 .../{simple_cases => cases}/comments4.py | 0 .../comments4.py.expect | 0 .../{simple_cases => cases}/comments5.py | 0 .../comments5.py.expect | 0 .../{simple_cases => cases}/comments6.py | 0 .../comments6.py.expect | 0 .../{simple_cases => cases}/comments8.py | 0 .../comments8.py.expect | 0 .../{simple_cases => cases}/comments9.py | 0 .../comments9.py.expect | 0 .../black/cases/comments_in_blocks.py | 111 + .../black/cases/comments_in_blocks.py.expect | 111 + .../comments_non_breaking_space.py | 2 +- .../comments_non_breaking_space.py.expect | 0 .../{simple_cases => cases}/composition.py | 0 .../composition.py.expect | 0 .../composition_no_trailing_comma.py | 0 .../composition_no_trailing_comma.py.expect | 0 .../cases/conditional_expression.options.json | 1 + .../black/cases/conditional_expression.py | 67 + .../cases/conditional_expression.py.expect | 90 + .../{simple_cases => cases}/docstring.py | 7 + .../docstring.py.expect | 7 + ...ocstring_no_extra_empty_line_before_eof.py | 0 ...g_no_extra_empty_line_before_eof.py.expect | 0 .../docstring_no_string_normalization.py | 0 ...ocstring_no_string_normalization.py.expect | 0 .../docstring_preview.py | 0 .../docstring_preview.py.expect | 3 +- .../{simple_cases => cases}/empty_lines.py | 0 .../empty_lines.py.expect | 0 .../{simple_cases => cases}/expression.py | 0 .../expression.py.expect | 0 .../test/fixtures/black/cases/f_docstring.py | 8 + .../black/cases/f_docstring.py.expect | 10 + .../black/{simple_cases => cases}/fmtonoff.py | 0 .../fmtonoff.py.expect | 0 .../{simple_cases => cases}/fmtonoff2.py | 0 .../fmtonoff2.py.expect | 0 .../{simple_cases => cases}/fmtonoff3.py | 0 .../fmtonoff3.py.expect | 0 .../{simple_cases => cases}/fmtonoff4.py | 0 .../fmtonoff4.py.expect | 0 .../{simple_cases => cases}/fmtonoff5.py | 0 .../fmtonoff5.py.expect | 0 .../fmtpass_imports.py | 0 .../fmtpass_imports.py.expect | 0 .../black/{simple_cases => cases}/fmtskip.py | 0 .../{simple_cases => cases}/fmtskip.py.expect | 0 .../black/{simple_cases => cases}/fmtskip2.py | 0 .../fmtskip2.py.expect | 0 .../black/{simple_cases => cases}/fmtskip3.py | 0 .../fmtskip3.py.expect | 0 .../black/{simple_cases => cases}/fmtskip4.py | 0 .../fmtskip4.py.expect | 0 .../black/{simple_cases => cases}/fmtskip5.py | 0 .../fmtskip5.py.expect | 0 .../black/{simple_cases => cases}/fmtskip6.py | 0 .../fmtskip6.py.expect | 0 .../black/{simple_cases => cases}/fmtskip7.py | 0 .../fmtskip7.py.expect | 0 .../black/{simple_cases => cases}/fmtskip8.py | 0 .../fmtskip8.py.expect | 0 .../black/{simple_cases => cases}/fstring.py | 0 .../{simple_cases => cases}/fstring.py.expect | 0 ...ef_return_type_trailing_comma.options.json | 1 + .../funcdef_return_type_trailing_comma.py | 143 + ...ncdef_return_type_trailing_comma.py.expect | 156 + .../black/{simple_cases => cases}/function.py | 0 .../function.py.expect | 0 .../{simple_cases => cases}/function2.py | 0 .../function2.py.expect | 0 .../function_trailing_comma.py | 0 .../function_trailing_comma.py.expect | 0 .../ignore_pyi.py => cases/ignore_pyi.pyi} | 7 +- .../ignore_pyi.pyi.expect} | 0 .../{simple_cases => cases}/import_spacing.py | 0 .../import_spacing.py.expect | 0 .../fixtures/black/cases/line_ranges_basic.py | 40 + .../black/cases/line_ranges_basic.py.expect | 63 + .../black/cases/line_ranges_diff_edge_case.py | 12 + .../line_ranges_diff_edge_case.py.expect | 13 + .../black/cases/line_ranges_fmt_off.py | 22 + .../black/cases/line_ranges_fmt_off.py.expect | 23 + .../cases/line_ranges_fmt_off_decorator.py | 11 + .../line_ranges_fmt_off_decorator.py.expect | 12 + .../cases/line_ranges_fmt_off_overlap.py | 16 + .../line_ranges_fmt_off_overlap.py.expect | 17 + .../black/cases/line_ranges_imports.py | 8 + .../black/cases/line_ranges_imports.py.expect | 8 + .../black/cases/line_ranges_indentation.py | 11 + .../cases/line_ranges_indentation.py.expect | 12 + .../black/cases/line_ranges_two_passes.py | 12 + .../cases/line_ranges_two_passes.py.expect | 11 + .../black/cases/line_ranges_unwrapping.py | 13 + .../cases/line_ranges_unwrapping.py.expect | 8 + .../black/cases/linelength6.options.json | 1 + .../{miscellaneous => cases}/linelength6.py | 0 .../linelength6.py.expect | 0 .../long_strings_flag_disabled.py | 0 .../long_strings_flag_disabled.py.expect | 0 .../cases/module_docstring_1.options.json | 1 + .../black/cases/module_docstring_1.py | 14 + .../black/cases/module_docstring_1.py.expect | 9 + .../cases/module_docstring_2.options.json | 1 + .../black/cases/module_docstring_2.py | 35 + .../black/cases/module_docstring_2.py.expect | 30 + .../cases/module_docstring_3.options.json | 1 + .../black/cases/module_docstring_3.py | 2 + .../black/cases/module_docstring_3.py.expect | 3 + .../cases/module_docstring_4.options.json | 1 + .../black/cases/module_docstring_4.py | 3 + .../black/cases/module_docstring_4.py.expect | 3 + ...e_docstring_followed_by_class.options.json | 1 + .../module_docstring_followed_by_class.py | 3 + ...dule_docstring_followed_by_class.py.expect | 5 + ...ocstring_followed_by_function.options.json | 1 + .../module_docstring_followed_by_function.py | 3 + ...e_docstring_followed_by_function.py.expect | 5 + ...ine_consecutive_open_parentheses_ignore.py | 0 ...secutive_open_parentheses_ignore.py.expect | 0 .../black/cases/nested_stub.options.json | 1 + .../test/fixtures/black/cases/nested_stub.pyi | 18 + .../black/cases/nested_stub.pyi.expect | 22 + .../{py_36 => cases}/numeric_literals.py | 2 - .../numeric_literals.py.expect | 2 - .../numeric_literals_skip_underscores.py | 2 - ...umeric_literals_skip_underscores.py.expect | 2 - .../one_element_subscript.py | 0 .../one_element_subscript.py.expect | 0 .../parenthesized_context_managers.py | 0 .../parenthesized_context_managers.py.expect | 0 .../pattern_matching_complex.py | 10 + .../pattern_matching_complex.py.expect | 10 + .../pattern_matching_extras.py | 22 +- .../pattern_matching_extras.py.expect | 22 +- .../pattern_matching_generic.py | 0 .../pattern_matching_generic.py.expect | 0 .../pattern_matching_simple.py | 0 .../pattern_matching_simple.py.expect | 0 .../pattern_matching_style.py | 0 .../pattern_matching_style.py.expect | 0 ...ep604_union_types_line_breaks.options.json | 1 + .../cases/pep604_union_types_line_breaks.py | 83 + .../pep604_union_types_line_breaks.py.expect | 101 + .../black/{py_38 => cases}/pep_570.py | 0 .../black/{py_38 => cases}/pep_570.py.expect | 0 .../black/{py_38 => cases}/pep_572.py | 0 .../black/{py_38 => cases}/pep_572.py.expect | 0 .../black/{py_310 => cases}/pep_572_py310.py | 0 .../{py_310 => cases}/pep_572_py310.py.expect | 0 .../black/{py_39 => cases}/pep_572_py39.py | 0 .../{py_39 => cases}/pep_572_py39.py.expect | 0 .../{py_38 => cases}/pep_572_remove_parens.py | 0 .../pep_572_remove_parens.py.expect | 0 .../black/{simple_cases => cases}/pep_604.py | 0 .../{simple_cases => cases}/pep_604.py.expect | 0 .../black/{py_311 => cases}/pep_646.py | 0 .../black/{py_311 => cases}/pep_646.py.expect | 0 .../black/{py_311 => cases}/pep_654.py | 0 .../black/{py_311 => cases}/pep_654.py.expect | 0 .../black/{py_311 => cases}/pep_654_style.py | 0 .../{py_311 => cases}/pep_654_style.py.expect | 0 .../black/cases/power_op_newline.options.json | 1 + .../power_op_newline.py | 0 .../power_op_newline.py.expect | 0 .../power_op_spacing.py | 14 + .../power_op_spacing.py.expect | 4 + .../prefer_rhs_split_reformatted.py | 0 .../prefer_rhs_split_reformatted.py.expect | 0 ...y_first_line_in_special_cases.options.json | 1 + ...allow_empty_first_line_in_special_cases.py | 51 + ...mpty_first_line_in_special_cases.py.expect | 51 + .../cases/preview_async_stmts.options.json | 1 + .../black/cases/preview_async_stmts.py | 11 + .../black/cases/preview_async_stmts.py.expect | 11 + .../black/cases/preview_cantfit.options.json | 1 + .../fixtures/black/cases/preview_cantfit.py | 39 + .../black/cases/preview_cantfit.py.expect | 63 + .../cases/preview_comments7.options.json | 1 + .../fixtures/black/cases/preview_comments7.py | 144 + .../black/cases/preview_comments7.py.expect | 161 ++ .../preview_context_managers_38.options.json | 1 + .../cases/preview_context_managers_38.py | 31 + .../preview_context_managers_38.py.expect | 18 + .../preview_context_managers_39.options.json | 1 + .../cases/preview_context_managers_39.py | 84 + .../preview_context_managers_39.py.expect | 85 + ...ntext_managers_autodetect_310.options.json | 1 + ...preview_context_managers_autodetect_310.py | 15 + ..._context_managers_autodetect_310.py.expect | 15 + ...ntext_managers_autodetect_311.options.json | 1 + ...preview_context_managers_autodetect_311.py | 16 + ..._context_managers_autodetect_311.py.expect | 16 + ...ontext_managers_autodetect_38.options.json | 1 + .../preview_context_managers_autodetect_38.py | 24 + ...w_context_managers_autodetect_38.py.expect | 19 + ...ontext_managers_autodetect_39.options.json | 1 + .../preview_context_managers_autodetect_39.py | 17 + ...w_context_managers_autodetect_39.py.expect | 14 + ...tring_no_string_normalization.options.json | 1 + ...view_docstring_no_string_normalization.py} | 0 ...cstring_no_string_normalization.py.expect} | 0 ...preview_dummy_implementations.options.json | 1 + .../cases/preview_dummy_implementations.py | 48 + .../preview_dummy_implementations.py.expect | 48 + .../cases/preview_form_feeds.options.json | 1 + .../black/cases/preview_form_feeds.py | 116 + .../black/cases/preview_form_feeds.py.expect | 101 + ...iew_format_unicode_escape_seq.options.json | 1 + .../preview_format_unicode_escape_seq.py | 15 + ...review_format_unicode_escape_seq.py.expect | 15 + ...th_braces_and_square_brackets.options.json | 1 + ..._parens_with_braces_and_square_brackets.py | 185 ++ ..._with_braces_and_square_brackets.py.expect | 255 ++ .../preview_long_dict_values.options.json | 1 + .../black/cases/preview_long_dict_values.py | 36 + .../cases/preview_long_dict_values.py.expect | 49 + .../cases/preview_long_strings.options.json | 1 + .../black/cases/preview_long_strings.py | 329 +++ .../cases/preview_long_strings.py.expect | 594 ++++ ...ong_strings__east_asian_width.options.json | 1 + .../preview_long_strings__east_asian_width.py | 6 + ...w_long_strings__east_asian_width.py.expect | 16 + ...eview_long_strings__edge_case.options.json | 1 + .../cases/preview_long_strings__edge_case.py | 37 + .../preview_long_strings__edge_case.py.expect | 98 + ...view_long_strings__regression.options.json | 1 + .../cases/preview_long_strings__regression.py | 561 ++++ ...preview_long_strings__regression.py.expect | 680 +++++ ...ong_strings__type_annotations.options.json | 1 + .../preview_long_strings__type_annotations.py | 28 + ...w_long_strings__type_annotations.py.expect | 26 + .../preview_multiline_strings.options.json | 1 + .../black/cases/preview_multiline_strings.py | 175 ++ .../cases/preview_multiline_strings.py.expect | 209 ++ ...o_blank_line_before_docstring.options.json | 1 + .../preview_no_blank_line_before_docstring.py | 29 + ...w_no_blank_line_before_docstring.py.expect | 24 + ...preview_pattern_matching_long.options.json | 1 + .../cases/preview_pattern_matching_long.py | 7 + .../preview_pattern_matching_long.py.expect | 23 + ...ttern_matching_trailing_comma.options.json | 1 + ...preview_pattern_matching_trailing_comma.py | 14 + ..._pattern_matching_trailing_comma.py.expect | 20 + .../black/cases/preview_pep_572.options.json | 1 + .../fixtures/black/cases/preview_pep_572.py | 2 + .../black/cases/preview_pep_572.py.expect | 2 + .../preview_percent_precedence.options.json | 1 + .../black/cases/preview_percent_precedence.py | 20 + .../preview_percent_precedence.py.expect | 20 + .../preview_power_op_spacing.options.json | 1 + .../black/cases/preview_power_op_spacing.py | 11 + .../cases/preview_power_op_spacing.py.expect | 83 + .../preview_prefer_rhs_split.options.json | 1 + .../black/cases/preview_prefer_rhs_split.py | 106 + .../cases/preview_prefer_rhs_split.py.expect | 106 + ...rn_annotation_brackets_string.options.json | 1 + ...eview_return_annotation_brackets_string.py | 7 + ...eturn_annotation_brackets_string.py.expect | 13 + ...t_skip_with_multiple_comments.options.json | 1 + ...line_format_skip_with_multiple_comments.py | 8 + ...rmat_skip_with_multiple_comments.py.expect | 8 + .../cases/preview_trailing_comma.options.json | 1 + .../black/cases/preview_trailing_comma.py | 24 + .../cases/preview_trailing_comma.py.expect | 28 + .../black/cases/py310_pep572.options.json | 1 + .../test/fixtures/black/cases/py310_pep572.py | 5 + .../black/cases/py310_pep572.py.expect | 5 + .../black/{py_37 => cases}/python37.py | 3 - .../black/{py_37 => cases}/python37.py.expect | 3 - .../black/{py_38 => cases}/python38.py | 3 - .../black/{py_38 => cases}/python38.py.expect | 3 - .../black/{py_39 => cases}/python39.py | 2 - .../black/{py_39 => cases}/python39.py.expect | 3 - .../black/cases/raw_docstring.options.json | 1 + .../fixtures/black/cases/raw_docstring.py | 15 + .../black/cases/raw_docstring.py.expect | 14 + .../remove_await_parens.py | 9 + .../remove_await_parens.py.expect | 10 + .../remove_except_parens.py | 0 .../remove_except_parens.py.expect | 0 .../remove_for_brackets.py | 0 .../remove_for_brackets.py.expect | 0 .../remove_newline_after_code_block_open.py | 0 ...ve_newline_after_code_block_open.py.expect | 0 .../remove_newline_after_match.py | 0 .../remove_newline_after_match.py.expect | 0 .../{simple_cases => cases}/remove_parens.py | 0 .../remove_parens.py.expect | 0 .../{py_39 => cases}/remove_with_brackets.py | 0 .../remove_with_brackets.py.expect | 0 .../return_annotation_brackets.py | 5 + .../return_annotation_brackets.py.expect | 8 + .../skip_magic_trailing_comma.options.json | 1 + .../skip_magic_trailing_comma.py | 0 .../skip_magic_trailing_comma.py.expect | 0 .../black/{simple_cases => cases}/slices.py | 0 .../{simple_cases => cases}/slices.py.expect | 0 .../{py_310 => cases}/starred_for_target.py | 0 .../starred_for_target.py.expect | 0 .../string_prefixes.py | 0 .../string_prefixes.py.expect | 0 .../test/fixtures/black/cases/stub.pyi | 75 + .../test/fixtures/black/cases/stub.pyi.expect | 73 + .../black/{simple_cases => cases}/torture.py | 0 .../{simple_cases => cases}/torture.py.expect | 0 .../trailing_comma_optional_parens1.py | 0 .../trailing_comma_optional_parens1.py.expect | 0 .../trailing_comma_optional_parens2.py | 0 .../trailing_comma_optional_parens2.py.expect | 0 .../trailing_comma_optional_parens3.py | 0 .../trailing_comma_optional_parens3.py.expect | 0 .../trailing_commas_in_leading_parts.py | 0 ...trailing_commas_in_leading_parts.py.expect | 0 .../tricky_unicode_symbols.py | 0 .../tricky_unicode_symbols.py.expect | 0 .../{simple_cases => cases}/tupleassign.py | 0 .../tupleassign.py.expect | 0 .../type_comment_syntax_error.py | 0 .../type_comment_syntax_error.py.expect | 0 .../black/{py_312 => cases}/type_params.py | 0 .../{py_312 => cases}/type_params.py.expect | 0 .../{simple_cases => cases}/whitespace.py | 0 .../whitespace.py.expect | 0 .../black/miscellaneous/decorators.py | 150 - .../black/miscellaneous/decorators.py.expect | 29 - .../fixtures/black/miscellaneous/force_pyi.py | 1 - .../black/miscellaneous/force_pyi.pyi | 30 + .../black/miscellaneous/force_pyi.pyi.expect | 32 + .../fixtures/black/py_312/type_aliases.py | 5 - .../black/py_312/type_aliases.py.expect | 5 - .../black/simple_cases/docstring.options.json | 3 - .../skip_magic_trailing_comma.options.json | 3 - .../test/fixtures/import_black_tests.py | 71 +- .../src/expression/string/docstring.rs | 17 +- .../ruff_python_formatter/tests/fixtures.rs | 17 +- ...es__comment_after_escaped_newline.py.snap} | 2 +- ...ck_compatibility@cases__comments2.py.snap} | 2 +- ...ck_compatibility@cases__comments6.py.snap} | 2 +- ...ck_compatibility@cases__comments9.py.snap} | 2 +- ...tibility@cases__comments_in_blocks.py.snap | 382 +++ ..._compatibility@cases__composition.py.snap} | 2 +- ...es__composition_no_trailing_comma.py.snap} | 2 +- ...lity@cases__conditional_expression.py.snap | 334 +++ ...docstring_no_string_normalization.py.snap} | 2 +- ...k_compatibility@cases__expression.py.snap} | 2 +- ...ack_compatibility@cases__fmtonoff.py.snap} | 2 +- ...ck_compatibility@cases__fmtonoff4.py.snap} | 2 +- ...ck_compatibility@cases__fmtonoff5.py.snap} | 2 +- ...patibility@cases__fmtpass_imports.py.snap} | 2 +- ...ack_compatibility@cases__fmtskip5.py.snap} | 2 +- ...funcdef_return_type_trailing_comma.py.snap | 608 ++++ ...ack_compatibility@cases__function.py.snap} | 2 +- ...ck_compatibility@cases__function2.py.snap} | 2 +- ..._compatibility@cases__ignore_pyi.pyi.snap} | 59 +- ...atibility@cases__line_ranges_basic.py.snap | 317 ++ ...@cases__line_ranges_diff_edge_case.py.snap | 79 + ...ibility@cases__line_ranges_fmt_off.py.snap | 114 + ...ses__line_ranges_fmt_off_decorator.py.snap | 74 + ...cases__line_ranges_fmt_off_overlap.py.snap | 93 + ...ity@cases__line_ranges_indentation.py.snap | 72 + ...lity@cases__line_ranges_two_passes.py.snap | 77 + ...lity@cases__line_ranges_unwrapping.py.snap | 60 + ...cases__long_strings_flag_disabled.py.snap} | 2 +- ...nsecutive_open_parentheses_ignore.py.snap} | 2 +- ..._compatibility@cases__nested_stub.pyi.snap | 126 + ...ity@cases__pattern_matching_style.py.snap} | 2 +- ...es__pep604_union_types_line_breaks.py.snap | 370 +++ ...ompatibility@cases__pep_572_py310.py.snap} | 2 +- ...lity@cases__pep_572_remove_parens.py.snap} | 2 +- ...atibility@cases__power_op_newline.py.snap} | 2 +- ..._empty_first_line_in_special_cases.py.snap | 218 ++ ...mpatibility@cases__preview_cantfit.py.snap | 219 ++ ...atibility@cases__preview_comments7.py.snap | 600 ++++ ...cases__preview_context_managers_39.py.snap | 342 +++ ...ew_context_managers_autodetect_310.py.snap | 79 + ...ew_context_managers_autodetect_311.py.snap | 82 + ...iew_context_managers_autodetect_39.py.snap | 81 + ...docstring_no_string_normalization.py.snap} | 2 +- ...ses__preview_dummy_implementations.py.snap | 231 ++ ...tibility@cases__preview_form_feeds.py.snap | 446 +++ ..._preview_format_unicode_escape_seq.py.snap | 97 + ...ns_with_braces_and_square_brackets.py.snap | 1212 ++++++++ ...ty@cases__preview_long_dict_values.py.snap | 201 ++ ...bility@cases__preview_long_strings.py.snap | 2038 +++++++++++++ ...iew_long_strings__east_asian_width.py.snap | 75 + ...s__preview_long_strings__edge_case.py.snap | 340 +++ ...__preview_long_strings__regression.py.snap | 2565 +++++++++++++++++ ...iew_long_strings__type_annotations.py.snap | 115 + ...y@cases__preview_multiline_strings.py.snap | 923 ++++++ ...iew_no_blank_line_before_docstring.py.snap | 134 + ...ew_pattern_matching_trailing_comma.py.snap | 104 + ...mpatibility@cases__preview_pep_572.py.snap | 38 + ...@cases__preview_percent_precedence.py.snap | 99 + ...ty@cases__preview_power_op_spacing.py.snap | 354 +++ ...ty@cases__preview_prefer_rhs_split.py.snap | 457 +++ ..._return_annotation_brackets_string.py.snap | 75 + ...format_skip_with_multiple_comments.py.snap | 64 + ...compatibility@cases__raw_docstring.py.snap | 89 + ...bility@cases__remove_await_parens.py.snap} | 31 +- ...ility@cases__remove_except_parens.py.snap} | 2 +- ...bility@cases__remove_for_brackets.py.snap} | 2 +- ...cases__return_annotation_brackets.py.snap} | 38 +- .../black_compatibility@cases__stub.pyi.snap | 288 ++ ...lack_compatibility@cases__torture.py.snap} | 2 +- ..._trailing_commas_in_leading_parts.py.snap} | 2 +- ..._compatibility@cases__tupleassign.py.snap} | 2 +- ...tibility@miscellaneous__decorators.py.snap | 624 ---- ...atibility@miscellaneous__force_pyi.py.snap | 13 +- ...tibility@miscellaneous__force_pyi.pyi.snap | 128 + ...ty@py_310__pattern_matching_extras.py.snap | 420 --- ...ty@simple_cases__docstring_preview.py.snap | 184 -- 435 files changed, 21436 insertions(+), 1595 deletions(-) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/attribute_access_on_number_literals.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/attribute_access_on_number_literals.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/beginning_backslash.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/beginning_backslash.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/bracketmatch.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/bracketmatch.py.expect (100%) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/bytes_docstring.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/bytes_docstring.py.expect rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/class_blank_parentheses.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/class_blank_parentheses.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/class_methods_new_line.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/class_methods_new_line.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/collections.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/collections.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comment_after_escaped_newline.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comment_after_escaped_newline.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments2.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments2.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments3.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments3.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments4.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments4.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments5.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments5.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments6.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments6.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments8.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments8.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments9.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments9.py.expect (100%) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments_in_blocks.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments_in_blocks.py.expect rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments_non_breaking_space.py (90%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/comments_non_breaking_space.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/composition.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/composition.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/composition_no_trailing_comma.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/composition_no_trailing_comma.py.expect (100%) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/conditional_expression.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/conditional_expression.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/conditional_expression.py.expect rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/docstring.py (97%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/docstring.py.expect (97%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/docstring_no_extra_empty_line_before_eof.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/docstring_no_extra_empty_line_before_eof.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{miscellaneous => cases}/docstring_no_string_normalization.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{miscellaneous => cases}/docstring_no_string_normalization.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/docstring_preview.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/docstring_preview.py.expect (98%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/empty_lines.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/empty_lines.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/expression.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/expression.py.expect (100%) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/f_docstring.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/f_docstring.py.expect rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtonoff.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtonoff.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtonoff2.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtonoff2.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtonoff3.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtonoff3.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtonoff4.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtonoff4.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtonoff5.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtonoff5.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtpass_imports.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtpass_imports.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip2.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip2.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip3.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip3.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip4.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip4.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip5.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip5.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip6.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip6.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip7.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip7.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip8.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fmtskip8.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fstring.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/fstring.py.expect (100%) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.py.expect rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/function.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/function.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/function2.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/function2.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/function_trailing_comma.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/function_trailing_comma.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases/ignore_pyi.py => cases/ignore_pyi.pyi} (71%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases/ignore_pyi.py.expect => cases/ignore_pyi.pyi.expect} (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/import_spacing.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/import_spacing.py.expect (100%) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_basic.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_basic.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_diff_edge_case.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_diff_edge_case.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_overlap.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_overlap.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_imports.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_imports.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_indentation.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_indentation.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_two_passes.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_two_passes.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_unwrapping.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_unwrapping.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/linelength6.options.json rename crates/ruff_python_formatter/resources/test/fixtures/black/{miscellaneous => cases}/linelength6.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{miscellaneous => cases}/linelength6.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{miscellaneous => cases}/long_strings_flag_disabled.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{miscellaneous => cases}/long_strings_flag_disabled.py.expect (100%) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_1.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_1.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_1.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_2.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_2.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_2.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_3.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_3.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_3.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_4.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_4.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_4.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_class.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_class.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_class.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_function.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_function.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_function.py.expect rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/multiline_consecutive_open_parentheses_ignore.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/multiline_consecutive_open_parentheses_ignore.py.expect (100%) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/nested_stub.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/nested_stub.pyi create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/nested_stub.pyi.expect rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_36 => cases}/numeric_literals.py (91%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_36 => cases}/numeric_literals.py.expect (91%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_36 => cases}/numeric_literals_skip_underscores.py (79%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_36 => cases}/numeric_literals_skip_underscores.py.expect (79%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/one_element_subscript.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/one_element_subscript.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/parenthesized_context_managers.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/parenthesized_context_managers.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/pattern_matching_complex.py (90%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/pattern_matching_complex.py.expect (90%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/pattern_matching_extras.py (88%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/pattern_matching_extras.py.expect (88%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/pattern_matching_generic.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/pattern_matching_generic.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/pattern_matching_simple.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/pattern_matching_simple.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/pattern_matching_style.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/pattern_matching_style.py.expect (100%) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.py.expect rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_38 => cases}/pep_570.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_38 => cases}/pep_570.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_38 => cases}/pep_572.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_38 => cases}/pep_572.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/pep_572_py310.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/pep_572_py310.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_39 => cases}/pep_572_py39.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_39 => cases}/pep_572_py39.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_38 => cases}/pep_572_remove_parens.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_38 => cases}/pep_572_remove_parens.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/pep_604.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/pep_604.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_311 => cases}/pep_646.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_311 => cases}/pep_646.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_311 => cases}/pep_654.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_311 => cases}/pep_654.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_311 => cases}/pep_654_style.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_311 => cases}/pep_654_style.py.expect (100%) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_newline.options.json rename crates/ruff_python_formatter/resources/test/fixtures/black/{miscellaneous => cases}/power_op_newline.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{miscellaneous => cases}/power_op_newline.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/power_op_spacing.py (93%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/power_op_spacing.py.expect (96%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/prefer_rhs_split_reformatted.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/prefer_rhs_split_reformatted.py.expect (100%) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_allow_empty_first_line_in_special_cases.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_allow_empty_first_line_in_special_cases.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_allow_empty_first_line_in_special_cases.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_async_stmts.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_async_stmts.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_async_stmts.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_cantfit.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_cantfit.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_cantfit.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_comments7.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_comments7.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_comments7.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_38.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_38.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_38.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_39.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_39.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_39.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_310.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_310.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_310.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_311.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_311.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_311.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_38.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_38.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_38.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_39.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_39.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_39.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_docstring_no_string_normalization.options.json rename crates/ruff_python_formatter/resources/test/fixtures/black/{miscellaneous/docstring_preview_no_string_normalization.py => cases/preview_docstring_no_string_normalization.py} (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{miscellaneous/docstring_preview_no_string_normalization.py.expect => cases/preview_docstring_no_string_normalization.py.expect} (100%) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_dummy_implementations.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_dummy_implementations.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_dummy_implementations.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_form_feeds.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_form_feeds.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_form_feeds.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_format_unicode_escape_seq.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_format_unicode_escape_seq.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_format_unicode_escape_seq.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_hug_parens_with_braces_and_square_brackets.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_hug_parens_with_braces_and_square_brackets.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_hug_parens_with_braces_and_square_brackets.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_dict_values.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_dict_values.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_dict_values.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__east_asian_width.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__east_asian_width.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__east_asian_width.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__edge_case.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__edge_case.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__edge_case.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__regression.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__regression.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__regression.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__type_annotations.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__type_annotations.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__type_annotations.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_multiline_strings.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_multiline_strings.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_multiline_strings.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_no_blank_line_before_docstring.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_no_blank_line_before_docstring.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_no_blank_line_before_docstring.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_long.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_long.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_long.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_trailing_comma.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_trailing_comma.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_trailing_comma.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep_572.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep_572.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep_572.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_percent_precedence.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_percent_precedence.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_percent_precedence.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_power_op_spacing.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_power_op_spacing.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_power_op_spacing.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_prefer_rhs_split.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_prefer_rhs_split.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_prefer_rhs_split.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_return_annotation_brackets_string.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_return_annotation_brackets_string.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_return_annotation_brackets_string.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_single_line_format_skip_with_multiple_comments.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_single_line_format_skip_with_multiple_comments.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_single_line_format_skip_with_multiple_comments.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_trailing_comma.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_trailing_comma.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_trailing_comma.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.py.expect rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_37 => cases}/python37.py (95%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_37 => cases}/python37.py.expect (95%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_38 => cases}/python38.py (93%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_38 => cases}/python38.py.expect (93%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_39 => cases}/python39.py (92%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_39 => cases}/python39.py.expect (92%) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/raw_docstring.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/raw_docstring.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/raw_docstring.py.expect rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/remove_await_parens.py (90%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/remove_await_parens.py.expect (90%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/remove_except_parens.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/remove_except_parens.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/remove_for_brackets.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/remove_for_brackets.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/remove_newline_after_code_block_open.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/remove_newline_after_code_block_open.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/remove_newline_after_match.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/remove_newline_after_match.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/remove_parens.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/remove_parens.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_39 => cases}/remove_with_brackets.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_39 => cases}/remove_with_brackets.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/return_annotation_brackets.py (93%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/return_annotation_brackets.py.expect (92%) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/skip_magic_trailing_comma.options.json rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/skip_magic_trailing_comma.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/skip_magic_trailing_comma.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/slices.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/slices.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/starred_for_target.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_310 => cases}/starred_for_target.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/string_prefixes.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/string_prefixes.py.expect (100%) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/stub.pyi create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/cases/stub.pyi.expect rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/torture.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/torture.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/trailing_comma_optional_parens1.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/trailing_comma_optional_parens1.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/trailing_comma_optional_parens2.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/trailing_comma_optional_parens2.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/trailing_comma_optional_parens3.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/trailing_comma_optional_parens3.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/trailing_commas_in_leading_parts.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/trailing_commas_in_leading_parts.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/tricky_unicode_symbols.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/tricky_unicode_symbols.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/tupleassign.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/tupleassign.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{type_comments => cases}/type_comment_syntax_error.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{type_comments => cases}/type_comment_syntax_error.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_312 => cases}/type_params.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{py_312 => cases}/type_params.py.expect (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/whitespace.py (100%) rename crates/ruff_python_formatter/resources/test/fixtures/black/{simple_cases => cases}/whitespace.py.expect (100%) delete mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/decorators.py delete mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/decorators.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/force_pyi.pyi create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/force_pyi.pyi.expect delete mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/py_312/type_aliases.py delete mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/py_312/type_aliases.py.expect delete mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring.options.json delete mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/skip_magic_trailing_comma.options.json rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__comment_after_escaped_newline.py.snap => black_compatibility@cases__comment_after_escaped_newline.py.snap} (93%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__comments2.py.snap => black_compatibility@cases__comments2.py.snap} (99%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__comments6.py.snap => black_compatibility@cases__comments6.py.snap} (99%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__comments9.py.snap => black_compatibility@cases__comments9.py.snap} (99%) create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comments_in_blocks.py.snap rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__composition.py.snap => black_compatibility@cases__composition.py.snap} (99%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__composition_no_trailing_comma.py.snap => black_compatibility@cases__composition_no_trailing_comma.py.snap} (99%) create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__conditional_expression.py.snap rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@miscellaneous__docstring_no_string_normalization.py.snap => black_compatibility@cases__docstring_no_string_normalization.py.snap} (99%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__expression.py.snap => black_compatibility@cases__expression.py.snap} (99%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__fmtonoff.py.snap => black_compatibility@cases__fmtonoff.py.snap} (99%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__fmtonoff4.py.snap => black_compatibility@cases__fmtonoff4.py.snap} (96%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__fmtonoff5.py.snap => black_compatibility@cases__fmtonoff5.py.snap} (99%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__fmtpass_imports.py.snap => black_compatibility@cases__fmtpass_imports.py.snap} (96%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__fmtskip5.py.snap => black_compatibility@cases__fmtskip5.py.snap} (96%) create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__funcdef_return_type_trailing_comma.py.snap rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__function.py.snap => black_compatibility@cases__function.py.snap} (99%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__function2.py.snap => black_compatibility@cases__function2.py.snap} (99%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__ignore_pyi.py.snap => black_compatibility@cases__ignore_pyi.pyi.snap} (71%) create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_basic.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_diff_edge_case.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off_decorator.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off_overlap.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_indentation.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_two_passes.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_unwrapping.py.snap rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@miscellaneous__long_strings_flag_disabled.py.snap => black_compatibility@cases__long_strings_flag_disabled.py.snap} (99%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__multiline_consecutive_open_parentheses_ignore.py.snap => black_compatibility@cases__multiline_consecutive_open_parentheses_ignore.py.snap} (95%) create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__nested_stub.pyi.snap rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@py_310__pattern_matching_style.py.snap => black_compatibility@cases__pattern_matching_style.py.snap} (98%) create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pep604_union_types_line_breaks.py.snap rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@py_310__pep_572_py310.py.snap => black_compatibility@cases__pep_572_py310.py.snap} (98%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@py_38__pep_572_remove_parens.py.snap => black_compatibility@cases__pep_572_remove_parens.py.snap} (98%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@miscellaneous__power_op_newline.py.snap => black_compatibility@cases__power_op_newline.py.snap} (91%) create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_allow_empty_first_line_in_special_cases.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_cantfit.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_comments7.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_39.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_autodetect_310.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_autodetect_311.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_autodetect_39.py.snap rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@miscellaneous__docstring_preview_no_string_normalization.py.snap => black_compatibility@cases__preview_docstring_no_string_normalization.py.snap} (96%) create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_dummy_implementations.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_form_feeds.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_format_unicode_escape_seq.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_hug_parens_with_braces_and_square_brackets.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_dict_values.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__east_asian_width.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__edge_case.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__regression.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__type_annotations.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_multiline_strings.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_no_blank_line_before_docstring.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_pattern_matching_trailing_comma.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_pep_572.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_percent_precedence.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_power_op_spacing.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_prefer_rhs_split.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_return_annotation_brackets_string.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_single_line_format_skip_with_multiple_comments.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__raw_docstring.py.snap rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__remove_await_parens.py.snap => black_compatibility@cases__remove_await_parens.py.snap} (90%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__remove_except_parens.py.snap => black_compatibility@cases__remove_except_parens.py.snap} (98%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__remove_for_brackets.py.snap => black_compatibility@cases__remove_for_brackets.py.snap} (98%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__return_annotation_brackets.py.snap => black_compatibility@cases__return_annotation_brackets.py.snap} (90%) create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__stub.pyi.snap rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__torture.py.snap => black_compatibility@cases__torture.py.snap} (99%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__trailing_commas_in_leading_parts.py.snap => black_compatibility@cases__trailing_commas_in_leading_parts.py.snap} (98%) rename crates/ruff_python_formatter/tests/snapshots/{black_compatibility@simple_cases__tupleassign.py.snap => black_compatibility@cases__tupleassign.py.snap} (97%) delete mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__decorators.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__force_pyi.pyi.snap delete mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_extras.py.snap delete mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__docstring_preview.py.snap diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/attribute_access_on_number_literals.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/attribute_access_on_number_literals.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/attribute_access_on_number_literals.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/attribute_access_on_number_literals.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/attribute_access_on_number_literals.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/attribute_access_on_number_literals.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/attribute_access_on_number_literals.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/attribute_access_on_number_literals.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/beginning_backslash.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/beginning_backslash.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/beginning_backslash.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/beginning_backslash.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/beginning_backslash.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/beginning_backslash.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/beginning_backslash.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/beginning_backslash.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/bracketmatch.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/bracketmatch.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/bracketmatch.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/bracketmatch.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/bracketmatch.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/bracketmatch.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/bracketmatch.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/bracketmatch.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/bytes_docstring.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/bytes_docstring.py new file mode 100644 index 0000000000000..488aef1ed7649 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/bytes_docstring.py @@ -0,0 +1,14 @@ +def bitey(): + b" not a docstring" + +def bitey2(): + b' also not a docstring' + +def triple_quoted_bytes(): + b""" not a docstring""" + +def triple_quoted_bytes2(): + b''' also not a docstring''' + +def capitalized_bytes(): + B" NOT A DOCSTRING" diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/bytes_docstring.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/bytes_docstring.py.expect new file mode 100644 index 0000000000000..d7ce57746e2be --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/bytes_docstring.py.expect @@ -0,0 +1,18 @@ +def bitey(): + b" not a docstring" + + +def bitey2(): + b" also not a docstring" + + +def triple_quoted_bytes(): + b""" not a docstring""" + + +def triple_quoted_bytes2(): + b""" also not a docstring""" + + +def capitalized_bytes(): + b" NOT A DOCSTRING" diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/class_blank_parentheses.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/class_blank_parentheses.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/class_blank_parentheses.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/class_blank_parentheses.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/class_blank_parentheses.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/class_blank_parentheses.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/class_blank_parentheses.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/class_blank_parentheses.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/class_methods_new_line.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/class_methods_new_line.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/class_methods_new_line.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/class_methods_new_line.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/class_methods_new_line.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/class_methods_new_line.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/class_methods_new_line.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/class_methods_new_line.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/collections.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/collections.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/collections.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/collections.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/collections.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/collections.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/collections.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/collections.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comment_after_escaped_newline.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comment_after_escaped_newline.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comment_after_escaped_newline.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comment_after_escaped_newline.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comment_after_escaped_newline.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comment_after_escaped_newline.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comment_after_escaped_newline.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comment_after_escaped_newline.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments2.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments2.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments2.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments2.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments2.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments2.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments2.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments2.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments3.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments3.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments3.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments3.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments3.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments3.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments3.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments3.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments4.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments4.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments4.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments4.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments4.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments4.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments4.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments4.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments5.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments5.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments5.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments5.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments5.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments5.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments5.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments5.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments6.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments6.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments6.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments6.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments6.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments6.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments6.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments6.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments8.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments8.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments8.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments8.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments8.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments8.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments8.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments8.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments9.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments9.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments9.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments9.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments9.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments9.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments9.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments9.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments_in_blocks.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments_in_blocks.py new file mode 100644 index 0000000000000..1221139b6d818 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments_in_blocks.py @@ -0,0 +1,111 @@ +# Test cases from: +# - https://github.com/psf/black/issues/1798 +# - https://github.com/psf/black/issues/1499 +# - https://github.com/psf/black/issues/1211 +# - https://github.com/psf/black/issues/563 + +( + lambda + # a comment + : None +) + +( + lambda: + # b comment + None +) + +( + lambda + # a comment + : + # b comment + None +) + +[ + x + # Let's do this + for + # OK? + x + # Some comment + # And another + in + # One more + y +] + +return [ + (offers[offer_index], 1.0) + for offer_index, _ + # avoid returning any offers that don't match the grammar so + # that the return values here are consistent with what would be + # returned in AcceptValidHeader + in self._parse_and_normalize_offers(offers) +] + +from foo import ( + bar, + # qux +) + + +def convert(collection): + # replace all variables by integers + replacement_dict = { + variable: f"{index}" + for index, variable + # 0 is reserved as line terminator + in enumerate(collection.variables(), start=1) + } + + +{ + i: i + for i + # a comment + in range(5) +} + + +def get_subtree_proof_nodes( + chunk_index_groups: Sequence[Tuple[int, ...], ...], +) -> Tuple[int, ...]: + subtree_node_paths = ( + # We take a candidate element from each group and shift it to + # remove the bits that are not common to other group members, then + # we convert it to a tree path that all elements from this group + # have in common. + chunk_index + for chunk_index, bits_to_truncate + # Each group will contain an even "power-of-two" number of# elements. + # This tells us how many tailing bits each element has# which need to + # be truncated to get the group's common prefix. + in ((group[0], (len(group) - 1).bit_length()) for group in chunk_index_groups) + ) + return subtree_node_paths + + +if ( + # comment1 + a + # comment2 + or ( + # comment3 + ( + # comment4 + b + ) + # comment5 + and + # comment6 + c + or ( + # comment7 + d + ) + ) +): + print("Foo") diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments_in_blocks.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments_in_blocks.py.expect new file mode 100644 index 0000000000000..1221139b6d818 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments_in_blocks.py.expect @@ -0,0 +1,111 @@ +# Test cases from: +# - https://github.com/psf/black/issues/1798 +# - https://github.com/psf/black/issues/1499 +# - https://github.com/psf/black/issues/1211 +# - https://github.com/psf/black/issues/563 + +( + lambda + # a comment + : None +) + +( + lambda: + # b comment + None +) + +( + lambda + # a comment + : + # b comment + None +) + +[ + x + # Let's do this + for + # OK? + x + # Some comment + # And another + in + # One more + y +] + +return [ + (offers[offer_index], 1.0) + for offer_index, _ + # avoid returning any offers that don't match the grammar so + # that the return values here are consistent with what would be + # returned in AcceptValidHeader + in self._parse_and_normalize_offers(offers) +] + +from foo import ( + bar, + # qux +) + + +def convert(collection): + # replace all variables by integers + replacement_dict = { + variable: f"{index}" + for index, variable + # 0 is reserved as line terminator + in enumerate(collection.variables(), start=1) + } + + +{ + i: i + for i + # a comment + in range(5) +} + + +def get_subtree_proof_nodes( + chunk_index_groups: Sequence[Tuple[int, ...], ...], +) -> Tuple[int, ...]: + subtree_node_paths = ( + # We take a candidate element from each group and shift it to + # remove the bits that are not common to other group members, then + # we convert it to a tree path that all elements from this group + # have in common. + chunk_index + for chunk_index, bits_to_truncate + # Each group will contain an even "power-of-two" number of# elements. + # This tells us how many tailing bits each element has# which need to + # be truncated to get the group's common prefix. + in ((group[0], (len(group) - 1).bit_length()) for group in chunk_index_groups) + ) + return subtree_node_paths + + +if ( + # comment1 + a + # comment2 + or ( + # comment3 + ( + # comment4 + b + ) + # comment5 + and + # comment6 + c + or ( + # comment7 + d + ) + ) +): + print("Foo") diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments_non_breaking_space.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments_non_breaking_space.py similarity index 90% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments_non_breaking_space.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments_non_breaking_space.py index 0c5f5660ebba9..d1d42f025969c 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments_non_breaking_space.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments_non_breaking_space.py @@ -14,6 +14,6 @@ def function(a:int=42): a b """ - #    There's a NBSP + 3 spaces before + #  There's a NBSP + 3 spaces before # And 4 spaces on the next line pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments_non_breaking_space.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments_non_breaking_space.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments_non_breaking_space.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments_non_breaking_space.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/composition.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/composition.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/composition.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/composition.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/composition.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/composition.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/composition.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/composition.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/composition_no_trailing_comma.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/composition_no_trailing_comma.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/composition_no_trailing_comma.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/composition_no_trailing_comma.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/composition_no_trailing_comma.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/composition_no_trailing_comma.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/composition_no_trailing_comma.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/composition_no_trailing_comma.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/conditional_expression.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/conditional_expression.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/conditional_expression.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/conditional_expression.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/conditional_expression.py new file mode 100644 index 0000000000000..bbe56623c6107 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/conditional_expression.py @@ -0,0 +1,67 @@ +long_kwargs_single_line = my_function( + foo="test, this is a sample value", + bar=some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz, + baz="hello, this is a another value", +) + +multiline_kwargs_indented = my_function( + foo="test, this is a sample value", + bar=some_long_value_name_foo_bar_baz + if some_boolean_variable + else some_fallback_value_foo_bar_baz, + baz="hello, this is a another value", +) + +imploding_kwargs = my_function( + foo="test, this is a sample value", + bar=a + if foo + else b, + baz="hello, this is a another value", +) + +imploding_line = ( + 1 + if 1 + 1 == 2 + else 0 +) + +exploding_line = "hello this is a slightly long string" if some_long_value_name_foo_bar_baz else "this one is a little shorter" + +positional_argument_test(some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz) + +def weird_default_argument(x=some_long_value_name_foo_bar_baz + if SOME_CONSTANT + else some_fallback_value_foo_bar_baz): + pass + +nested = "hello this is a slightly long string" if (some_long_value_name_foo_bar_baz if + nesting_test_expressions else some_fallback_value_foo_bar_baz) \ + else "this one is a little shorter" + +generator_expression = ( + some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz for some_boolean_variable in some_iterable +) + + +def limit_offset_sql(self, low_mark, high_mark): + """Return LIMIT/OFFSET SQL clause.""" + limit, offset = self._get_limit_offset_params(low_mark, high_mark) + return " ".join( + sql + for sql in ( + "LIMIT %d" % limit if limit else None, + ("OFFSET %d" % offset) if offset else None, + ) + if sql + ) + + +def something(): + clone._iterable_class = ( + NamedValuesListIterable + if named + else FlatValuesListIterable + if flat + else ValuesListIterable + ) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/conditional_expression.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/conditional_expression.py.expect new file mode 100644 index 0000000000000..122ea7860dea7 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/conditional_expression.py.expect @@ -0,0 +1,90 @@ +long_kwargs_single_line = my_function( + foo="test, this is a sample value", + bar=( + some_long_value_name_foo_bar_baz + if some_boolean_variable + else some_fallback_value_foo_bar_baz + ), + baz="hello, this is a another value", +) + +multiline_kwargs_indented = my_function( + foo="test, this is a sample value", + bar=( + some_long_value_name_foo_bar_baz + if some_boolean_variable + else some_fallback_value_foo_bar_baz + ), + baz="hello, this is a another value", +) + +imploding_kwargs = my_function( + foo="test, this is a sample value", + bar=a if foo else b, + baz="hello, this is a another value", +) + +imploding_line = 1 if 1 + 1 == 2 else 0 + +exploding_line = ( + "hello this is a slightly long string" + if some_long_value_name_foo_bar_baz + else "this one is a little shorter" +) + +positional_argument_test( + some_long_value_name_foo_bar_baz + if some_boolean_variable + else some_fallback_value_foo_bar_baz +) + + +def weird_default_argument( + x=( + some_long_value_name_foo_bar_baz + if SOME_CONSTANT + else some_fallback_value_foo_bar_baz + ), +): + pass + + +nested = ( + "hello this is a slightly long string" + if ( + some_long_value_name_foo_bar_baz + if nesting_test_expressions + else some_fallback_value_foo_bar_baz + ) + else "this one is a little shorter" +) + +generator_expression = ( + ( + some_long_value_name_foo_bar_baz + if some_boolean_variable + else some_fallback_value_foo_bar_baz + ) + for some_boolean_variable in some_iterable +) + + +def limit_offset_sql(self, low_mark, high_mark): + """Return LIMIT/OFFSET SQL clause.""" + limit, offset = self._get_limit_offset_params(low_mark, high_mark) + return " ".join( + sql + for sql in ( + "LIMIT %d" % limit if limit else None, + ("OFFSET %d" % offset) if offset else None, + ) + if sql + ) + + +def something(): + clone._iterable_class = ( + NamedValuesListIterable + if named + else FlatValuesListIterable if flat else ValuesListIterable + ) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring.py similarity index 97% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring.py index e1725f1f4fbfe..c3e6b9fca18a7 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring.py @@ -219,3 +219,10 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self): ''' + + +def foo(): + """ + Docstring with a backslash followed by a space\ + and then another line + """ diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring.py.expect similarity index 97% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring.py.expect index a8f12a5b51702..2259a0cf01a0a 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring.py.expect +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring.py.expect @@ -217,3 +217,10 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self): """ + + +def foo(): + """ + Docstring with a backslash followed by a space\ + and then another line + """ diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring_no_extra_empty_line_before_eof.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring_no_extra_empty_line_before_eof.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring_no_extra_empty_line_before_eof.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring_no_extra_empty_line_before_eof.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring_no_extra_empty_line_before_eof.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring_no_extra_empty_line_before_eof.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring_no_extra_empty_line_before_eof.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring_no_extra_empty_line_before_eof.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/docstring_no_string_normalization.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring_no_string_normalization.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/docstring_no_string_normalization.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring_no_string_normalization.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/docstring_no_string_normalization.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring_no_string_normalization.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/docstring_no_string_normalization.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring_no_string_normalization.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring_preview.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring_preview.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring_preview.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring_preview.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring_preview.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring_preview.py.expect similarity index 98% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring_preview.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring_preview.py.expect index dc453dcc76e96..859c295511617 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring_preview.py.expect +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring_preview.py.expect @@ -3,7 +3,8 @@ def docstring_almost_at_line_limit(): def docstring_almost_at_line_limit_with_prefix(): - f"""long docstring................................................................""" + f"""long docstring................................................................ + """ def mulitline_docstring_almost_at_line_limit(): diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/empty_lines.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/empty_lines.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/empty_lines.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/empty_lines.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/empty_lines.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/empty_lines.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/empty_lines.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/empty_lines.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/expression.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/expression.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/expression.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/expression.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/expression.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/expression.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/expression.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/expression.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/f_docstring.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/f_docstring.py new file mode 100644 index 0000000000000..88dab4840f3e4 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/f_docstring.py @@ -0,0 +1,8 @@ +def foo(e): + f""" {'.'.join(e)}""" + +def bar(e): + f"{'.'.join(e)}" + +def baz(e): + F""" {'.'.join(e)}""" diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/f_docstring.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/f_docstring.py.expect new file mode 100644 index 0000000000000..7081a229ed117 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/f_docstring.py.expect @@ -0,0 +1,10 @@ +def foo(e): + f""" {'.'.join(e)}""" + + +def bar(e): + f"{'.'.join(e)}" + + +def baz(e): + f""" {'.'.join(e)}""" diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff2.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff2.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff2.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff2.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff2.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff2.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff2.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff2.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff3.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff3.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff3.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff3.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff3.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff3.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff3.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff3.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff4.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff4.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff4.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff4.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff4.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff4.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff4.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff4.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff5.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff5.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff5.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff5.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff5.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff5.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff5.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff5.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtpass_imports.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtpass_imports.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtpass_imports.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtpass_imports.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtpass_imports.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtpass_imports.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtpass_imports.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtpass_imports.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip2.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip2.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip2.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip2.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip2.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip2.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip2.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip2.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip3.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip3.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip3.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip3.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip3.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip3.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip3.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip3.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip4.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip4.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip4.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip4.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip4.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip4.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip4.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip4.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip5.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip5.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip5.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip5.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip5.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip5.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip5.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip5.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip6.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip6.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip6.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip6.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip6.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip6.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip6.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip6.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip7.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip7.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip7.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip7.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip7.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip7.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip7.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip7.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip8.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip8.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip8.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip8.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip8.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip8.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip8.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip8.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fstring.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fstring.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fstring.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fstring.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fstring.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/fstring.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fstring.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/fstring.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.py new file mode 100644 index 0000000000000..16915fc220c90 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.py @@ -0,0 +1,143 @@ +# normal, short, function definition +def foo(a, b) -> tuple[int, float]: ... + + +# normal, short, function definition w/o return type +def foo(a, b): ... + + +# no splitting +def foo(a: A, b: B) -> list[p, q]: + pass + + +# magic trailing comma in param list +def foo(a, b,): ... + + +# magic trailing comma in nested params in param list +def foo(a, b: tuple[int, float,]): ... + + +# magic trailing comma in return type, no params +def a() -> tuple[ + a, + b, +]: ... + + +# magic trailing comma in return type, params +def foo(a: A, b: B) -> list[ + p, + q, +]: + pass + + +# magic trailing comma in param list and in return type +def foo( + a: a, + b: b, +) -> list[ + a, + a, +]: + pass + + +# long function definition, param list is longer +def aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa( + bbbbbbbbbbbbbbbbbb, +) -> cccccccccccccccccccccccccccccc: ... + + +# long function definition, return type is longer +# this should maybe split on rhs? +def aaaaaaaaaaaaaaaaa(bbbbbbbbbbbbbbbbbb) -> list[ + Ccccccccccccccccccccccccccccccccccccccccccccccccccc, Dddddd +]: ... + + +# long return type, no param list +def foo() -> list[ + Loooooooooooooooooooooooooooooooooooong, + Loooooooooooooooooooong, + Looooooooooooong, +]: ... + + +# long function name, no param list, no return value +def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeeeeery_looooooong(): + pass + + +# long function name, no param list +def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeeeeery_looooooong() -> ( + list[int, float] +): ... + + +# long function name, no return value +def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeeeeery_looooooong( + a, b +): ... + + +# unskippable type hint (??) +def foo(a) -> list[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]: # type: ignore + pass + + +def foo(a) -> list[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +]: # abpedeifnore + pass + +def foo(a, b: list[Bad],): ... # type: ignore + +# don't lose any comments (no magic) +def foo( # 1 + a, # 2 + b) -> list[ # 3 + a, # 4 + b]: # 5 + ... # 6 + + +# don't lose any comments (param list magic) +def foo( # 1 + a, # 2 + b,) -> list[ # 3 + a, # 4 + b]: # 5 + ... # 6 + + +# don't lose any comments (return type magic) +def foo( # 1 + a, # 2 + b) -> list[ # 3 + a, # 4 + b,]: # 5 + ... # 6 + + +# don't lose any comments (both magic) +def foo( # 1 + a, # 2 + b,) -> list[ # 3 + a, # 4 + b,]: # 5 + ... # 6 + +# real life example +def SimplePyFn( + context: hl.GeneratorContext, + buffer_input: Buffer[UInt8, 2], + func_input: Buffer[Int32, 2], + float_arg: Scalar[Float32], + offset: int = 0, +) -> tuple[ + Buffer[UInt8, 2], + Buffer[UInt8, 2], +]: ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.py.expect new file mode 100644 index 0000000000000..bb12b80672b06 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.py.expect @@ -0,0 +1,156 @@ +# normal, short, function definition +def foo(a, b) -> tuple[int, float]: ... + + +# normal, short, function definition w/o return type +def foo(a, b): ... + + +# no splitting +def foo(a: A, b: B) -> list[p, q]: + pass + + +# magic trailing comma in param list +def foo( + a, + b, +): ... + + +# magic trailing comma in nested params in param list +def foo( + a, + b: tuple[ + int, + float, + ], +): ... + + +# magic trailing comma in return type, no params +def a() -> tuple[ + a, + b, +]: ... + + +# magic trailing comma in return type, params +def foo(a: A, b: B) -> list[ + p, + q, +]: + pass + + +# magic trailing comma in param list and in return type +def foo( + a: a, + b: b, +) -> list[ + a, + a, +]: + pass + + +# long function definition, param list is longer +def aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa( + bbbbbbbbbbbbbbbbbb, +) -> cccccccccccccccccccccccccccccc: ... + + +# long function definition, return type is longer +# this should maybe split on rhs? +def aaaaaaaaaaaaaaaaa( + bbbbbbbbbbbbbbbbbb, +) -> list[Ccccccccccccccccccccccccccccccccccccccccccccccccccc, Dddddd]: ... + + +# long return type, no param list +def foo() -> list[ + Loooooooooooooooooooooooooooooooooooong, + Loooooooooooooooooooong, + Looooooooooooong, +]: ... + + +# long function name, no param list, no return value +def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeeeeery_looooooong(): + pass + + +# long function name, no param list +def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeeeeery_looooooong() -> ( + list[int, float] +): ... + + +# long function name, no return value +def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeeeeery_looooooong( + a, b +): ... + + +# unskippable type hint (??) +def foo(a) -> list[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]: # type: ignore + pass + + +def foo( + a, +) -> list[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +]: # abpedeifnore + pass + + +def foo( + a, + b: list[Bad], +): ... # type: ignore + + +# don't lose any comments (no magic) +def foo(a, b) -> list[a, b]: # 1 # 2 # 3 # 4 # 5 + ... # 6 + + +# don't lose any comments (param list magic) +def foo( # 1 + a, # 2 + b, +) -> list[a, b]: # 3 # 4 # 5 + ... # 6 + + +# don't lose any comments (return type magic) +def foo(a, b) -> list[ # 1 # 2 # 3 + a, # 4 + b, +]: # 5 + ... # 6 + + +# don't lose any comments (both magic) +def foo( # 1 + a, # 2 + b, +) -> list[ # 3 + a, # 4 + b, +]: # 5 + ... # 6 + + +# real life example +def SimplePyFn( + context: hl.GeneratorContext, + buffer_input: Buffer[UInt8, 2], + func_input: Buffer[Int32, 2], + float_arg: Scalar[Float32], + offset: int = 0, +) -> tuple[ + Buffer[UInt8, 2], + Buffer[UInt8, 2], +]: ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/function.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/function.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/function.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/function.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function2.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/function2.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function2.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/function2.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function2.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/function2.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function2.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/function2.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function_trailing_comma.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/function_trailing_comma.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function_trailing_comma.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/function_trailing_comma.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function_trailing_comma.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/function_trailing_comma.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function_trailing_comma.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/function_trailing_comma.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/ignore_pyi.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/ignore_pyi.pyi similarity index 71% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/ignore_pyi.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/ignore_pyi.pyi index 5e643ea38e4f7..64230590670a4 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/ignore_pyi.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/ignore_pyi.pyi @@ -15,6 +15,7 @@ def g(): # hi ... -def h(): - ... - # bye +# FIXME(#8905): Uncomment, leads to unstable formatting +# def h(): +# ... +# # bye diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/ignore_pyi.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/ignore_pyi.pyi.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/ignore_pyi.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/ignore_pyi.pyi.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/import_spacing.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/import_spacing.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/import_spacing.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/import_spacing.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/import_spacing.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/import_spacing.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/import_spacing.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/import_spacing.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_basic.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_basic.py new file mode 100644 index 0000000000000..40d0f7053b9e2 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_basic.py @@ -0,0 +1,40 @@ +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. +def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass +def foo2(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass +def foo3(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass +def foo4(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass + +# Adding some unformated code covering a wide range of syntaxes. + +if True: + # Incorrectly indented prefix comments. + pass + +import typing +from typing import ( + Any , + ) +class MyClass( object): # Trailing comment with extra leading space. + #NOTE: The following indentation is incorrect: + @decor( 1 * 3 ) + def my_func( arg): + pass + +try: # Trailing comment with extra leading space. + for i in range(10): # Trailing comment with extra leading space. + while condition: + if something: + then_something( ) + elif something_else: + then_something_else( ) +except ValueError as e: + unformatted( ) +finally: + unformatted( ) + +async def test_async_unformatted( ): # Trailing comment with extra leading space. + async for i in some_iter( unformatted ): # Trailing comment with extra leading space. + await asyncio.sleep( 1 ) + async with some_context( unformatted ): + print( "unformatted" ) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_basic.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_basic.py.expect new file mode 100644 index 0000000000000..7fdfdfd0dbbae --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_basic.py.expect @@ -0,0 +1,63 @@ +# flags: --line-ranges=5-6 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. +def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass +def foo2( + parameter_1, + parameter_2, + parameter_3, + parameter_4, + parameter_5, + parameter_6, + parameter_7, +): + pass + + +def foo3( + parameter_1, + parameter_2, + parameter_3, + parameter_4, + parameter_5, + parameter_6, + parameter_7, +): + pass + + +def foo4(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass + +# Adding some unformated code covering a wide range of syntaxes. + +if True: + # Incorrectly indented prefix comments. + pass + +import typing +from typing import ( + Any , + ) +class MyClass( object): # Trailing comment with extra leading space. + #NOTE: The following indentation is incorrect: + @decor( 1 * 3 ) + def my_func( arg): + pass + +try: # Trailing comment with extra leading space. + for i in range(10): # Trailing comment with extra leading space. + while condition: + if something: + then_something( ) + elif something_else: + then_something_else( ) +except ValueError as e: + unformatted( ) +finally: + unformatted( ) + +async def test_async_unformatted( ): # Trailing comment with extra leading space. + async for i in some_iter( unformatted ): # Trailing comment with extra leading space. + await asyncio.sleep( 1 ) + async with some_context( unformatted ): + print( "unformatted" ) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_diff_edge_case.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_diff_edge_case.py new file mode 100644 index 0000000000000..17613eb8dbe18 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_diff_edge_case.py @@ -0,0 +1,12 @@ +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# Reproducible example for https://github.com/psf/black/issues/4033. +# This can be fixed in the future if we use a better diffing algorithm, or make Black +# perform formatting in a single pass. + +print ( "format me" ) +print ( "format me" ) +print ( "format me" ) +print ( "format me" ) +print ( "format me" ) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_diff_edge_case.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_diff_edge_case.py.expect new file mode 100644 index 0000000000000..96106c6988b94 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_diff_edge_case.py.expect @@ -0,0 +1,13 @@ +# flags: --line-ranges=10-11 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# Reproducible example for https://github.com/psf/black/issues/4033. +# This can be fixed in the future if we use a better diffing algorithm, or make Black +# perform formatting in a single pass. + +print ( "format me" ) +print("format me") +print("format me") +print("format me") +print("format me") diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off.py new file mode 100644 index 0000000000000..bcb36284a844e --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off.py @@ -0,0 +1,22 @@ +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# fmt: off +import os +def myfunc( ): # Intentionally unformatted. + pass +# fmt: on + + +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: off +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: on + + +def myfunc( ): # This will be reformatted. + print( {"this will be reformatted"} ) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off.py.expect new file mode 100644 index 0000000000000..03cd50db754c8 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off.py.expect @@ -0,0 +1,23 @@ +# flags: --line-ranges=7-7 --line-ranges=17-23 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# fmt: off +import os +def myfunc( ): # Intentionally unformatted. + pass +# fmt: on + + +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: off +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: on + + +def myfunc(): # This will be reformatted. + print({"this will be reformatted"}) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py new file mode 100644 index 0000000000000..3c9e616d83a98 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py @@ -0,0 +1,11 @@ +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# Regression test for an edge case involving decorators and fmt: off/on. +class MyClass: + + # fmt: off + @decorator ( ) + # fmt: on + def method(): + print ( "str" ) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py.expect new file mode 100644 index 0000000000000..326b48df6b4f4 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py.expect @@ -0,0 +1,12 @@ +# flags: --line-ranges=12-12 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# Regression test for an edge case involving decorators and fmt: off/on. +class MyClass: + + # fmt: off + @decorator ( ) + # fmt: on + def method(): + print("str") diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_overlap.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_overlap.py new file mode 100644 index 0000000000000..4d3db25824c64 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_overlap.py @@ -0,0 +1,16 @@ +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + + +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: off +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: on + + +def myfunc( ): # This will be reformatted. + print( {"this will be reformatted"} ) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_overlap.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_overlap.py.expect new file mode 100644 index 0000000000000..fa7c683b3ace9 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_overlap.py.expect @@ -0,0 +1,17 @@ +# flags: --line-ranges=11-17 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + + +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: off +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: on + + +def myfunc(): # This will be reformatted. + print({"this will be reformatted"}) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_imports.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_imports.py new file mode 100644 index 0000000000000..0e516f28226c3 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_imports.py @@ -0,0 +1,8 @@ +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# This test ensures no empty lines are added around import lines. +# It caused an issue before https://github.com/psf/black/pull/3610 is merged. +import os +import re +import sys diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_imports.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_imports.py.expect new file mode 100644 index 0000000000000..0e516f28226c3 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_imports.py.expect @@ -0,0 +1,8 @@ +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# This test ensures no empty lines are added around import lines. +# It caused an issue before https://github.com/psf/black/pull/3610 is merged. +import os +import re +import sys diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_indentation.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_indentation.py new file mode 100644 index 0000000000000..ee2269d06102d --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_indentation.py @@ -0,0 +1,11 @@ +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. +if cond1: + print("first") + if cond2: + print("second") + else: + print("else") + +if another_cond: + print("will not be changed") diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_indentation.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_indentation.py.expect new file mode 100644 index 0000000000000..e6265c1ded0c5 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_indentation.py.expect @@ -0,0 +1,12 @@ +# flags: --line-ranges=5-5 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. +if cond1: + print("first") + if cond2: + print("second") + else: + print("else") + +if another_cond: + print("will not be changed") diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_two_passes.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_two_passes.py new file mode 100644 index 0000000000000..c8a57fdf77aef --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_two_passes.py @@ -0,0 +1,12 @@ +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# This is a specific case for Black's two-pass formatting behavior in `format_str`. +# The second pass must respect the line ranges before the first pass. + + +def restrict_to_this_line(arg1, + arg2, + arg3): + print ( "This should not be formatted." ) + print ( "Note that in the second pass, the original line range 9-11 will cover these print lines.") diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_two_passes.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_two_passes.py.expect new file mode 100644 index 0000000000000..593ef6d331807 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_two_passes.py.expect @@ -0,0 +1,11 @@ +# flags: --line-ranges=9-11 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# This is a specific case for Black's two-pass formatting behavior in `format_str`. +# The second pass must respect the line ranges before the first pass. + + +def restrict_to_this_line(arg1, arg2, arg3): + print ( "This should not be formatted." ) + print ( "Note that in the second pass, the original line range 9-11 will cover these print lines.") diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_unwrapping.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_unwrapping.py new file mode 100644 index 0000000000000..c5db777884258 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_unwrapping.py @@ -0,0 +1,13 @@ +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. +alist = [ + 1, 2 +] + +adict = { + "key" : "value" +} + +func_call ( + arg = value +) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_unwrapping.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_unwrapping.py.expect new file mode 100644 index 0000000000000..4d8de0a45d97e --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_unwrapping.py.expect @@ -0,0 +1,8 @@ +# flags: --line-ranges=5-5 --line-ranges=9-9 --line-ranges=13-13 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. +alist = [1, 2] + +adict = {"key": "value"} + +func_call(arg=value) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/linelength6.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/linelength6.options.json new file mode 100644 index 0000000000000..f6d0b5fa4c54c --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/linelength6.options.json @@ -0,0 +1 @@ +{"line_length": 6} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/linelength6.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/linelength6.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/linelength6.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/linelength6.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/linelength6.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/linelength6.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/linelength6.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/linelength6.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/long_strings_flag_disabled.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/long_strings_flag_disabled.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/long_strings_flag_disabled.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/long_strings_flag_disabled.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/long_strings_flag_disabled.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/long_strings_flag_disabled.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/long_strings_flag_disabled.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/long_strings_flag_disabled.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_1.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_1.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_1.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_1.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_1.py new file mode 100644 index 0000000000000..6868801be3e59 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_1.py @@ -0,0 +1,14 @@ +"""Single line module-level docstring should be followed by single newline.""" + + + + +a = 1 + + +"""I'm just a string so should be followed by 2 newlines.""" + + + + +b = 2 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_1.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_1.py.expect new file mode 100644 index 0000000000000..09fc6076ab5f8 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_1.py.expect @@ -0,0 +1,9 @@ +"""Single line module-level docstring should be followed by single newline.""" + +a = 1 + + +"""I'm just a string so should be followed by 2 newlines.""" + + +b = 2 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_2.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_2.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_2.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_2.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_2.py new file mode 100644 index 0000000000000..48be31c41c906 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_2.py @@ -0,0 +1,35 @@ +"""I am a very helpful module docstring. + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, +sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris +nisi ut aliquip ex ea commodo consequat. +Duis aute irure dolor in reprehenderit in voluptate +velit esse cillum dolore eu fugiat nulla pariatur. +Excepteur sint occaecat cupidatat non proident, +sunt in culpa qui officia deserunt mollit anim id est laborum. +""" + + + + +a = 1 + + +"""Look at me I'm a docstring... + +............................................................ +............................................................ +............................................................ +............................................................ +............................................................ +............................................................ +............................................................ +........................................................NOT! +""" + + + + +b = 2 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_2.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_2.py.expect new file mode 100644 index 0000000000000..6c07d2d16978e --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_2.py.expect @@ -0,0 +1,30 @@ +"""I am a very helpful module docstring. + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, +sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris +nisi ut aliquip ex ea commodo consequat. +Duis aute irure dolor in reprehenderit in voluptate +velit esse cillum dolore eu fugiat nulla pariatur. +Excepteur sint occaecat cupidatat non proident, +sunt in culpa qui officia deserunt mollit anim id est laborum. +""" + +a = 1 + + +"""Look at me I'm a docstring... + +............................................................ +............................................................ +............................................................ +............................................................ +............................................................ +............................................................ +............................................................ +........................................................NOT! +""" + + +b = 2 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_3.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_3.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_3.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_3.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_3.py new file mode 100644 index 0000000000000..f785054cefcb1 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_3.py @@ -0,0 +1,2 @@ +"""Single line module-level docstring should be followed by single newline.""" +a = 1 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_3.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_3.py.expect new file mode 100644 index 0000000000000..98e7364384c7a --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_3.py.expect @@ -0,0 +1,3 @@ +"""Single line module-level docstring should be followed by single newline.""" + +a = 1 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_4.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_4.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_4.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_4.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_4.py new file mode 100644 index 0000000000000..98e7364384c7a --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_4.py @@ -0,0 +1,3 @@ +"""Single line module-level docstring should be followed by single newline.""" + +a = 1 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_4.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_4.py.expect new file mode 100644 index 0000000000000..98e7364384c7a --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_4.py.expect @@ -0,0 +1,3 @@ +"""Single line module-level docstring should be followed by single newline.""" + +a = 1 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_class.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_class.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_class.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_class.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_class.py new file mode 100644 index 0000000000000..5a10eeb881098 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_class.py @@ -0,0 +1,3 @@ +"""Two blank lines between module docstring and a class.""" +class MyClass: + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_class.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_class.py.expect new file mode 100644 index 0000000000000..57611855321c6 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_class.py.expect @@ -0,0 +1,5 @@ +"""Two blank lines between module docstring and a class.""" + + +class MyClass: + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_function.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_function.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_function.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_function.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_function.py new file mode 100644 index 0000000000000..5d8a52a85b066 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_function.py @@ -0,0 +1,3 @@ +"""Two blank lines between module docstring and a function def.""" +def function(): + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_function.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_function.py.expect new file mode 100644 index 0000000000000..73ac8469ce827 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/module_docstring_followed_by_function.py.expect @@ -0,0 +1,5 @@ +"""Two blank lines between module docstring and a function def.""" + + +def function(): + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/multiline_consecutive_open_parentheses_ignore.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/multiline_consecutive_open_parentheses_ignore.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/multiline_consecutive_open_parentheses_ignore.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/multiline_consecutive_open_parentheses_ignore.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/multiline_consecutive_open_parentheses_ignore.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/multiline_consecutive_open_parentheses_ignore.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/multiline_consecutive_open_parentheses_ignore.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/multiline_consecutive_open_parentheses_ignore.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/nested_stub.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/nested_stub.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/nested_stub.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/nested_stub.pyi b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/nested_stub.pyi new file mode 100644 index 0000000000000..2cb19a8ba0dd6 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/nested_stub.pyi @@ -0,0 +1,18 @@ +import sys + +class Outer: + class InnerStub: ... + outer_attr_after_inner_stub: int + class Inner: + inner_attr: int + outer_attr: int + +if sys.version_info > (3, 7): + if sys.platform == "win32": + assignment = 1 + def function_definition(self): ... + def f1(self) -> str: ... + if sys.platform != "win32": + def function_definition(self): ... + assignment = 1 + def f2(self) -> str: ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/nested_stub.pyi.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/nested_stub.pyi.expect new file mode 100644 index 0000000000000..da431eb8493f1 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/nested_stub.pyi.expect @@ -0,0 +1,22 @@ +import sys + +class Outer: + class InnerStub: ... + outer_attr_after_inner_stub: int + + class Inner: + inner_attr: int + + outer_attr: int + +if sys.version_info > (3, 7): + if sys.platform == "win32": + assignment = 1 + def function_definition(self): ... + + def f1(self) -> str: ... + if sys.platform != "win32": + def function_definition(self): ... + assignment = 1 + + def f2(self) -> str: ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_36/numeric_literals.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/numeric_literals.py similarity index 91% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_36/numeric_literals.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/numeric_literals.py index 6da4ba68d62d9..0aa2aef4eb6ca 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_36/numeric_literals.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/numeric_literals.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3.6 - x = 123456789 x = 123456 x = .1 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_36/numeric_literals.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/numeric_literals.py.expect similarity index 91% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_36/numeric_literals.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/numeric_literals.py.expect index e263924b4e783..6514de6cb99d1 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_36/numeric_literals.py.expect +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/numeric_literals.py.expect @@ -1,5 +1,3 @@ -#!/usr/bin/env python3.6 - x = 123456789 x = 123456 x = 0.1 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_36/numeric_literals_skip_underscores.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/numeric_literals_skip_underscores.py similarity index 79% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_36/numeric_literals_skip_underscores.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/numeric_literals_skip_underscores.py index d77116a8327e0..9e8f89736c077 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_36/numeric_literals_skip_underscores.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/numeric_literals_skip_underscores.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3.6 - x = 123456789 x = 1_2_3_4_5_6_7 x = 1E+1 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_36/numeric_literals_skip_underscores.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/numeric_literals_skip_underscores.py.expect similarity index 79% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_36/numeric_literals_skip_underscores.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/numeric_literals_skip_underscores.py.expect index a81ada11e57b0..e57b5f0944d75 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_36/numeric_literals_skip_underscores.py.expect +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/numeric_literals_skip_underscores.py.expect @@ -1,5 +1,3 @@ -#!/usr/bin/env python3.6 - x = 123456789 x = 1_2_3_4_5_6_7 x = 1e1 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/one_element_subscript.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/one_element_subscript.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/one_element_subscript.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/one_element_subscript.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/one_element_subscript.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/one_element_subscript.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/one_element_subscript.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/one_element_subscript.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/parenthesized_context_managers.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/parenthesized_context_managers.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/parenthesized_context_managers.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/parenthesized_context_managers.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/parenthesized_context_managers.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/parenthesized_context_managers.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/parenthesized_context_managers.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/parenthesized_context_managers.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_complex.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_complex.py similarity index 90% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_complex.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_complex.py index 97ee194fd39e2..60c80b9ea1df9 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_complex.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_complex.py @@ -142,3 +142,13 @@ y = 1 case []: y = 2 +# issue 3790 +match (X.type, Y): + case _: + pass +# issue 3487 +match = re.match(r"(?PLD|MD|HD)(?PAL|SS)", "HDSS") + +match (match.group("grade"), match.group("material")): + case ("MD" | "HD", "SS" as code): + print("You will get here") diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_complex.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_complex.py.expect similarity index 90% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_complex.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_complex.py.expect index 97ee194fd39e2..60c80b9ea1df9 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_complex.py.expect +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_complex.py.expect @@ -142,3 +142,13 @@ match x: y = 1 case []: y = 2 +# issue 3790 +match (X.type, Y): + case _: + pass +# issue 3487 +match = re.match(r"(?PLD|MD|HD)(?PAL|SS)", "HDSS") + +match (match.group("grade"), match.group("material")): + case ("MD" | "HD", "SS" as code): + print("You will get here") diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_extras.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_extras.py similarity index 88% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_extras.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_extras.py index 0242d264e5b63..5afe69920eb66 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_extras.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_extras.py @@ -29,22 +29,6 @@ def func(match: case, case: match) -> case: ... -match maybe, multiple: - case perhaps, 5: - pass - case perhaps, 6,: - pass - - -match more := (than, one), indeed,: - case _, (5, 6): - pass - case [[5], (6)], [7],: - pass - case _: - pass - - match a, *b, c: case [*_]: assert "seq" == _ @@ -66,12 +50,12 @@ def func(match: case, case: match) -> case: ), ): pass - case [a as match]: pass - case case: pass + case something: + pass match match: @@ -97,10 +81,8 @@ def func(match: case, case: match) -> case: match something: case 1 as a: pass - case 2 as b, 3 as c: pass - case 4 as d, (5 as e), (6 | 7 as g), *h: pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_extras.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_extras.py.expect similarity index 88% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_extras.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_extras.py.expect index 0242d264e5b63..5afe69920eb66 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_extras.py.expect +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_extras.py.expect @@ -29,22 +29,6 @@ def func(match: case, case: match) -> case: ... -match maybe, multiple: - case perhaps, 5: - pass - case perhaps, 6,: - pass - - -match more := (than, one), indeed,: - case _, (5, 6): - pass - case [[5], (6)], [7],: - pass - case _: - pass - - match a, *b, c: case [*_]: assert "seq" == _ @@ -66,12 +50,12 @@ match match( ), ): pass - case [a as match]: pass - case case: pass + case something: + pass match match: @@ -97,10 +81,8 @@ match something: match something: case 1 as a: pass - case 2 as b, 3 as c: pass - case 4 as d, (5 as e), (6 | 7 as g), *h: pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_generic.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_generic.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_generic.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_generic.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_generic.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_generic.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_generic.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_generic.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_simple.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_simple.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_simple.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_simple.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_simple.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_simple.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_simple.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_simple.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_style.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_style.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_style.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_style.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_style.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_style.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_style.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_style.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.py new file mode 100644 index 0000000000000..bd3e48417b6b5 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.py @@ -0,0 +1,83 @@ +# This has always worked +z= Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong + +# "AnnAssign"s now also work +z: Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong +z: (Short + | Short2 + | Short3 + | Short4) +z: (int) +z: ((int)) + + +z: Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong = 7 +z: (Short + | Short2 + | Short3 + | Short4) = 8 +z: (int) = 2.3 +z: ((int)) = foo() + +# In case I go for not enforcing parantheses, this might get improved at the same time +x = ( + z + == 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999, + y + == 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999, +) + +x = ( + z == (9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999), + y == (9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999), +) + +# handle formatting of "tname"s in parameter list + +# remove unnecessary paren +def foo(i: (int)) -> None: ... + + +# this is a syntax error in the type annotation according to mypy, but it's not invalid *python* code, so make sure we don't mess with it and make it so. +def foo(i: (int,)) -> None: ... + +def foo( + i: int, + x: Loooooooooooooooooooooooong + | Looooooooooooooooong + | Looooooooooooooooooooong + | Looooooong, + *, + s: str, +) -> None: + pass + + +@app.get("/path/") +async def foo( + q: str + | None = Query(None, title="Some long title", description="Some long description") +): + pass + + +def f( + max_jobs: int + | None = Option( + None, help="Maximum number of jobs to launch. And some additional text." + ), + another_option: bool = False + ): + ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.py.expect new file mode 100644 index 0000000000000..ab0a4d96772ca --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.py.expect @@ -0,0 +1,101 @@ +# This has always worked +z = ( + Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong +) + +# "AnnAssign"s now also work +z: ( + Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong +) +z: Short | Short2 | Short3 | Short4 +z: int +z: int + + +z: ( + Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong +) = 7 +z: Short | Short2 | Short3 | Short4 = 8 +z: int = 2.3 +z: int = foo() + +# In case I go for not enforcing parantheses, this might get improved at the same time +x = ( + z + == 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999, + y + == 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999, +) + +x = ( + z + == ( + 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + ), + y + == ( + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + ), +) + +# handle formatting of "tname"s in parameter list + + +# remove unnecessary paren +def foo(i: int) -> None: ... + + +# this is a syntax error in the type annotation according to mypy, but it's not invalid *python* code, so make sure we don't mess with it and make it so. +def foo(i: (int,)) -> None: ... + + +def foo( + i: int, + x: ( + Loooooooooooooooooooooooong + | Looooooooooooooooong + | Looooooooooooooooooooong + | Looooooong + ), + *, + s: str, +) -> None: + pass + + +@app.get("/path/") +async def foo( + q: str | None = Query( + None, title="Some long title", description="Some long description" + ) +): + pass + + +def f( + max_jobs: int | None = Option( + None, help="Maximum number of jobs to launch. And some additional text." + ), + another_option: bool = False, +): ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_38/pep_570.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_570.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_38/pep_570.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_570.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_38/pep_570.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_570.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_38/pep_570.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_570.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_38/pep_572.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_38/pep_572.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_38/pep_572.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_38/pep_572.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pep_572_py310.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_py310.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pep_572_py310.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_py310.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pep_572_py310.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_py310.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pep_572_py310.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_py310.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_39/pep_572_py39.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_py39.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_39/pep_572_py39.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_py39.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_39/pep_572_py39.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_py39.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_39/pep_572_py39.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_py39.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_38/pep_572_remove_parens.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_remove_parens.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_38/pep_572_remove_parens.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_remove_parens.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_38/pep_572_remove_parens.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_remove_parens.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_38/pep_572_remove_parens.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_remove_parens.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/pep_604.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_604.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/pep_604.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_604.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/pep_604.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_604.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/pep_604.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_604.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_311/pep_646.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_646.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_311/pep_646.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_646.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_311/pep_646.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_646.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_311/pep_646.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_646.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_311/pep_654.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_311/pep_654.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_311/pep_654.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_311/pep_654.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_311/pep_654_style.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654_style.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_311/pep_654_style.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654_style.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_311/pep_654_style.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654_style.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_311/pep_654_style.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654_style.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_newline.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_newline.options.json new file mode 100644 index 0000000000000..80ad04dcfc445 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_newline.options.json @@ -0,0 +1 @@ +{"line_length": 0} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/power_op_newline.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_newline.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/power_op_newline.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_newline.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/power_op_newline.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_newline.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/power_op_newline.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_newline.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/power_op_spacing.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_spacing.py similarity index 93% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/power_op_spacing.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_spacing.py index 1ae3fc2b4f979..14b29b3febf50 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/power_op_spacing.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_spacing.py @@ -29,6 +29,13 @@ def function_dont_replace_spaces(): p = {(k, k**2): v**2 for k, v in pairs} q = [10**i for i in range(6)] r = x**y +s = 1 ** 1 +t = ( + 1 + ** 1 + **1 + ** 1 +) a = 5.0**~4.0 b = 5.0 ** f() @@ -47,6 +54,13 @@ def function_dont_replace_spaces(): o = settings(max_examples=10**6.0) p = {(k, k**2): v**2.0 for k, v in pairs} q = [10.5**i for i in range(6)] +s = 1.0 ** 1.0 +t = ( + 1.0 + ** 1.0 + **1.0 + ** 1.0 +) # WE SHOULD DEFINITELY NOT EAT THESE COMMENTS (https://github.com/psf/black/issues/2873) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/power_op_spacing.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_spacing.py.expect similarity index 96% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/power_op_spacing.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_spacing.py.expect index ffc2be7e78f4d..ca00fba8b3c80 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/power_op_spacing.py.expect +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_spacing.py.expect @@ -29,6 +29,8 @@ o = settings(max_examples=10**6) p = {(k, k**2): v**2 for k, v in pairs} q = [10**i for i in range(6)] r = x**y +s = 1**1 +t = 1**1**1**1 a = 5.0**~4.0 b = 5.0 ** f() @@ -47,6 +49,8 @@ n = count <= 10**5.0 o = settings(max_examples=10**6.0) p = {(k, k**2): v**2.0 for k, v in pairs} q = [10.5**i for i in range(6)] +s = 1.0**1.0 +t = 1.0**1.0**1.0**1.0 # WE SHOULD DEFINITELY NOT EAT THESE COMMENTS (https://github.com/psf/black/issues/2873) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/prefer_rhs_split_reformatted.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/prefer_rhs_split_reformatted.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/prefer_rhs_split_reformatted.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/prefer_rhs_split_reformatted.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/prefer_rhs_split_reformatted.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/prefer_rhs_split_reformatted.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/prefer_rhs_split_reformatted.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/prefer_rhs_split_reformatted.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_allow_empty_first_line_in_special_cases.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_allow_empty_first_line_in_special_cases.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_allow_empty_first_line_in_special_cases.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_allow_empty_first_line_in_special_cases.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_allow_empty_first_line_in_special_cases.py new file mode 100644 index 0000000000000..7cf2fc1b8c18d --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_allow_empty_first_line_in_special_cases.py @@ -0,0 +1,51 @@ +def foo(): + """ + Docstring + """ + + # Here we go + if x: + + # This is also now fine + a = 123 + + else: + # But not necessary + a = 123 + + if y: + + while True: + + """ + Long comment here + """ + a = 123 + + if z: + + for _ in range(100): + a = 123 + else: + + try: + + # this should be ok + a = 123 + except: + + """also this""" + a = 123 + + +def bar(): + + if x: + a = 123 + + +def baz(): + + # OK + if x: + a = 123 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_allow_empty_first_line_in_special_cases.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_allow_empty_first_line_in_special_cases.py.expect new file mode 100644 index 0000000000000..570a63b1d3f3c --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_allow_empty_first_line_in_special_cases.py.expect @@ -0,0 +1,51 @@ +def foo(): + """ + Docstring + """ + + # Here we go + if x: + + # This is also now fine + a = 123 + + else: + # But not necessary + a = 123 + + if y: + + while True: + + """ + Long comment here + """ + a = 123 + + if z: + + for _ in range(100): + a = 123 + else: + + try: + + # this should be ok + a = 123 + except: + + """also this""" + a = 123 + + +def bar(): + + if x: + a = 123 + + +def baz(): + + # OK + if x: + a = 123 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_async_stmts.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_async_stmts.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_async_stmts.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_async_stmts.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_async_stmts.py new file mode 100644 index 0000000000000..88767abb88cc6 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_async_stmts.py @@ -0,0 +1,11 @@ +async def func() -> (int): + return 0 + + +@decorated +async def func() -> (int): + return 0 + + +async for (item) in async_iter: + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_async_stmts.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_async_stmts.py.expect new file mode 100644 index 0000000000000..13423345b6386 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_async_stmts.py.expect @@ -0,0 +1,11 @@ +async def func() -> int: + return 0 + + +@decorated +async def func() -> int: + return 0 + + +async for item in async_iter: + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_cantfit.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_cantfit.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_cantfit.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_cantfit.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_cantfit.py new file mode 100644 index 0000000000000..32ef2770cf719 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_cantfit.py @@ -0,0 +1,39 @@ +# long variable name +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = 0 +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = 1 # with a comment +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = [ + 1, 2, 3 +] +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function() +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + arg1, arg2, arg3 +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 +) +# long function name +normal_name = but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying() +normal_name = but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying( + arg1, arg2, arg3 +) +normal_name = but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 +) +# long arguments +normal_name = normal_function_name( + "but with super long string arguments that on their own exceed the line limit so there's no way it can ever fit", + "eggs with spam and eggs and spam with eggs with spam and eggs and spam with eggs with spam and eggs and spam with eggs", + this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it=0, +) +string_variable_name = ( + "a string that is waaaaaaaayyyyyyyy too long, even in parens, there's nothing you can do" # noqa +) +for key in """ + hostname + port + username +""".split(): + if key in self.connect_kwargs: + raise ValueError(err.format(key)) +concatenated_strings = "some strings that are " "concatenated implicitly, so if you put them on separate " "lines it will fit" +del concatenated_strings, string_variable_name, normal_function_name, normal_name, need_more_to_make_the_line_long_enough diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_cantfit.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_cantfit.py.expect new file mode 100644 index 0000000000000..27327be5f860f --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_cantfit.py.expect @@ -0,0 +1,63 @@ +# long variable name +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = ( + 0 +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = ( + 1 # with a comment +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = [ + 1, + 2, + 3, +] +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = ( + function() +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + arg1, arg2, arg3 +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 +) +# long function name +normal_name = ( + but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying() +) +normal_name = ( + but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying( + arg1, arg2, arg3 + ) +) +normal_name = ( + but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 + ) +) +# long arguments +normal_name = normal_function_name( + "but with super long string arguments that on their own exceed the line limit so" + " there's no way it can ever fit", + "eggs with spam and eggs and spam with eggs with spam and eggs and spam with eggs" + " with spam and eggs and spam with eggs", + this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it=0, +) +string_variable_name = "a string that is waaaaaaaayyyyyyyy too long, even in parens, there's nothing you can do" # noqa +for key in """ + hostname + port + username +""".split(): + if key in self.connect_kwargs: + raise ValueError(err.format(key)) +concatenated_strings = ( + "some strings that are " + "concatenated implicitly, so if you put them on separate " + "lines it will fit" +) +del ( + concatenated_strings, + string_variable_name, + normal_function_name, + normal_name, + need_more_to_make_the_line_long_enough, +) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_comments7.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_comments7.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_comments7.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_comments7.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_comments7.py new file mode 100644 index 0000000000000..14fe9b2f8bad8 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_comments7.py @@ -0,0 +1,144 @@ +from .config import ( + Any, + Bool, + ConfigType, + ConfigTypeAttributes, + Int, + Path, + # String, + # resolve_to_config_type, + # DEFAULT_TYPE_ATTRIBUTES, +) + + +from .config import ( + Any, + Bool, + ConfigType, + ConfigTypeAttributes, + Int, + no_comma_here_yet + # and some comments, + # resolve_to_config_type, + # DEFAULT_TYPE_ATTRIBUTES, +) +from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( + MyLovelyCompanyTeamProjectComponent # NOT DRY +) +from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( + MyLovelyCompanyTeamProjectComponent as component # DRY +) + + +result = 1 # look ma, no comment migration xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +result = ( + 1 # look ma, no comment migration xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +) + +result = ( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # aaa +) + +result = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # aaa + + +def func(): + c = call( + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0789, + a[-1], # type: ignore + ) + c = call( + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0789, + a[-1] # type: ignore + ) + c = call( + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0456, + 0.0789, + a[-1] # type: ignore + ) + + # The type: ignore exception only applies to line length, not + # other types of formatting. + c = call( + "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", # type: ignore + "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" + ) + + +class C: + @pytest.mark.parametrize( + ("post_data", "message"), + [ + # metadata_version errors. + ( + {}, + "None is an invalid value for Metadata-Version. Error: This field is" + " required. see" + " https://packaging.python.org/specifications/core-metadata" + ), + ( + {"metadata_version": "-1"}, + "'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata" + " Version see" + " https://packaging.python.org/specifications/core-metadata" + ), + # name errors. + ( + {"metadata_version": "1.2"}, + "'' is an invalid value for Name. Error: This field is required. see" + " https://packaging.python.org/specifications/core-metadata" + ), + ( + {"metadata_version": "1.2", "name": "foo-"}, + "'foo-' is an invalid value for Name. Error: Must start and end with a" + " letter or numeral and contain only ascii numeric and '.', '_' and" + " '-'. see https://packaging.python.org/specifications/core-metadata" + ), + # version errors. + ( + {"metadata_version": "1.2", "name": "example"}, + "'' is an invalid value for Version. Error: This field is required. see" + " https://packaging.python.org/specifications/core-metadata" + ), + ( + {"metadata_version": "1.2", "name": "example", "version": "dog"}, + "'dog' is an invalid value for Version. Error: Must start and end with" + " a letter or numeral and contain only ascii numeric and '.', '_' and" + " '-'. see https://packaging.python.org/specifications/core-metadata" + ) + ] + ) + def test_fails_invalid_post_data( + self, pyramid_config, db_request, post_data, message + ): + ... + +square = Square(4) # type: Optional[Square] + +# Regression test for https://github.com/psf/black/issues/3756. +[ + ( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ), +] +[ + ( # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ), +] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_comments7.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_comments7.py.expect new file mode 100644 index 0000000000000..9e583ab571966 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_comments7.py.expect @@ -0,0 +1,161 @@ +from .config import ( + Any, + Bool, + ConfigType, + ConfigTypeAttributes, + Int, + Path, + # String, + # resolve_to_config_type, + # DEFAULT_TYPE_ATTRIBUTES, +) + + +from .config import ( + Any, + Bool, + ConfigType, + ConfigTypeAttributes, + Int, + no_comma_here_yet, + # and some comments, + # resolve_to_config_type, + # DEFAULT_TYPE_ATTRIBUTES, +) +from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( + MyLovelyCompanyTeamProjectComponent, # NOT DRY +) +from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( + MyLovelyCompanyTeamProjectComponent as component, # DRY +) + + +result = 1 # look ma, no comment migration xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +result = 1 # look ma, no comment migration xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +result = ( # aaa + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +) + +result = ( # aaa + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +) + + +def func(): + c = call( + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0789, + a[-1], # type: ignore + ) + c = call(0.0123, 0.0456, 0.0789, 0.0123, 0.0789, a[-1]) # type: ignore + c = call( + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0456, + 0.0789, + a[-1], # type: ignore + ) + + # The type: ignore exception only applies to line length, not + # other types of formatting. + c = call( + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", # type: ignore + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + ) + + +class C: + @pytest.mark.parametrize( + ("post_data", "message"), + [ + # metadata_version errors. + ( + {}, + ( + "None is an invalid value for Metadata-Version. Error: This field" + " is required. see" + " https://packaging.python.org/specifications/core-metadata" + ), + ), + ( + {"metadata_version": "-1"}, + ( + "'-1' is an invalid value for Metadata-Version. Error: Unknown" + " Metadata Version see" + " https://packaging.python.org/specifications/core-metadata" + ), + ), + # name errors. + ( + {"metadata_version": "1.2"}, + ( + "'' is an invalid value for Name. Error: This field is required." + " see https://packaging.python.org/specifications/core-metadata" + ), + ), + ( + {"metadata_version": "1.2", "name": "foo-"}, + ( + "'foo-' is an invalid value for Name. Error: Must start and end" + " with a letter or numeral and contain only ascii numeric and '.'," + " '_' and '-'. see" + " https://packaging.python.org/specifications/core-metadata" + ), + ), + # version errors. + ( + {"metadata_version": "1.2", "name": "example"}, + ( + "'' is an invalid value for Version. Error: This field is required." + " see https://packaging.python.org/specifications/core-metadata" + ), + ), + ( + {"metadata_version": "1.2", "name": "example", "version": "dog"}, + ( + "'dog' is an invalid value for Version. Error: Must start and end" + " with a letter or numeral and contain only ascii numeric and '.'," + " '_' and '-'. see" + " https://packaging.python.org/specifications/core-metadata" + ), + ), + ], + ) + def test_fails_invalid_post_data( + self, pyramid_config, db_request, post_data, message + ): ... + + +square = Square(4) # type: Optional[Square] + +# Regression test for https://github.com/psf/black/issues/3756. +[ + ( # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + ), +] +[ + ( # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ), +] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_38.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_38.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_38.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_38.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_38.py new file mode 100644 index 0000000000000..811be47176279 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_38.py @@ -0,0 +1,31 @@ +with \ + make_context_manager1() as cm1, \ + make_context_manager2() as cm2, \ + make_context_manager3() as cm3, \ + make_context_manager4() as cm4 \ +: + pass + + +with \ + make_context_manager1() as cm1, \ + make_context_manager2(), \ + make_context_manager3() as cm3, \ + make_context_manager4() \ +: + pass + + +with \ + new_new_new1() as cm1, \ + new_new_new2() \ +: + pass + + +with mock.patch.object( + self.my_runner, "first_method", autospec=True +) as mock_run_adb, mock.patch.object( + self.my_runner, "second_method", autospec=True, return_value="foo" +): + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_38.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_38.py.expect new file mode 100644 index 0000000000000..5c0cdde0d29a5 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_38.py.expect @@ -0,0 +1,18 @@ +with make_context_manager1() as cm1, make_context_manager2() as cm2, make_context_manager3() as cm3, make_context_manager4() as cm4: + pass + + +with make_context_manager1() as cm1, make_context_manager2(), make_context_manager3() as cm3, make_context_manager4(): + pass + + +with new_new_new1() as cm1, new_new_new2(): + pass + + +with mock.patch.object( + self.my_runner, "first_method", autospec=True +) as mock_run_adb, mock.patch.object( + self.my_runner, "second_method", autospec=True, return_value="foo" +): + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_39.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_39.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_39.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_39.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_39.py new file mode 100644 index 0000000000000..f0ae0053630a2 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_39.py @@ -0,0 +1,84 @@ +with \ + make_context_manager1() as cm1, \ + make_context_manager2() as cm2, \ + make_context_manager3() as cm3, \ + make_context_manager4() as cm4 \ +: + pass + + +# Leading comment +with \ + make_context_manager1() as cm1, \ + make_context_manager2(), \ + make_context_manager3() as cm3, \ + make_context_manager4() \ +: + pass + + +with \ + new_new_new1() as cm1, \ + new_new_new2() \ +: + pass + + +with ( + new_new_new1() as cm1, + new_new_new2() +): + pass + + +# Leading comment. +with ( + # First comment. + new_new_new1() as cm1, + # Second comment. + new_new_new2() + # Last comment. +): + pass + + +with \ + this_is_a_very_long_call(looong_arg1=looong_value1, looong_arg2=looong_value2) as cm1, \ + this_is_a_very_long_call(looong_arg1=looong_value1, looong_arg2=looong_value2, looong_arg3=looong_value3, looong_arg4=looong_value4) as cm2 \ +: + pass + + +with mock.patch.object( + self.my_runner, "first_method", autospec=True +) as mock_run_adb, mock.patch.object( + self.my_runner, "second_method", autospec=True, return_value="foo" +): + pass + + +with xxxxxxxx.some_kind_of_method( + some_argument=[ + "first", + "second", + "third", + ] +).another_method() as cmd: + pass + + +async def func(): + async with \ + make_context_manager1() as cm1, \ + make_context_manager2() as cm2, \ + make_context_manager3() as cm3, \ + make_context_manager4() as cm4 \ + : + pass + + async with some_function( + argument1, argument2, argument3="some_value" + ) as some_cm, some_other_function( + argument1, argument2, argument3="some_value" + ): + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_39.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_39.py.expect new file mode 100644 index 0000000000000..1b8e86593390b --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_39.py.expect @@ -0,0 +1,85 @@ +with ( + make_context_manager1() as cm1, + make_context_manager2() as cm2, + make_context_manager3() as cm3, + make_context_manager4() as cm4, +): + pass + + +# Leading comment +with ( + make_context_manager1() as cm1, + make_context_manager2(), + make_context_manager3() as cm3, + make_context_manager4(), +): + pass + + +with new_new_new1() as cm1, new_new_new2(): + pass + + +with new_new_new1() as cm1, new_new_new2(): + pass + + +# Leading comment. +with ( + # First comment. + new_new_new1() as cm1, + # Second comment. + new_new_new2(), + # Last comment. +): + pass + + +with ( + this_is_a_very_long_call( + looong_arg1=looong_value1, looong_arg2=looong_value2 + ) as cm1, + this_is_a_very_long_call( + looong_arg1=looong_value1, + looong_arg2=looong_value2, + looong_arg3=looong_value3, + looong_arg4=looong_value4, + ) as cm2, +): + pass + + +with ( + mock.patch.object(self.my_runner, "first_method", autospec=True) as mock_run_adb, + mock.patch.object( + self.my_runner, "second_method", autospec=True, return_value="foo" + ), +): + pass + + +with xxxxxxxx.some_kind_of_method( + some_argument=[ + "first", + "second", + "third", + ] +).another_method() as cmd: + pass + + +async def func(): + async with ( + make_context_manager1() as cm1, + make_context_manager2() as cm2, + make_context_manager3() as cm3, + make_context_manager4() as cm4, + ): + pass + + async with ( + some_function(argument1, argument2, argument3="some_value") as some_cm, + some_other_function(argument1, argument2, argument3="some_value"), + ): + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_310.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_310.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_310.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_310.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_310.py new file mode 100644 index 0000000000000..493ad2110867c --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_310.py @@ -0,0 +1,15 @@ +# This file uses pattern matching introduced in Python 3.10. + + +match http_code: + case 404: + print("Not found") + + +with \ + make_context_manager1() as cm1, \ + make_context_manager2() as cm2, \ + make_context_manager3() as cm3, \ + make_context_manager4() as cm4 \ +: + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_310.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_310.py.expect new file mode 100644 index 0000000000000..4c35978000410 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_310.py.expect @@ -0,0 +1,15 @@ +# This file uses pattern matching introduced in Python 3.10. + + +match http_code: + case 404: + print("Not found") + + +with ( + make_context_manager1() as cm1, + make_context_manager2() as cm2, + make_context_manager3() as cm3, + make_context_manager4() as cm4, +): + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_311.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_311.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_311.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_311.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_311.py new file mode 100644 index 0000000000000..fb3fb65a31129 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_311.py @@ -0,0 +1,16 @@ +# This file uses except* clause in Python 3.11. + + +try: + some_call() +except* Error as e: + pass + + +with \ + make_context_manager1() as cm1, \ + make_context_manager2() as cm2, \ + make_context_manager3() as cm3, \ + make_context_manager4() as cm4 \ +: + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_311.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_311.py.expect new file mode 100644 index 0000000000000..b5ca9c0b1473e --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_311.py.expect @@ -0,0 +1,16 @@ +# This file uses except* clause in Python 3.11. + + +try: + some_call() +except* Error as e: + pass + + +with ( + make_context_manager1() as cm1, + make_context_manager2() as cm2, + make_context_manager3() as cm3, + make_context_manager4() as cm4, +): + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_38.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_38.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_38.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_38.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_38.py new file mode 100644 index 0000000000000..f48fbe78e3709 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_38.py @@ -0,0 +1,24 @@ +# This file doesn't use any Python 3.9+ only grammars. + + +# Make sure parens around a single context manager don't get autodetected as +# Python 3.9+. +with (a): + pass + + +with \ + make_context_manager1() as cm1, \ + make_context_manager2() as cm2, \ + make_context_manager3() as cm3, \ + make_context_manager4() as cm4 \ +: + pass + + +with mock.patch.object( + self.my_runner, "first_method", autospec=True +) as mock_run_adb, mock.patch.object( + self.my_runner, "second_method", autospec=True, return_value="foo" +): + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_38.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_38.py.expect new file mode 100644 index 0000000000000..d43eb9f0917ca --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_38.py.expect @@ -0,0 +1,19 @@ +# This file doesn't use any Python 3.9+ only grammars. + + +# Make sure parens around a single context manager don't get autodetected as +# Python 3.9+. +with a: + pass + + +with make_context_manager1() as cm1, make_context_manager2() as cm2, make_context_manager3() as cm3, make_context_manager4() as cm4: + pass + + +with mock.patch.object( + self.my_runner, "first_method", autospec=True +) as mock_run_adb, mock.patch.object( + self.my_runner, "second_method", autospec=True, return_value="foo" +): + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_39.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_39.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_39.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_39.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_39.py new file mode 100644 index 0000000000000..c69d3a72894b7 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_39.py @@ -0,0 +1,17 @@ +# This file uses parenthesized context managers introduced in Python 3.9. + + +with \ + make_context_manager1() as cm1, \ + make_context_manager2() as cm2, \ + make_context_manager3() as cm3, \ + make_context_manager4() as cm4 \ +: + pass + + +with ( + new_new_new1() as cm1, + new_new_new2() +): + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_39.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_39.py.expect new file mode 100644 index 0000000000000..ff6ce999175b2 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_39.py.expect @@ -0,0 +1,14 @@ +# This file uses parenthesized context managers introduced in Python 3.9. + + +with ( + make_context_manager1() as cm1, + make_context_manager2() as cm2, + make_context_manager3() as cm3, + make_context_manager4() as cm4, +): + pass + + +with new_new_new1() as cm1, new_new_new2(): + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_docstring_no_string_normalization.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_docstring_no_string_normalization.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_docstring_no_string_normalization.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/docstring_preview_no_string_normalization.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_docstring_no_string_normalization.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/docstring_preview_no_string_normalization.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_docstring_no_string_normalization.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/docstring_preview_no_string_normalization.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_docstring_no_string_normalization.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/docstring_preview_no_string_normalization.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_docstring_no_string_normalization.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_dummy_implementations.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_dummy_implementations.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_dummy_implementations.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_dummy_implementations.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_dummy_implementations.py new file mode 100644 index 0000000000000..99729fed0a28d --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_dummy_implementations.py @@ -0,0 +1,48 @@ +from typing import NoReturn, Protocol, Union, overload + + +def dummy(a): ... +def other(b): ... + + +@overload +def a(arg: int) -> int: ... +@overload +def a(arg: str) -> str: ... +@overload +def a(arg: object) -> NoReturn: ... +def a(arg: Union[int, str, object]) -> Union[int, str]: + if not isinstance(arg, (int, str)): + raise TypeError + return arg + +class Proto(Protocol): + def foo(self, a: int) -> int: + ... + + def bar(self, b: str) -> str: ... + def baz(self, c: bytes) -> str: + ... + + +def dummy_two(): + ... +@dummy +def dummy_three(): + ... + +def dummy_four(): + ... + +@overload +def b(arg: int) -> int: ... + +@overload +def b(arg: str) -> str: ... +@overload +def b(arg: object) -> NoReturn: ... + +def b(arg: Union[int, str, object]) -> Union[int, str]: + if not isinstance(arg, (int, str)): + raise TypeError + return arg diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_dummy_implementations.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_dummy_implementations.py.expect new file mode 100644 index 0000000000000..24068c5d183ee --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_dummy_implementations.py.expect @@ -0,0 +1,48 @@ +from typing import NoReturn, Protocol, Union, overload + + +def dummy(a): ... +def other(b): ... + + +@overload +def a(arg: int) -> int: ... +@overload +def a(arg: str) -> str: ... +@overload +def a(arg: object) -> NoReturn: ... +def a(arg: Union[int, str, object]) -> Union[int, str]: + if not isinstance(arg, (int, str)): + raise TypeError + return arg + + +class Proto(Protocol): + def foo(self, a: int) -> int: ... + + def bar(self, b: str) -> str: ... + def baz(self, c: bytes) -> str: ... + + +def dummy_two(): ... +@dummy +def dummy_three(): ... + + +def dummy_four(): ... + + +@overload +def b(arg: int) -> int: ... + + +@overload +def b(arg: str) -> str: ... +@overload +def b(arg: object) -> NoReturn: ... + + +def b(arg: Union[int, str, object]) -> Union[int, str]: + if not isinstance(arg, (int, str)): + raise TypeError + return arg diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_form_feeds.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_form_feeds.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_form_feeds.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_form_feeds.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_form_feeds.py new file mode 100644 index 0000000000000..42ba8fe243b29 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_form_feeds.py @@ -0,0 +1,116 @@ +# Warning! This file contains form feeds (ASCII 0x0C, often represented by \f or ^L). +# These may be invisible in your editor: ensure you can see them before making changes here. + +# There's one at the start that'll get stripped + +# Comment and statement processing is different enough that we'll test variations of both +# contexts here + +# + + +# + + +# + + + +# + + + +# + + + +# + + +# + + + +# + +# + +# + + \ +# +pass + +pass + + +pass + + +pass + + + +pass + + + +pass + + + +pass + + +pass + + + +pass + +pass + +pass + + +# form feed after a dedent +def foo(): + pass + +pass + + +# form feeds are prohibited inside blocks, or on a line with nonwhitespace + def bar( a = 1 ,b : bool = False ) : + + + pass + + +class Baz: + + def __init__(self): + pass + + + def something(self): + pass + + + +# +pass +pass # +a = 1 + # + pass + a = 1 + +a = [ + +] + +# as internal whitespace of a comment is allowed but why +"form feed literal in a string is okay " + +# form feeds at the very end get removed. diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_form_feeds.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_form_feeds.py.expect new file mode 100644 index 0000000000000..4895f2af697cc --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_form_feeds.py.expect @@ -0,0 +1,101 @@ +# Warning! This file contains form feeds (ASCII 0x0C, often represented by \f or ^L). +# These may be invisible in your editor: ensure you can see them before making changes here. + +# There's one at the start that'll get stripped + +# Comment and statement processing is different enough that we'll test variations of both +# contexts here + +# + + +# + + +# + + +# + + +# + + +# + + +# + + +# + +# + +# + +# +pass + +pass + + +pass + + +pass + + +pass + + +pass + + +pass + + +pass + + +pass + +pass + +pass + + +# form feed after a dedent +def foo(): + pass + + +pass + + +# form feeds are prohibited inside blocks, or on a line with nonwhitespace +def bar(a=1, b: bool = False): + pass + + +class Baz: + def __init__(self): + pass + + def something(self): + pass + + +# +pass +pass # +a = 1 +# +pass +a = 1 + +a = [] + +# as internal whitespace of a comment is allowed but why +"form feed literal in a string is okay " + +# form feeds at the very end get removed. diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_format_unicode_escape_seq.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_format_unicode_escape_seq.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_format_unicode_escape_seq.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_format_unicode_escape_seq.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_format_unicode_escape_seq.py new file mode 100644 index 0000000000000..70699c5663413 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_format_unicode_escape_seq.py @@ -0,0 +1,15 @@ +x = "\x1F" +x = "\\x1B" +x = "\\\x1B" +x = "\U0001F60E" +x = "\u0001F60E" +x = r"\u0001F60E" +x = "don't format me" +x = "\xA3" +x = "\u2717" +x = "\uFaCe" +x = "\N{ox}\N{OX}" +x = "\N{lAtIn smaLL letteR x}" +x = "\N{CYRILLIC small LETTER BYELORUSSIAN-UKRAINIAN I}" +x = b"\x1Fdon't byte" +x = rb"\x1Fdon't format" diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_format_unicode_escape_seq.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_format_unicode_escape_seq.py.expect new file mode 100644 index 0000000000000..d12e858bf0a3f --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_format_unicode_escape_seq.py.expect @@ -0,0 +1,15 @@ +x = "\x1f" +x = "\\x1B" +x = "\\\x1b" +x = "\U0001f60e" +x = "\u0001F60E" +x = r"\u0001F60E" +x = "don't format me" +x = "\xa3" +x = "\u2717" +x = "\uface" +x = "\N{OX}\N{OX}" +x = "\N{LATIN SMALL LETTER X}" +x = "\N{CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I}" +x = b"\x1fdon't byte" +x = rb"\x1Fdon't format" diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_hug_parens_with_braces_and_square_brackets.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_hug_parens_with_braces_and_square_brackets.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_hug_parens_with_braces_and_square_brackets.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_hug_parens_with_braces_and_square_brackets.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_hug_parens_with_braces_and_square_brackets.py new file mode 100644 index 0000000000000..2560ff5c1fb2b --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_hug_parens_with_braces_and_square_brackets.py @@ -0,0 +1,185 @@ +def foo_brackets(request): + return JsonResponse( + { + "var_1": foo, + "var_2": bar, + } + ) + +def foo_square_brackets(request): + return JsonResponse( + [ + "var_1", + "var_2", + ] + ) + +func({"a": 37, "b": 42, "c": 927, "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111}) + +func(["random_string_number_one","random_string_number_two","random_string_number_three","random_string_number_four"]) + +func( + { + # expand me + 'a':37, + 'b':42, + 'c':927 + } +) + +func( + [ + 'a', + 'b', + 'c', + ] +) + +func( + [ + 'a', + 'b', + 'c', + ], +) + +func( # a + [ # b + "c", # c + "d", # d + "e", # e + ] # f +) # g + +func( # a + { # b + "c": 1, # c + "d": 2, # d + "e": 3, # e + } # f +) # g + +func( + # preserve me + [ + "c", + "d", + "e", + ] +) + +func( + [ # preserve me but hug brackets + "c", + "d", + "e", + ] +) + +func( + [ + # preserve me but hug brackets + "c", + "d", + "e", + ] +) + +func( + [ + "c", + # preserve me but hug brackets + "d", + "e", + ] +) + +func( + [ + "c", + "d", + "e", + # preserve me but hug brackets + ] +) + +func( + [ + "c", + "d", + "e", + ] # preserve me but hug brackets +) + +func( + [ + "c", + "d", + "e", + ] + # preserve me +) + +func([x for x in "short line"]) +func([x for x in "long line long line long line long line long line long line long line"]) +func([x for x in [x for x in "long line long line long line long line long line long line long line"]]) + +func({"short line"}) +func({"long line", "long long line", "long long long line", "long long long long line", "long long long long long line"}) +func({{"long line", "long long line", "long long long line", "long long long long line", "long long long long long line"}}) +func(("long line", "long long line", "long long long line", "long long long long line", "long long long long long line")) +func((("long line", "long long line", "long long long line", "long long long long line", "long long long long long line"))) +func([["long line", "long long line", "long long long line", "long long long long line", "long long long long long line"]]) + +# Do not hug if the argument fits on a single line. +func({"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"}) +func(("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line")) +func(["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"]) +func(**{"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit---"}) +func(*("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit----")) +array = [{"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"}] +array = [("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line")] +array = [["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"]] + +foooooooooooooooooooo( + [{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size} +) + +baaaaaaaaaaaaar( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +) + +nested_mapping = {"key": [{"a very long key 1": "with a very long value", "a very long key 2": "with a very long value"}]} +nested_array = [[["long line", "long long line", "long long long line", "long long long long line", "long long long long long line"]]] +explicit_exploding = [[["short", "line",],],] +single_item_do_not_explode = Context({ + "version": get_docs_version(), +}) + +foo(*["long long long long long line", "long long long long long line", "long long long long long line"]) + +foo(*[str(i) for i in range(100000000000000000000000000000000000000000000000000000000000)]) + +foo( + **{ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": 1, + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb": 2, + "ccccccccccccccccccccccccccccccccc": 3, + **other, + } +) + +foo(**{x: y for x, y in enumerate(["long long long long line","long long long long line"])}) + +# Edge case when deciding whether to hug the brackets without inner content. +very_very_very_long_variable = very_very_very_long_module.VeryVeryVeryVeryLongClassName([[]]) + +for foo in ["a", "b"]: + output.extend([ + individual + for + # Foobar + container in xs_by_y[foo] + # Foobar + for individual in container["nested"] + ]) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_hug_parens_with_braces_and_square_brackets.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_hug_parens_with_braces_and_square_brackets.py.expect new file mode 100644 index 0000000000000..a4f879e6dea5d --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_hug_parens_with_braces_and_square_brackets.py.expect @@ -0,0 +1,255 @@ +def foo_brackets(request): + return JsonResponse({ + "var_1": foo, + "var_2": bar, + }) + + +def foo_square_brackets(request): + return JsonResponse([ + "var_1", + "var_2", + ]) + + +func({ + "a": 37, + "b": 42, + "c": 927, + "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111, +}) + +func([ + "random_string_number_one", + "random_string_number_two", + "random_string_number_three", + "random_string_number_four", +]) + +func({ + # expand me + "a": 37, + "b": 42, + "c": 927, +}) + +func([ + "a", + "b", + "c", +]) + +func( + [ + "a", + "b", + "c", + ], +) + +func([ # a # b + "c", # c + "d", # d + "e", # e +]) # f # g + +func({ # a # b + "c": 1, # c + "d": 2, # d + "e": 3, # e +}) # f # g + +func( + # preserve me + [ + "c", + "d", + "e", + ] +) + +func([ # preserve me but hug brackets + "c", + "d", + "e", +]) + +func([ + # preserve me but hug brackets + "c", + "d", + "e", +]) + +func([ + "c", + # preserve me but hug brackets + "d", + "e", +]) + +func([ + "c", + "d", + "e", + # preserve me but hug brackets +]) + +func([ + "c", + "d", + "e", +]) # preserve me but hug brackets + +func( + [ + "c", + "d", + "e", + ] + # preserve me +) + +func([x for x in "short line"]) +func( + [x for x in "long line long line long line long line long line long line long line"] +) +func([ + x + for x in [ + x + for x in "long line long line long line long line long line long line long line" + ] +]) + +func({"short line"}) +func({ + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +}) +func({{ + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +}}) +func(( + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +)) +func((( + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +))) +func([[ + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +]]) + +# Do not hug if the argument fits on a single line. +func( + {"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"} +) +func( + ("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line") +) +func( + ["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"] +) +func( + **{"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit---"} +) +func( + *("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit----") +) +array = [ + {"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"} +] +array = [ + ("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line") +] +array = [ + ["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"] +] + +foooooooooooooooooooo( + [{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size} +) + +baaaaaaaaaaaaar( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +) + +nested_mapping = { + "key": [{ + "a very long key 1": "with a very long value", + "a very long key 2": "with a very long value", + }] +} +nested_array = [[[ + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +]]] +explicit_exploding = [ + [ + [ + "short", + "line", + ], + ], +] +single_item_do_not_explode = Context({ + "version": get_docs_version(), +}) + +foo(*[ + "long long long long long line", + "long long long long long line", + "long long long long long line", +]) + +foo(*[ + str(i) for i in range(100000000000000000000000000000000000000000000000000000000000) +]) + +foo(**{ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": 1, + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb": 2, + "ccccccccccccccccccccccccccccccccc": 3, + **other, +}) + +foo(**{ + x: y for x, y in enumerate(["long long long long line", "long long long long line"]) +}) + +# Edge case when deciding whether to hug the brackets without inner content. +very_very_very_long_variable = very_very_very_long_module.VeryVeryVeryVeryLongClassName( + [[]] +) + +for foo in ["a", "b"]: + output.extend([ + individual + for + # Foobar + container in xs_by_y[foo] + # Foobar + for individual in container["nested"] + ]) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_dict_values.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_dict_values.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_dict_values.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_dict_values.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_dict_values.py new file mode 100644 index 0000000000000..67ff7b671cb45 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_dict_values.py @@ -0,0 +1,36 @@ +my_dict = { + "something_something": + r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t" + r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t" + r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t", +} + +my_dict = { + "a key in my dict": a_very_long_variable * and_a_very_long_function_call() / 100000.0 +} + +my_dict = { + "a key in my dict": a_very_long_variable * and_a_very_long_function_call() * and_another_long_func() / 100000.0 +} + +my_dict = { + "a key in my dict": MyClass.some_attribute.first_call().second_call().third_call(some_args="some value") +} + +{ + 'xxxxxx': + xxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxx( + xxxxxxxxxxxxxx={ + 'x': + xxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + .xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + xxxxxxxxxxxxx=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + .xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx={ + 'x': x.xx, + 'x': x.x, + })))) + }), +} diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_dict_values.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_dict_values.py.expect new file mode 100644 index 0000000000000..e9ec664093a92 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_dict_values.py.expect @@ -0,0 +1,49 @@ +my_dict = { + "something_something": ( + r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t" + r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t" + r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t" + ), +} + +my_dict = { + "a key in my dict": ( + a_very_long_variable * and_a_very_long_function_call() / 100000.0 + ) +} + +my_dict = { + "a key in my dict": ( + a_very_long_variable + * and_a_very_long_function_call() + * and_another_long_func() + / 100000.0 + ) +} + +my_dict = { + "a key in my dict": ( + MyClass.some_attribute.first_call() + .second_call() + .third_call(some_args="some value") + ) +} + +{ + "xxxxxx": xxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxx( + xxxxxxxxxxxxxx={ + "x": xxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + xxxxxxxxxxxxx=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx={ + "x": x.xx, + "x": x.x, + } + ) + ) + ) + ) + } + ), +} diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings.py new file mode 100644 index 0000000000000..017f679115a06 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings.py @@ -0,0 +1,329 @@ +x = "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three." + +x += "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three." + +y = ( + 'Short string' +) + +print('This is a really long string inside of a print statement with extra arguments attached at the end of it.', x, y, z) + +print("This is a really long string inside of a print statement with no extra arguments attached at the end of it.") + +D1 = {"The First": "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.", "The Second": "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary."} + +D2 = {1.0: "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.", 2.0: "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary."} + +D3 = {x: "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.", y: "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary."} + +D4 = {"A long and ridiculous {}".format(string_key): "This is a really really really long string that has to go i,side of a dictionary. It is soooo bad.", some_func("calling", "some", "stuff"): "This is a really really really long string that has to go inside of a dictionary. It is {soooo} bad (#{x}).".format(sooo="soooo", x=2), "A %s %s" % ("formatted", "string"): "This is a really really really long string that has to go inside of a dictionary. It is %s bad (#%d)." % ("soooo", 2)} + +D5 = { # Test for https://github.com/psf/black/issues/3261 + ("This is a really long string that can't be expected to fit in one line and is used as a nested dict's key"): {"inner": "value"}, +} + +D6 = { # Test for https://github.com/psf/black/issues/3261 + ("This is a really long string that can't be expected to fit in one line and is used as a dict's key"): ["value1", "value2"], +} + +L1 = ["The is a short string", "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a list literal, so it's expected to be wrapped in parens when splitting to avoid implicit str concatenation.", short_call("arg", {"key": "value"}), "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a list literal.", ("parens should be stripped for short string in list")] + +L2 = ["This is a really long string that can't be expected to fit in one line and is the only child of a list literal."] + +S1 = {"The is a short string", "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a set literal, so it's expected to be wrapped in parens when splitting to avoid implicit str concatenation.", short_call("arg", {"key": "value"}), "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a set literal.", ("parens should be stripped for short string in set")} + +S2 = {"This is a really long string that can't be expected to fit in one line and is the only child of a set literal."} + +T1 = ("The is a short string", "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a tuple literal, so it's expected to be wrapped in parens when splitting to avoid implicit str concatenation.", short_call("arg", {"key": "value"}), "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a tuple literal.", ("parens should be stripped for short string in list")) + +T2 = ("This is a really long string that can't be expected to fit in one line and is the only child of a tuple literal.",) + +func_with_keywords(my_arg, my_kwarg="Long keyword strings also need to be wrapped, but they will probably need to be handled a little bit differently.") + +bad_split1 = ( + 'But what should happen when code has already been formatted but in the wrong way? Like' + " with a space at the end instead of the beginning. Or what about when it is split too soon?" +) + +bad_split2 = "But what should happen when code has already " \ + "been formatted but in the wrong way? Like " \ + "with a space at the end instead of the " \ + "beginning. Or what about when it is split too " \ + "soon? In the case of a split that is too " \ + "short, black will try to honer the custom " \ + "split." + +bad_split3 = ( + "What if we have inline comments on " # First Comment + "each line of a bad split? In that " # Second Comment + "case, we should just leave it alone." # Third Comment +) + +bad_split_func1( + "But what should happen when code has already " + "been formatted but in the wrong way? Like " + "with a space at the end instead of the " + "beginning. Or what about when it is split too " + "soon? In the case of a split that is too " + "short, black will try to honer the custom " + "split.", + xxx, yyy, zzz +) + +bad_split_func2( + xxx, yyy, zzz, + long_string_kwarg="But what should happen when code has already been formatted but in the wrong way? Like " + "with a space at the end instead of the beginning. Or what about when it is split too " + "soon?", +) + +bad_split_func3( + ( + "But what should happen when code has already " + r"been formatted but in the wrong way? Like " + "with a space at the end instead of the " + r"beginning. Or what about when it is split too " + r"soon? In the case of a split that is too " + "short, black will try to honer the custom " + "split." + ), + xxx, + yyy, + zzz, +) + +inline_comments_func1( + "if there are inline " + "comments in the middle " + # Here is the standard alone comment. + "of the implicitly concatenated " + "string, we should handle " + "them correctly", + xxx, +) + +inline_comments_func2( + "what if the string is very very very very very very very very very very long and this part does " + "not fit into a single line? " + # Here is the standard alone comment. + "then the string should still be properly handled by merging and splitting " + "it into parts that fit in line length.", + xxx, +) + +raw_string = r"This is a long raw string. When re-formatting this string, black needs to make sure it prepends the 'r' onto the new string." + +fmt_string1 = "We also need to be sure to preserve any and all {} which may or may not be attached to the string in question.".format("method calls") + +fmt_string2 = "But what about when the string is {} but {}".format("short", "the method call is really really really really really really really really long?") + +old_fmt_string1 = "While we are on the topic of %s, we should also note that old-style formatting must also be preserved, since some %s still uses it." % ("formatting", "code") + +old_fmt_string2 = "This is a %s %s %s %s" % ("really really really really really", "old", "way to format strings!", "Use f-strings instead!") + +old_fmt_string3 = "Whereas only the strings after the percent sign were long in the last example, this example uses a long initial string as well. This is another %s %s %s %s" % ("really really really really really", "old", "way to format strings!", "Use f-strings instead!") + +fstring = f"f-strings definitely make things more {difficult} than they need to be for {{black}}. But boy they sure are handy. The problem is that some lines will need to have the 'f' whereas others do not. This {line}, for example, needs one." + +fstring_with_no_fexprs = f"Some regular string that needs to get split certainly but is NOT an fstring by any means whatsoever." + +comment_string = "Long lines with inline comments should have their comments appended to the reformatted string's enclosing right parentheses." # This comment gets thrown to the top. + +arg_comment_string = print("Long lines with inline comments which are apart of (and not the only member of) an argument list should have their comments appended to the reformatted string's enclosing left parentheses.", # This comment gets thrown to the top. + "Arg #2", "Arg #3", "Arg #4", "Arg #5") + +pragma_comment_string1 = "Lines which end with an inline pragma comment of the form `# : <...>` should be left alone." # noqa: E501 + +pragma_comment_string2 = "Lines which end with an inline pragma comment of the form `# : <...>` should be left alone." # noqa + +"""This is a really really really long triple quote string and it should not be touched.""" + +triple_quote_string = """This is a really really really long triple quote string assignment and it should not be touched.""" + +assert some_type_of_boolean_expression, "Followed by a really really really long string that is used to provide context to the AssertionError exception." + +assert some_type_of_boolean_expression, "Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic string {}.".format("formatting") + +assert some_type_of_boolean_expression, "Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic string %s." % "formatting" + +assert some_type_of_boolean_expression, "Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic %s %s." % ("string", "formatting") + +some_function_call("With a reallly generic name and with a really really long string that is, at some point down the line, " + added + " to a variable and then added to another string.") + +some_function_call("With a reallly generic name and with a really really long string that is, at some point down the line, " + added + " to a variable and then added to another string. But then what happens when the final string is also supppppperrrrr long?! Well then that second (realllllllly long) string should be split too.", "and a second argument", and_a_third) + +return "A really really really really really really really really really really really really really long {} {}".format("return", "value") + +func_with_bad_comma( + "This is a really long string argument to a function that has a trailing comma which should NOT be there.", +) + +func_with_bad_comma( + "This is a really long string argument to a function that has a trailing comma which should NOT be there.", # comment after comma +) + +func_with_bad_comma( + ( + "This is a really long string argument to a function that has a trailing comma" + " which should NOT be there." + ), +) + +func_with_bad_comma( + ( + "This is a really long string argument to a function that has a trailing comma" + " which should NOT be there." + ), # comment after comma +) + +func_with_bad_parens_that_wont_fit_in_one_line( + ("short string that should have parens stripped"), + x, + y, + z +) + +func_with_bad_parens_that_wont_fit_in_one_line( + x, + y, + ("short string that should have parens stripped"), + z +) + +func_with_bad_parens( + ("short string that should have parens stripped"), + x, + y, + z, +) + +func_with_bad_parens( + x, + y, + ("short string that should have parens stripped"), + z, +) + +annotated_variable: Final = "This is a large " + STRING + " that has been " + CONCATENATED + "using the '+' operator." +annotated_variable: Final = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped." +annotated_variable: Literal["fakse_literal"] = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped." + +backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\" +backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\\\" +backslashes = "This is a really 'long' string with \"embedded double quotes\" and 'single' quotes that also handles checking for an odd number of backslashes \\\", like this...\\\\\\" + +short_string = ( + "Hi" + " there." +) + +func_call( + short_string=( + "Hi" + " there." + ) +) + +raw_strings = r"Don't" " get" r" merged" " unless they are all raw." + +def foo(): + yield "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three." + +x = f"This is a {{really}} long string that needs to be split without a doubt (i.e. most definitely). In short, this {string} that can't possibly be {{expected}} to fit all together on one line. In {fact} it may even take up three or more lines... like four or five... but probably just four." + +long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # type: ignore + " of it." +) + +long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # noqa + " of it." +) + +long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # pylint: disable=some-pylint-check + " of it." +) + +string_with_nameescape = ( + "........................................................................ \N{LAO KO LA}" +) + +string_with_nameescape = ( + "........................................................................... \N{LAO KO LA}" +) + +string_with_nameescape = ( + "............................................................................ \N{LAO KO LA}" +) + +string_with_nameescape_and_escaped_backslash = ( + "...................................................................... \\\N{LAO KO LA}" +) + +string_with_nameescape_and_escaped_backslash = ( + "......................................................................... \\\N{LAO KO LA}" +) + +string_with_nameescape_and_escaped_backslash = ( + ".......................................................................... \\\N{LAO KO LA}" +) + +string_with_escaped_nameescape = ( + "........................................................................ \\N{LAO KO LA}" +) + +string_with_escaped_nameescape = ( + "........................................................................... \\N{LAO KO LA}" +) + +msg = lambda x: f"this is a very very very long lambda value {x} that doesn't fit on a single line" + +dict_with_lambda_values = { + "join": lambda j: ( + f"{j.__class__.__name__}({some_function_call(j.left)}, " + f"{some_function_call(j.right)})" + ), +} + +# Complex string concatenations with a method call in the middle. +code = ( + (" return [\n") + + ( + ", \n".join( + " (%r, self.%s, visitor.%s)" + % (attrname, attrname, visit_name) + for attrname, visit_name in names + ) + ) + + ("\n ]\n") +) + + +# Test case of an outer string' parens enclose an inner string's parens. +call(body=("%s %s" % ((",".join(items)), suffix))) + +log.info(f'Skipping: {desc["db_id"]=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]=} {desc["exposure_max"]=}') + +log.info(f"Skipping: {desc['db_id']=} {desc['ms_name']} {money=} {dte=} {pos_share=} {desc['status']=} {desc['exposure_max']=}") + +log.info(f'Skipping: {desc["db_id"]} {foo("bar",x=123)} {"foo" != "bar"} {(x := "abc=")} {pos_share=} {desc["status"]} {desc["exposure_max"]}') + +log.info(f'Skipping: {desc["db_id"]} {desc["ms_name"]} {money=} {(x := "abc=")=} {pos_share=} {desc["status"]} {desc["exposure_max"]}') + +log.info(f'Skipping: {desc["db_id"]} {foo("bar",x=123)=} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}') + +log.info(f'Skipping: {foo("asdf")=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}') + +log.info(f'Skipping: {"a" == "b" == "c" == "d"} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}') + +log.info(f'Skipping: {"a" == "b" == "c" == "d"=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}') + +log.info(f'Skipping: { longer_longer_longer_longer_longer_longer_name [ "db_id" ] [ "another_key" ] = : .3f }') + +log.info(f'''Skipping: {"a" == 'b'} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}''') + +log.info(f'''Skipping: {'a' == "b"=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}''') + +log.info(f"""Skipping: {'a' == 'b'} {desc['ms_name']} {money=} {dte=} {pos_share=} {desc['status']} {desc['exposure_max']}""") diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings.py.expect new file mode 100644 index 0000000000000..4b7bdd86d2baa --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings.py.expect @@ -0,0 +1,594 @@ +x = ( + "This is a really long string that can't possibly be expected to fit all together" + " on one line. In fact it may even take up three or more lines... like four or" + " five... but probably just three." +) + +x += ( + "This is a really long string that can't possibly be expected to fit all together" + " on one line. In fact it may even take up three or more lines... like four or" + " five... but probably just three." +) + +y = "Short string" + +print( + "This is a really long string inside of a print statement with extra arguments" + " attached at the end of it.", + x, + y, + z, +) + +print( + "This is a really long string inside of a print statement with no extra arguments" + " attached at the end of it." +) + +D1 = { + "The First": ( + "This is a really long string that can't possibly be expected to fit all" + " together on one line. Also it is inside a dictionary, so formatting is more" + " difficult." + ), + "The Second": ( + "This is another really really (not really) long string that also can't be" + " expected to fit on one line and is, like the other string, inside a" + " dictionary." + ), +} + +D2 = { + 1.0: ( + "This is a really long string that can't possibly be expected to fit all" + " together on one line. Also it is inside a dictionary, so formatting is more" + " difficult." + ), + 2.0: ( + "This is another really really (not really) long string that also can't be" + " expected to fit on one line and is, like the other string, inside a" + " dictionary." + ), +} + +D3 = { + x: ( + "This is a really long string that can't possibly be expected to fit all" + " together on one line. Also it is inside a dictionary, so formatting is more" + " difficult." + ), + y: ( + "This is another really really (not really) long string that also can't be" + " expected to fit on one line and is, like the other string, inside a" + " dictionary." + ), +} + +D4 = { + "A long and ridiculous {}".format(string_key): ( + "This is a really really really long string that has to go i,side of a" + " dictionary. It is soooo bad." + ), + some_func("calling", "some", "stuff"): ( + "This is a really really really long string that has to go inside of a" + " dictionary. It is {soooo} bad (#{x}).".format(sooo="soooo", x=2) + ), + "A %s %s" + % ("formatted", "string"): ( + "This is a really really really long string that has to go inside of a" + " dictionary. It is %s bad (#%d)." % ("soooo", 2) + ), +} + +D5 = { # Test for https://github.com/psf/black/issues/3261 + "This is a really long string that can't be expected to fit in one line and is used as a nested dict's key": { + "inner": "value" + }, +} + +D6 = { # Test for https://github.com/psf/black/issues/3261 + "This is a really long string that can't be expected to fit in one line and is used as a dict's key": [ + "value1", + "value2", + ], +} + +L1 = [ + "The is a short string", + ( + "This is a really long string that can't possibly be expected to fit all" + " together on one line. Also it is inside a list literal, so it's expected to" + " be wrapped in parens when splitting to avoid implicit str concatenation." + ), + short_call("arg", {"key": "value"}), + ( + "This is another really really (not really) long string that also can't be" + " expected to fit on one line and is, like the other string, inside a list" + " literal." + ), + "parens should be stripped for short string in list", +] + +L2 = [ + "This is a really long string that can't be expected to fit in one line and is the" + " only child of a list literal." +] + +S1 = { + "The is a short string", + ( + "This is a really long string that can't possibly be expected to fit all" + " together on one line. Also it is inside a set literal, so it's expected to be" + " wrapped in parens when splitting to avoid implicit str concatenation." + ), + short_call("arg", {"key": "value"}), + ( + "This is another really really (not really) long string that also can't be" + " expected to fit on one line and is, like the other string, inside a set" + " literal." + ), + "parens should be stripped for short string in set", +} + +S2 = { + "This is a really long string that can't be expected to fit in one line and is the" + " only child of a set literal." +} + +T1 = ( + "The is a short string", + ( + "This is a really long string that can't possibly be expected to fit all" + " together on one line. Also it is inside a tuple literal, so it's expected to" + " be wrapped in parens when splitting to avoid implicit str concatenation." + ), + short_call("arg", {"key": "value"}), + ( + "This is another really really (not really) long string that also can't be" + " expected to fit on one line and is, like the other string, inside a tuple" + " literal." + ), + "parens should be stripped for short string in list", +) + +T2 = ( + ( + "This is a really long string that can't be expected to fit in one line and is" + " the only child of a tuple literal." + ), +) + +func_with_keywords( + my_arg, + my_kwarg=( + "Long keyword strings also need to be wrapped, but they will probably need to" + " be handled a little bit differently." + ), +) + +bad_split1 = ( + "But what should happen when code has already been formatted but in the wrong way?" + " Like with a space at the end instead of the beginning. Or what about when it is" + " split too soon?" +) + +bad_split2 = ( + "But what should happen when code has already " + "been formatted but in the wrong way? Like " + "with a space at the end instead of the " + "beginning. Or what about when it is split too " + "soon? In the case of a split that is too " + "short, black will try to honer the custom " + "split." +) + +bad_split3 = ( + "What if we have inline comments on " # First Comment + "each line of a bad split? In that " # Second Comment + "case, we should just leave it alone." # Third Comment +) + +bad_split_func1( + "But what should happen when code has already " + "been formatted but in the wrong way? Like " + "with a space at the end instead of the " + "beginning. Or what about when it is split too " + "soon? In the case of a split that is too " + "short, black will try to honer the custom " + "split.", + xxx, + yyy, + zzz, +) + +bad_split_func2( + xxx, + yyy, + zzz, + long_string_kwarg=( + "But what should happen when code has already been formatted but in the wrong" + " way? Like with a space at the end instead of the beginning. Or what about" + " when it is split too soon?" + ), +) + +bad_split_func3( + ( + "But what should happen when code has already " + r"been formatted but in the wrong way? Like " + "with a space at the end instead of the " + r"beginning. Or what about when it is split too " + r"soon? In the case of a split that is too " + "short, black will try to honer the custom " + "split." + ), + xxx, + yyy, + zzz, +) + +inline_comments_func1( + "if there are inline comments in the middle " + # Here is the standard alone comment. + "of the implicitly concatenated string, we should handle them correctly", + xxx, +) + +inline_comments_func2( + "what if the string is very very very very very very very very very very long and" + " this part does not fit into a single line? " + # Here is the standard alone comment. + "then the string should still be properly handled by merging and splitting " + "it into parts that fit in line length.", + xxx, +) + +raw_string = ( + r"This is a long raw string. When re-formatting this string, black needs to make" + r" sure it prepends the 'r' onto the new string." +) + +fmt_string1 = ( + "We also need to be sure to preserve any and all {} which may or may not be" + " attached to the string in question.".format("method calls") +) + +fmt_string2 = "But what about when the string is {} but {}".format( + "short", + "the method call is really really really really really really really really long?", +) + +old_fmt_string1 = ( + "While we are on the topic of %s, we should also note that old-style formatting" + " must also be preserved, since some %s still uses it." % ("formatting", "code") +) + +old_fmt_string2 = "This is a %s %s %s %s" % ( + "really really really really really", + "old", + "way to format strings!", + "Use f-strings instead!", +) + +old_fmt_string3 = ( + "Whereas only the strings after the percent sign were long in the last example," + " this example uses a long initial string as well. This is another %s %s %s %s" + % ( + "really really really really really", + "old", + "way to format strings!", + "Use f-strings instead!", + ) +) + +fstring = ( + f"f-strings definitely make things more {difficult} than they need to be for" + " {black}. But boy they sure are handy. The problem is that some lines will need" + f" to have the 'f' whereas others do not. This {line}, for example, needs one." +) + +fstring_with_no_fexprs = ( + f"Some regular string that needs to get split certainly but is NOT an fstring by" + f" any means whatsoever." +) + +comment_string = ( # This comment gets thrown to the top. + "Long lines with inline comments should have their comments appended to the" + " reformatted string's enclosing right parentheses." +) + +arg_comment_string = print( + "Long lines with inline comments which are apart of (and not the only member of) an" + " argument list should have their comments appended to the reformatted string's" + " enclosing left parentheses.", # This comment gets thrown to the top. + "Arg #2", + "Arg #3", + "Arg #4", + "Arg #5", +) + +pragma_comment_string1 = "Lines which end with an inline pragma comment of the form `# : <...>` should be left alone." # noqa: E501 + +pragma_comment_string2 = "Lines which end with an inline pragma comment of the form `# : <...>` should be left alone." # noqa + +"""This is a really really really long triple quote string and it should not be touched.""" + +triple_quote_string = """This is a really really really long triple quote string assignment and it should not be touched.""" + +assert some_type_of_boolean_expression, ( + "Followed by a really really really long string that is used to provide context to" + " the AssertionError exception." +) + +assert some_type_of_boolean_expression, ( + "Followed by a really really really long string that is used to provide context to" + " the AssertionError exception, which uses dynamic string {}.".format("formatting") +) + +assert some_type_of_boolean_expression, ( + "Followed by a really really really long string that is used to provide context to" + " the AssertionError exception, which uses dynamic string %s." % "formatting" +) + +assert some_type_of_boolean_expression, ( + "Followed by a really really really long string that is used to provide context to" + " the AssertionError exception, which uses dynamic %s %s." + % ("string", "formatting") +) + +some_function_call( + "With a reallly generic name and with a really really long string that is, at some" + " point down the line, " + + added + + " to a variable and then added to another string." +) + +some_function_call( + "With a reallly generic name and with a really really long string that is, at some" + " point down the line, " + + added + + " to a variable and then added to another string. But then what happens when the" + " final string is also supppppperrrrr long?! Well then that second (realllllllly" + " long) string should be split too.", + "and a second argument", + and_a_third, +) + +return ( + "A really really really really really really really really really really really" + " really really long {} {}".format("return", "value") +) + +func_with_bad_comma( + "This is a really long string argument to a function that has a trailing comma" + " which should NOT be there.", +) + +func_with_bad_comma( + "This is a really long string argument to a function that has a trailing comma" + " which should NOT be there.", # comment after comma +) + +func_with_bad_comma( + "This is a really long string argument to a function that has a trailing comma" + " which should NOT be there.", +) + +func_with_bad_comma( + "This is a really long string argument to a function that has a trailing comma" + " which should NOT be there.", # comment after comma +) + +func_with_bad_parens_that_wont_fit_in_one_line( + "short string that should have parens stripped", x, y, z +) + +func_with_bad_parens_that_wont_fit_in_one_line( + x, y, "short string that should have parens stripped", z +) + +func_with_bad_parens( + "short string that should have parens stripped", + x, + y, + z, +) + +func_with_bad_parens( + x, + y, + "short string that should have parens stripped", + z, +) + +annotated_variable: Final = ( + "This is a large " + + STRING + + " that has been " + + CONCATENATED + + "using the '+' operator." +) +annotated_variable: Final = ( + "This is a large string that has a type annotation attached to it. A type" + " annotation should NOT stop a long string from being wrapped." +) +annotated_variable: Literal["fakse_literal"] = ( + "This is a large string that has a type annotation attached to it. A type" + " annotation should NOT stop a long string from being wrapped." +) + +backslashes = ( + "This is a really long string with \"embedded\" double quotes and 'single' quotes" + " that also handles checking for an even number of backslashes \\" +) +backslashes = ( + "This is a really long string with \"embedded\" double quotes and 'single' quotes" + " that also handles checking for an even number of backslashes \\\\" +) +backslashes = ( + "This is a really 'long' string with \"embedded double quotes\" and 'single' quotes" + ' that also handles checking for an odd number of backslashes \\", like' + " this...\\\\\\" +) + +short_string = "Hi there." + +func_call(short_string="Hi there.") + +raw_strings = r"Don't" " get" r" merged" " unless they are all raw." + + +def foo(): + yield ( + "This is a really long string that can't possibly be expected to fit all" + " together on one line. In fact it may even take up three or more lines... like" + " four or five... but probably just three." + ) + + +x = ( + "This is a {really} long string that needs to be split without a doubt (i.e." + f" most definitely). In short, this {string} that can't possibly be {{expected}} to" + f" fit all together on one line. In {fact} it may even take up three or more" + " lines... like four or five... but probably just four." +) + +long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # type: ignore + " of it." +) + +long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # noqa + " of it." +) + +long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # pylint: disable=some-pylint-check + " of it." +) + +string_with_nameescape = ( + "........................................................................" + " \N{LAO KO LA}" +) + +string_with_nameescape = ( + "..........................................................................." + " \N{LAO KO LA}" +) + +string_with_nameescape = ( + "............................................................................" + " \N{LAO KO LA}" +) + +string_with_nameescape_and_escaped_backslash = ( + "......................................................................" + " \\\N{LAO KO LA}" +) + +string_with_nameescape_and_escaped_backslash = ( + "........................................................................." + " \\\N{LAO KO LA}" +) + +string_with_nameescape_and_escaped_backslash = ( + ".........................................................................." + " \\\N{LAO KO LA}" +) + +string_with_escaped_nameescape = ( + "........................................................................ \\N{LAO" + " KO LA}" +) + +string_with_escaped_nameescape = ( + "..........................................................................." + " \\N{LAO KO LA}" +) + +msg = ( + lambda x: ( + f"this is a very very very long lambda value {x} that doesn't fit on a single" + " line" + ) +) + +dict_with_lambda_values = { + "join": lambda j: ( + f"{j.__class__.__name__}({some_function_call(j.left)}, " + f"{some_function_call(j.right)})" + ), +} + +# Complex string concatenations with a method call in the middle. +code = ( + " return [\n" + + ", \n".join( + " (%r, self.%s, visitor.%s)" % (attrname, attrname, visit_name) + for attrname, visit_name in names + ) + + "\n ]\n" +) + + +# Test case of an outer string' parens enclose an inner string's parens. +call(body="%s %s" % (",".join(items), suffix)) + +log.info( + "Skipping:" + f' {desc["db_id"]=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]=} {desc["exposure_max"]=}' +) + +log.info( + "Skipping:" + f" {desc['db_id']=} {desc['ms_name']} {money=} {dte=} {pos_share=} {desc['status']=} {desc['exposure_max']=}" +) + +log.info( + "Skipping:" + f" {desc['db_id']} {foo('bar',x=123)} {'foo' != 'bar'} {(x := 'abc=')} {pos_share=} {desc['status']} {desc['exposure_max']}" +) + +log.info( + "Skipping:" + f' {desc["db_id"]} {desc["ms_name"]} {money=} {(x := "abc=")=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' +) + +log.info( + "Skipping:" + f' {desc["db_id"]} {foo("bar",x=123)=} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' +) + +log.info( + "Skipping:" + f' {foo("asdf")=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' +) + +log.info( + "Skipping:" + f" {'a' == 'b' == 'c' == 'd'} {desc['ms_name']} {money=} {dte=} {pos_share=} {desc['status']} {desc['exposure_max']}" +) + +log.info( + "Skipping:" + f' {"a" == "b" == "c" == "d"=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' +) + +log.info( + "Skipping:" + f' { longer_longer_longer_longer_longer_longer_name [ "db_id" ] [ "another_key" ] = : .3f }' +) + +log.info( + f"""Skipping: {"a" == 'b'} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}""" +) + +log.info( + f"""Skipping: {'a' == "b"=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}""" +) + +log.info( + f"""Skipping: {'a' == 'b'} {desc['ms_name']} {money=} {dte=} {pos_share=} {desc['status']} {desc['exposure_max']}""" +) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__east_asian_width.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__east_asian_width.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__east_asian_width.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__east_asian_width.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__east_asian_width.py new file mode 100644 index 0000000000000..e807dc2035db7 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__east_asian_width.py @@ -0,0 +1,6 @@ +# The following strings do not have not-so-many chars, but are long enough +# when these are rendered in a monospace font (if the renderer respects +# Unicode East Asian Width properties). +hangul = '코드포인트 수는 적으나 실제 터미널이나 에디터에서 렌더링될 땐 너무 길어서 줄바꿈이 필요한 문자열' +hanzi = '中文測試:代碼點數量少,但在真正的終端模擬器或編輯器中呈現時太長,因此需要換行的字符串。' +japanese = 'コードポイントの数は少ないが、実際の端末エミュレータやエディタでレンダリングされる時は長すぎる為、改行が要る文字列' diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__east_asian_width.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__east_asian_width.py.expect new file mode 100644 index 0000000000000..c5c05b31fa9d9 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__east_asian_width.py.expect @@ -0,0 +1,16 @@ +# The following strings do not have not-so-many chars, but are long enough +# when these are rendered in a monospace font (if the renderer respects +# Unicode East Asian Width properties). +hangul = ( + "코드포인트 수는 적으나 실제 터미널이나 에디터에서 렌더링될 땐 너무 길어서 줄바꿈이" + " 필요한 문자열" +) +hanzi = ( + "中文測試:代碼點數量少,但在真正的終端模擬器或編輯器中呈現時太長," + "因此需要換行的字符串。" +) +japanese = ( + "コードポイントの数は少ないが、" + "実際の端末エミュレータやエディタでレンダリングされる時は長すぎる為、" + "改行が要る文字列" +) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__edge_case.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__edge_case.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__edge_case.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__edge_case.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__edge_case.py new file mode 100644 index 0000000000000..c747ad388607b --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__edge_case.py @@ -0,0 +1,37 @@ +some_variable = "This string is long but not so long that it needs to be split just yet" +some_variable = 'This string is long but not so long that it needs to be split just yet' +some_variable = "This string is long, just long enough that it needs to be split, u get?" +some_variable = 'This string is long, just long enough that it needs to be split, u get?' +some_variable = "This string is long, just long enough that it needs to be split, u get? So we stay" +some_variable = 'This string is long, just long enough that it needs to be split, u get? So we stay' +some_variable = "This string is long, just long enough that it needs to be split, u get? So we split" +some_variable = 'This string is long, just long enough that it needs to be split, u get? So we split' +some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at alll".format("ha") +some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at allll".format("ha") +some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at alllllllllll".format("ha") +some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at allllllllllll".format("ha") +some_variable = "This is a long string that will end with a method that is not calleddd".format +addition_inside_tuple = ( + some_string_inside_a_variable + + "Some string that is just long enough to cause a split to take place.............", + xyz, + "Some really long string that needs to get split eventually but I'm running out of things to say" + some_string_inside_a_variable +) +addition_inside_tuple = ( + some_string_inside_a_variable + + "Some string that is just long enough to cause a split to take place.............." +) +return "Hi there. This is areally really reallllly long string that needs to be split!!!" +ternary_expression = ( + "Short String" + if some_condition + else "This is a really long string that will eventually need to be split right here." +) +return f'{x}/b/c/d/d/d/dadfjsadjsaidoaisjdsfjaofjdfijaidfjaodfjaoifjodjafojdoajaaaaaaaaaaa' +return f'{x}/b/c/d/d/d/dadfjsadjsaidoaisjdsfjaofjdfijaidfjaodfjaoifjodjafojdoajaaaaaaaaaaaa' +assert str(result) == "This long string should be split at some point right close to or around hereeeeeee" +assert str(result) < "This long string should be split at some point right close to or around hereeeeee" +assert "A format string: %s" % "This long string should be split at some point right close to or around hereeeeeee" != result +msg += "This long string should be wrapped in parens at some point right around hereeeee" +msg += "This long string should be split at some point right close to or around hereeeeeeee" +msg += "This long string should not be split at any point ever since it is just righttt" diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__edge_case.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__edge_case.py.expect new file mode 100644 index 0000000000000..12ffc671d2a37 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__edge_case.py.expect @@ -0,0 +1,98 @@ +some_variable = "This string is long but not so long that it needs to be split just yet" +some_variable = "This string is long but not so long that it needs to be split just yet" +some_variable = ( + "This string is long, just long enough that it needs to be split, u get?" +) +some_variable = ( + "This string is long, just long enough that it needs to be split, u get?" +) +some_variable = ( + "This string is long, just long enough that it needs to be split, u get? So we stay" +) +some_variable = ( + "This string is long, just long enough that it needs to be split, u get? So we stay" +) +some_variable = ( + "This string is long, just long enough that it needs to be split, u get? So we" + " split" +) +some_variable = ( + "This string is long, just long enough that it needs to be split, u get? So we" + " split" +) +some_variable = ( + "This string is long but not so long that it needs hahahah toooooo be so greatttt" + " {} that I just can't think of any more good words to say about it at alll".format( + "ha" + ) +) +some_variable = ( + "This string is long but not so long that it needs hahahah toooooo be so greatttt" + " {} that I just can't think of any more good words to say about it at allll" + .format("ha") +) +some_variable = ( + "This string is long but not so long that it needs hahahah toooooo be so greatttt" + " {} that I just can't think of any more good words to say about it at alllllllllll" + .format("ha") +) +some_variable = ( + "This string is long but not so long that it needs hahahah toooooo be so greatttt" + " {} that I just can't think of any more good words to say about it at" + " allllllllllll".format("ha") +) +some_variable = ( + "This is a long string that will end with a method that is not calleddd".format +) +addition_inside_tuple = ( + some_string_inside_a_variable + + "Some string that is just long enough to cause a split to take" + " place.............", + xyz, + "Some really long string that needs to get split eventually but I'm running out of" + " things to say" + + some_string_inside_a_variable, +) +addition_inside_tuple = ( + some_string_inside_a_variable + + "Some string that is just long enough to cause a split to take" + " place.............." +) +return ( + "Hi there. This is areally really reallllly long string that needs to be split!!!" +) +ternary_expression = ( + "Short String" + if some_condition + else ( + "This is a really long string that will eventually need to be split right here." + ) +) +return ( + f"{x}/b/c/d/d/d/dadfjsadjsaidoaisjdsfjaofjdfijaidfjaodfjaoifjodjafojdoajaaaaaaaaaaa" +) +return f"{x}/b/c/d/d/d/dadfjsadjsaidoaisjdsfjaofjdfijaidfjaodfjaoifjodjafojdoajaaaaaaaaaaaa" +assert ( + str(result) + == "This long string should be split at some point right close to or around" + " hereeeeeee" +) +assert ( + str(result) + < "This long string should be split at some point right close to or around" + " hereeeeee" +) +assert ( + "A format string: %s" + % "This long string should be split at some point right close to or around" + " hereeeeeee" + != result +) +msg += ( + "This long string should be wrapped in parens at some point right around hereeeee" +) +msg += ( + "This long string should be split at some point right close to or around" + " hereeeeeeee" +) +msg += "This long string should not be split at any point ever since it is just righttt" diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__regression.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__regression.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__regression.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__regression.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__regression.py new file mode 100644 index 0000000000000..74b6cd43a2aa4 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__regression.py @@ -0,0 +1,561 @@ +class A: + def foo(): + result = type(message)("") + + +# Don't merge multiline (e.g. triple-quoted) strings. +def foo(): + query = ( + """SELECT xxxxxxxxxxxxxxxxxxxx(xxx)""" + """ FROM xxxxxxxxxxxxxxxx WHERE xxxxxxxxxx AND xxx <> xxxxxxxxxxxxxx()""") + +# There was a bug where tuples were being identified as long strings. +long_tuple = ('Apple', 'Berry', 'Cherry', 'Dill', 'Evergreen', 'Fig', + 'Grape', 'Harry', 'Iglu', 'Jaguar') + +stupid_format_method_bug = "Some really long string that just so happens to be the {} {} to force the 'format' method to hang over the line length boundary. This is pretty annoying.".format("perfect", "length") + +class A: + def foo(): + os.system("This is a regression test. xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxxx.".format("xxxxxxxxxx", "xxxxxx", "xxxxxxxxxx")) + + +class A: + def foo(): + XXXXXXXXXXXX.append( + ( + "xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx, xxxx_xxxx_xxxxxxxxxx={})".format( + xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx + ), + my_var, + my_other_var, + ) + ) + +class A: + class B: + def foo(): + bar( + ( + "[{}]: xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx={}" + " xxxx_xxxx_xxxxxxxxxx={}, xxxx={})" + .format(xxxx._xxxxxxxxxxxxxx, xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx, xxxxxxx) + ), + varX, + varY, + varZ, + ) + +def foo(xxxx): + for (xxx_xxxx, _xxx_xxx, _xxx_xxxxx, xxx_xxxx) in xxxx: + for xxx in xxx_xxxx: + assert ("x" in xxx) or ( + xxx in xxx_xxx_xxxxx + ), "{0} xxxxxxx xx {1}, xxx {1} xx xxx xx xxxx xx xxx xxxx: xxx xxxx {2}".format( + xxx_xxxx, xxx, xxxxxx.xxxxxxx(xxx_xxx_xxxxx) + ) + +class A: + def disappearing_comment(): + return ( + ( # xx -x xxxxxxx xx xxx xxxxxxx. + '{{xxx_xxxxxxxxxx_xxxxxxxx}} xxx xxxx' + ' {} {{xxxx}} >&2' + .format( + "{xxxx} {xxxxxx}" + if xxxxx.xx_xxxxxxxxxx + else ( # Disappearing Comment + "--xxxxxxx --xxxxxx=x --xxxxxx-xxxxx=xxxxxx" + " --xxxxxx-xxxx=xxxxxxxxxxx.xxx" + ) + ) + ), + (x, y, z), + ) + +class A: + class B: + def foo(): + xxxxx_xxxx( + xx, "\t" + "@xxxxxx '{xxxx_xxx}\t' > {xxxxxx_xxxx}.xxxxxxx;" + "{xxxx_xxx} >> {xxxxxx_xxxx}.xxxxxxx 2>&1; xx=$$?;" + "xxxx $$xx" + .format(xxxx_xxx=xxxx_xxxxxxx, xxxxxx_xxxx=xxxxxxx + "/" + xxxx_xxx_xxxx, x=xxx_xxxxx_xxxxx_xxx), + x, + y, + z, + ) + +func_call_where_string_arg_has_method_call_and_bad_parens( + ( + "A long string with {}. This string is so long that it is ridiculous. It can't fit on one line at alllll.".format("formatting") + ), +) + +func_call_where_string_arg_has_old_fmt_and_bad_parens( + ( + "A long string with {}. This string is so long that it is ridiculous. It can't fit on one line at alllll." % "formatting" + ), +) + +func_call_where_string_arg_has_old_fmt_and_bad_parens( + ( + "A long string with {}. This {} is so long that it is ridiculous. It can't fit on one line at alllll." % ("formatting", "string") + ), +) + +class A: + def append(self): + if True: + xxxx.xxxxxxx.xxxxx( ('xxxxxxxxxx xxxx xx xxxxxx(%x) xx %x xxxx xx xxx %x.xx' + % (len(self) + 1, + xxxx.xxxxxxxxxx, + xxxx.xxxxxxxxxx)) + + (' %.3f (%s) to %.3f (%s).\n' + % (xxxx.xxxxxxxxx, + xxxx.xxxxxxxxxxxxxx(xxxx.xxxxxxxxx), + x, + xxxx.xxxxxxxxxxxxxx( xx) + ))) + +class A: + def foo(): + some_func_call( + 'xxxxxxxxxx', + ( + "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " + "\"xxxx xxxxxxx xxxxxx xxxx; xxxx xxxxxx_xxxxx xxxxxx xxxx; " + "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" " + ), + None, + ('xxxxxxxxxxx',), + ), + +class A: + def foo(): + some_func_call( + ( + "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " + "xxxx, ('xxxxxxx xxxxxx xxxx, xxxx') xxxxxx_xxxxx xxxxxx xxxx; " + "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" " + ), + None, + ('xxxxxxxxxxx',), + ), + +xxxxxxx = { 'xx' : 'xxxx xxxxxxx xxxxxxxxx -x xxx -x /xxx/{0} -x xxx,xxx -xx {1} \ +-xx {1} -xx xxx=xxx_xxxx,xxx_xx,xxx_xxx,xxx_xxxx,xxx_xx,xxx_xxx |\ + xxxxxx -x xxxxxxxx -x xxxxxxxx -x', + 'xx' : 'xxxx xxxxxxx xxxxxxxxx -x xxx -x /xxx/{0} -x xxx,xxx -xx {1} \ +-xx {1} -xx xxx=xxx_xxxx_xxx_xxxx,xxx_xx_xxx_xxxx,xxx_xxxx_xxx_xxxx,\ +xxx_xx_xxxx_xxxx,xxx_xxx_xxxx,xxx_xxx_xxxx xxxx=xxx | xxxxxx -x xxxxxxxx -x xxxxxxxx -x' +} + +class A: + def foo(self): + if True: + xxxxx_xxxxxxxxxxxx('xxx xxxxxx xxx xxxxxxxxx.xx xx xxxxxxxx. xxx xxxxxxxxxxxxx.xx xxxxxxx ' + + 'xx xxxxxx xxxxxx xxxxxx xx xxxxxxx xxx xxx ${0} xx x xxxxxxxx xxxxx'.xxxxxx(xxxxxx_xxxxxx_xxx)) + +class A: + class B: + def foo(): + row = { + 'xxxxxxxxxxxxxxx' : xxxxxx_xxxxx_xxxx, + # 'xxxxxxxxxxxxxxxxxxxxxxx' + # 'xxxxxxxxxxxxxxxxxxxxxx' + # 'xxxxxxxxxxxxxxxxxx' + # 'xxxxxxxxxxxxxxxxx' + 'xxxxxxxxxx' : xxxxx_xxxxx, + } + +class A: + def xxxx_xxx_xx_xxxxxxxxxx_xxxx_xxxxxxxxx(xxxx): + xxxxxxxx = [ + xxxxxxxxxxxxxxxx( + 'xxxx', + xxxxxxxxxxx={ + 'xxxx' : 1.0, + }, + xxxxxx={'xxxxxx 1' : xxxxxx(xxxx='xxxxxx 1', xxxxxx=600.0)}, + xxxxxxxx_xxxxxxx=0.0, + ), + xxxxxxxxxxxxxxxx( + 'xxxxxxx', + xxxxxxxxxxx={ + 'xxxx' : 1.0, + }, + xxxxxx={'xxxxxx 1' : xxxxxx(xxxx='xxxxxx 1', xxxxxx=200.0)}, + xxxxxxxx_xxxxxxx=0.0, + ), + xxxxxxxxxxxxxxxx( + 'xxxx', + ), + ] + +some_dictionary = { + 'xxxxx006': ['xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx0xx6xxxxxxxxxx2xxxxxx9xxxxxxxxxx0xxxxx1xxx2x/xx9xx6+x+xxxxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxxxx43xxx2xx2x4x++xxx6xxxxxxxxx+xxxxx/xx9x+xxxxxxxxxxxxxx8x15xxxxxxxxxxxxxxxxx82xx/xxxxxxxxxxxxxx/x5xxxxxxxxxxxxxx6xxxxxx74x4/xxx4x+xxxxxxxxx2xxxxxxxx87xxxxx4xxxxxxxx3xx0xxxxx4xxx1xx9xx5xxxxxxx/xxxxx5xx6xx4xxxx1x/x2xxxxxxxxxxxx64xxxxxxx1x0xx5xxxxxxxxxxxxxx== xxxxx000 xxxxxxxxxx\n', + 'xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx6xxxxxxxxxxxxxx9xxxxxxxxxxxxx3xxx9xxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxxxx2xxxx2xxx6xxxxx/xx54xxxxxxxxx4xxx3xxxxxx9xx3xxxxx39xxxxxxxxx5xx91xxxx7xxxxxx8xxxxxxxxxxxxxxxx9xxx93xxxxxxxxxxxxxxxxx7xxx8xx8xx4/x1xxxxx1x3xxxxxxxxxxxxx3xxxxxx9xx4xx4x7xxxxxxxxxxxxx1xxxxxxxxx7xxxxxxxxxxxxxx4xx6xxxxxxxxx9xxx7xxxx2xxxxxxxxxxxxxxxxxxxxxx8xxxxxxxxxxxxxxxxxxxx6xx== xxxxx010 xxxxxxxxxx\n'], + 'xxxxx016': ['xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx0xx6xxxxxxxxxx2xxxxxx9xxxxxxxxxx0xxxxx1xxx2x/xx9xx6+x+xxxxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxxxx43xxx2xx2x4x++xxx6xxxxxxxxx+xxxxx/xx9x+xxxxxxxxxxxxxx8x15xxxxxxxxxxxxxxxxx82xx/xxxxxxxxxxxxxx/x5xxxxxxxxxxxxxx6xxxxxx74x4/xxx4x+xxxxxxxxx2xxxxxxxx87xxxxx4xxxxxxxx3xx0xxxxx4xxx1xx9xx5xxxxxxx/xxxxx5xx6xx4xxxx1x/x2xxxxxxxxxxxx64xxxxxxx1x0xx5xxxxxxxxxxxxxx== xxxxx000 xxxxxxxxxx\n', + 'xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx6xxxxxxxxxxxxxx9xxxxxxxxxxxxx3xxx9xxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxxxx2xxxx2xxx6xxxxx/xx54xxxxxxxxx4xxx3xxxxxx9xx3xxxxx39xxxxxxxxx5xx91xxxx7xxxxxx8xxxxxxxxxxxxxxxx9xxx93xxxxxxxxxxxxxxxxx7xxx8xx8xx4/x1xxxxx1x3xxxxxxxxxxxxx3xxxxxx9xx4xx4x7xxxxxxxxxxxxx1xxxxxxxxx7xxxxxxxxxxxxxx4xx6xxxxxxxxx9xxx7xxxx2xxxxxxxxxxxxxxxxxxxxxx8xxxxxxxxxxxxxxxxxxxx6xx== xxxxx010 xxxxxxxxxx\n'] +} + +def foo(): + xxx_xxx = ( + 'xxxx xxx xxxxxxxx_xxxx xx "xxxxxxxxxx".' + '\n xxx: xxxxxx xxxxxxxx_xxxx=xxxxxxxxxx' + ) # xxxx xxxxxxxxxx xxxx xx xxxx xx xxx xxxxxxxx xxxxxx xxxxx. + +some_tuple = ("some string", "some string" " which should be joined") + +some_commented_string = ( # This comment stays at the top. + "This string is long but not so long that it needs hahahah toooooo be so greatttt" + " {} that I just can't think of any more good words to say about it at" + " allllllllllll".format("ha") # comments here are fine +) + +some_commented_string = ( + "This string is long but not so long that it needs hahahah toooooo be so greatttt" # But these + " {} that I just can't think of any more good words to say about it at" # comments will stay + " allllllllllll".format("ha") # comments here are fine +) + +lpar_and_rpar_have_comments = func_call( # LPAR Comment + "Long really ridiculous type of string that shouldn't really even exist at all. I mean commmme onnn!!!", # Comma Comment +) # RPAR Comment + +cmd_fstring = ( + f"sudo -E deluge-console info --detailed --sort-reverse=time_added " + f"{'' if ID is None else ID} | perl -nE 'print if /^{field}:/'" +) + +cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {'' if ID is None else ID} | perl -nE 'print if /^{field}:/'" + +cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {'{{}}' if ID is None else ID} | perl -nE 'print if /^{field}:/'" + +cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {{'' if ID is None else ID}} | perl -nE 'print if /^{field}:/'" + +fstring = f"This string really doesn't need to be an {{{{fstring}}}}, but this one most certainly, absolutely {does}." + +fstring = ( + f"We have to remember to escape {braces}." + " Like {these}." + f" But not {this}." +) + +class A: + class B: + def foo(): + st_error = STError( + f"This string ({string_leaf.value}) appears to be pointless (i.e. has" + " no parent)." + ) + +def foo(): + user_regex = _lazy_re_compile( + r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*\Z" # dot-atom + r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"\Z)', # quoted-string + re.IGNORECASE) + +def foo(): + user_regex = _lazy_re_compile( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # dot-atom + 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', # quoted-string + xyz + ) + +def foo(): + user_regex = _lazy_re_compile( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # dot-atom + 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', # quoted-string + xyz + ) + +class A: + class B: + def foo(): + if not hasattr(module, name): + raise ValueError( + "Could not find object %s in %s.\n" + "Please note that you cannot serialize things like inner " + "classes. Please move the object into the main module " + "body to use migrations.\n" + "For more information, see " + "https://docs.djangoproject.com/en/%s/topics/migrations/#serializing-values" + % (name, module_name, get_docs_version())) + +class A: + class B: + def foo(): + if not hasattr(module, name): + raise ValueError( + "Could not find object %s in %s.\nPlease note that you cannot serialize things like inner classes. Please move the object into the main module body to use migrations.\nFor more information, see https://docs.djangoproject.com/en/%s/topics/migrations/#serializing-values" + % (name, module_name, get_docs_version())) + +x = ( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +) + +class Step(StepBase): + def who(self): + self.cmd = 'SR AAAA-CORRECT NAME IS {last_name} {first_name}{middle_name} {title}/P{passenger_association}'.format( + last_name=last_name, + first_name=first_name, + middle_name=middle_name, + title=title, + passenger_association=passenger_association, + ) + +xxxxxxx_xxxxxx_xxxxxxx = xxx( + [ + xxxxxxxxxxxx( + xxxxxx_xxxxxxx=( + '((x.aaaaaaaaa = "xxxxxx.xxxxxxxxxxxxxxxxxxxxx") || (x.xxxxxxxxx = "xxxxxxxxxxxx")) && ' + # xxxxx xxxxxxxxxxxx xxxx xxx (xxxxxxxxxxxxxxxx) xx x xxxxxxxxx xx xxxxxx. + "(x.bbbbbbbbbbbb.xxx != " + '"xxx:xxx:xxx::cccccccccccc:xxxxxxx-xxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxxxx") && ' + ) + ) + ] +) + +if __name__ == "__main__": + for i in range(4, 8): + cmd = ( + r"for pid in $(ps aux | grep paster | grep -v grep | grep '\-%d' | awk '{print $2}'); do kill $pid; done" + % (i) + ) + +def A(): + def B(): + def C(): + def D(): + def E(): + def F(): + def G(): + assert ( + c_float(val[0][0] / val[0][1]).value + == c_float(value[0][0] / value[0][1]).value + ), "%s didn't roundtrip" % tag + +class xxxxxxxxxxxxxxxxxxxxx(xxxx.xxxxxxxxxxxxx): + def xxxxxxx_xxxxxx(xxxx): + assert xxxxxxx_xxxx in [ + x.xxxxx.xxxxxx.xxxxx.xxxxxx, + x.xxxxx.xxxxxx.xxxxx.xxxx, + ], ("xxxxxxxxxxx xxxxxxx xxxx (xxxxxx xxxx) %x xxx xxxxx" % xxxxxxx_xxxx) + +value.__dict__[ + key +] = "test" # set some Thrift field to non-None in the struct aa bb cc dd ee + +RE_ONE_BACKSLASH = { + "asdf_hjkl_jkl": re.compile( + r"(?>\n" +) + +assert str(suffix_arr) == ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) != ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) <= ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) >= ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) < ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) > ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) in "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', 'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', 'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +assert str(suffix_arr) not in "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', 'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', 'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +message = ( + f"1. Go to Google Developers Console and log in with your Google account." + "(https://console.developers.google.com/)" + "2. You should be prompted to create a new project (name does not matter)." + "3. Click on Enable APIs and Services at the top." + "4. In the list of APIs choose or search for YouTube Data API v3 and " + "click on it. Choose Enable." + "5. Click on Credentials on the left navigation bar." + "6. Click on Create Credential at the top." + '7. At the top click the link for "API key".' + "8. No application restrictions are needed. Click Create at the bottom." + "9. You now have a key to add to `{prefix}set api youtube api_key`" +) +message = ( + f"1. Go to Google Developers Console and log in with your Google account." + "(https://console.developers.google.com/)" + "2. You should be prompted to create a new project (name does not matter)." + f"3. Click on Enable APIs and Services at the top." + "4. In the list of APIs choose or search for YouTube Data API v3 and " + "click on it. Choose Enable." + f"5. Click on Credentials on the left navigation bar." + "6. Click on Create Credential at the top." + '7. At the top click the link for "API key".' + "8. No application restrictions are needed. Click Create at the bottom." + "9. You now have a key to add to `{prefix}set api youtube api_key`" +) +message = ( + f"1. Go to Google Developers Console and log in with your Google account." + "(https://console.developers.google.com/)" + "2. You should be prompted to create a new project (name does not matter)." + f"3. Click on Enable APIs and Services at the top." + "4. In the list of APIs choose or search for YouTube Data API v3 and " + "click on it. Choose Enable." + f"5. Click on Credentials on the left navigation bar." + "6. Click on Create Credential at the top." + '7. At the top click the link for "API key".' + "8. No application restrictions are needed. Click Create at the bottom." + f"9. You now have a key to add to `{prefix}set api youtube api_key`" +) + +# It shouldn't matter if the string prefixes are capitalized. +temp_msg = ( + F"{F'{humanize_number(pos)}.': <{pound_len+2}} " + F"{balance: <{bal_len + 5}} " + F"<<{author.display_name}>>\n" +) + +fstring = ( + F"We have to remember to escape {braces}." + " Like {these}." + F" But not {this}." +) + +welcome_to_programming = R"hello," R" world!" + +fstring = F"f-strings definitely make things more {difficult} than they need to be for {{black}}. But boy they sure are handy. The problem is that some lines will need to have the 'f' whereas others do not. This {line}, for example, needs one." + +x = F"This is a long string which contains an f-expr that should not split {{{[i for i in range(5)]}}}." + +x = ( + "\N{BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR}\N{VARIATION SELECTOR-16}" +) + +xxxxxx_xxx_xxxx_xx_xxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxx_xxxx_xxxx_xxxxx = xxxx.xxxxxx.xxxxxxxxx.xxxxxxxxxxxxxxxxxxxx( + xx_xxxxxx={ + "x3_xxxxxxxx": "xxx3_xxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxx_xxxxxxxx_xxxxxx_xxxxxxx", + }, +) + +# Regression test for https://github.com/psf/black/issues/3117. +some_dict = { + "something_something": + r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t" + r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t", +} + +# Regression test for https://github.com/psf/black/issues/3459. +xxxx( + empty_str_as_first_split='' + f'xxxxxxx {xxxxxxxxxx} xxx xxxxxxxxxx xxxxx xxx xxx xx ' + 'xxxxx xxxxxxxxx xxxxxxx, xxx xxxxxxxxxxx xxx xxxxx. ' + f'xxxxxxxxxxxxx xxxx xx xxxxxxxxxx. xxxxx: {x.xxx}', + empty_u_str_as_first_split=u'' + f'xxxxxxx {xxxxxxxxxx} xxx xxxxxxxxxx xxxxx xxx xxx xx ' + 'xxxxx xxxxxxxxx xxxxxxx, xxx xxxxxxxxxxx xxx xxxxx. ' + f'xxxxxxxxxxxxx xxxx xx xxxxxxxxxx. xxxxx: {x.xxx}', +) + +# Regression test for https://github.com/psf/black/issues/3455. +a_dict = { + "/this/is/a/very/very/very/very/very/very/very/very/very/very/long/key/without/spaces": + # And there is a comment before the value + ("item1", "item2", "item3"), +} + +# Regression test for https://github.com/psf/black/issues/3506. +s = ( + "With single quote: ' " + f" {my_dict['foo']}" + ' With double quote: " ' + f' {my_dict["bar"]}' +) + +s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry:\'{my_dict["foo"]}\'' diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__regression.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__regression.py.expect new file mode 100644 index 0000000000000..15c91275afcae --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__regression.py.expect @@ -0,0 +1,680 @@ +class A: + def foo(): + result = type(message)("") + + +# Don't merge multiline (e.g. triple-quoted) strings. +def foo(): + query = ( + """SELECT xxxxxxxxxxxxxxxxxxxx(xxx)""" + """ FROM xxxxxxxxxxxxxxxx WHERE xxxxxxxxxx AND xxx <> xxxxxxxxxxxxxx()""" + ) + + +# There was a bug where tuples were being identified as long strings. +long_tuple = ( + "Apple", + "Berry", + "Cherry", + "Dill", + "Evergreen", + "Fig", + "Grape", + "Harry", + "Iglu", + "Jaguar", +) + +stupid_format_method_bug = ( + "Some really long string that just so happens to be the {} {} to force the 'format'" + " method to hang over the line length boundary. This is pretty annoying.".format( + "perfect", "length" + ) +) + + +class A: + def foo(): + os.system( + "This is a regression test. xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx" + " xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx" + " xxxx.".format("xxxxxxxxxx", "xxxxxx", "xxxxxxxxxx") + ) + + +class A: + def foo(): + XXXXXXXXXXXX.append(( + "xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx, xxxx_xxxx_xxxxxxxxxx={})".format( + xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx + ), + my_var, + my_other_var, + )) + + +class A: + class B: + def foo(): + bar( + "[{}]: xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx={}" + " xxxx_xxxx_xxxxxxxxxx={}, xxxx={})".format( + xxxx._xxxxxxxxxxxxxx, xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx, xxxxxxx + ), + varX, + varY, + varZ, + ) + + +def foo(xxxx): + for xxx_xxxx, _xxx_xxx, _xxx_xxxxx, xxx_xxxx in xxxx: + for xxx in xxx_xxxx: + assert ("x" in xxx) or (xxx in xxx_xxx_xxxxx), ( + "{0} xxxxxxx xx {1}, xxx {1} xx xxx xx xxxx xx xxx xxxx: xxx xxxx {2}" + .format(xxx_xxxx, xxx, xxxxxx.xxxxxxx(xxx_xxx_xxxxx)) + ) + + +class A: + def disappearing_comment(): + return ( + ( # xx -x xxxxxxx xx xxx xxxxxxx. + "{{xxx_xxxxxxxxxx_xxxxxxxx}} xxx xxxx {} {{xxxx}} >&2".format( + "{xxxx} {xxxxxx}" + if xxxxx.xx_xxxxxxxxxx + else ( # Disappearing Comment + "--xxxxxxx --xxxxxx=x --xxxxxx-xxxxx=xxxxxx" + " --xxxxxx-xxxx=xxxxxxxxxxx.xxx" + ) + ) + ), + (x, y, z), + ) + + +class A: + class B: + def foo(): + xxxxx_xxxx( + xx, + "\t" + "@xxxxxx '{xxxx_xxx}\t' > {xxxxxx_xxxx}.xxxxxxx;" + "{xxxx_xxx} >> {xxxxxx_xxxx}.xxxxxxx 2>&1; xx=$$?;" + "xxxx $$xx".format( + xxxx_xxx=xxxx_xxxxxxx, + xxxxxx_xxxx=xxxxxxx + "/" + xxxx_xxx_xxxx, + x=xxx_xxxxx_xxxxx_xxx, + ), + x, + y, + z, + ) + + +func_call_where_string_arg_has_method_call_and_bad_parens( + "A long string with {}. This string is so long that it is ridiculous. It can't fit" + " on one line at alllll.".format("formatting"), +) + +func_call_where_string_arg_has_old_fmt_and_bad_parens( + "A long string with {}. This string is so long that it is ridiculous. It can't fit" + " on one line at alllll." % "formatting", +) + +func_call_where_string_arg_has_old_fmt_and_bad_parens( + "A long string with {}. This {} is so long that it is ridiculous. It can't fit on" + " one line at alllll." % ("formatting", "string"), +) + + +class A: + def append(self): + if True: + xxxx.xxxxxxx.xxxxx( + "xxxxxxxxxx xxxx xx xxxxxx(%x) xx %x xxxx xx xxx %x.xx" + % (len(self) + 1, xxxx.xxxxxxxxxx, xxxx.xxxxxxxxxx) + + " %.3f (%s) to %.3f (%s).\n" + % ( + xxxx.xxxxxxxxx, + xxxx.xxxxxxxxxxxxxx(xxxx.xxxxxxxxx), + x, + xxxx.xxxxxxxxxxxxxx(xx), + ) + ) + + +class A: + def foo(): + some_func_call( + "xxxxxxxxxx", + "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " + '"xxxx xxxxxxx xxxxxx xxxx; xxxx xxxxxx_xxxxx xxxxxx xxxx; ' + "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" ", + None, + ("xxxxxxxxxxx",), + ), + + +class A: + def foo(): + some_func_call( + "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " + "xxxx, ('xxxxxxx xxxxxx xxxx, xxxx') xxxxxx_xxxxx xxxxxx xxxx; " + "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" ", + None, + ("xxxxxxxxxxx",), + ), + + +xxxxxxx = { + "xx": ( + "xxxx xxxxxxx xxxxxxxxx -x xxx -x /xxx/{0} -x xxx,xxx -xx {1} -xx {1} -xx" + " xxx=xxx_xxxx,xxx_xx,xxx_xxx,xxx_xxxx,xxx_xx,xxx_xxx | xxxxxx -x xxxxxxxx -x" + " xxxxxxxx -x" + ), + "xx": ( + "xxxx xxxxxxx xxxxxxxxx -x xxx -x /xxx/{0} -x xxx,xxx -xx {1} -xx {1} -xx" + " xxx=xxx_xxxx_xxx_xxxx,xxx_xx_xxx_xxxx,xxx_xxxx_xxx_xxxx,xxx_xx_xxxx_xxxx,xxx_xxx_xxxx,xxx_xxx_xxxx" + " xxxx=xxx | xxxxxx -x xxxxxxxx -x xxxxxxxx -x" + ), +} + + +class A: + def foo(self): + if True: + xxxxx_xxxxxxxxxxxx( + "xxx xxxxxx xxx xxxxxxxxx.xx xx xxxxxxxx. xxx xxxxxxxxxxxxx.xx" + " xxxxxxx " + + "xx xxxxxx xxxxxx xxxxxx xx xxxxxxx xxx xxx ${0} xx x xxxxxxxx xxxxx" + .xxxxxx(xxxxxx_xxxxxx_xxx) + ) + + +class A: + class B: + def foo(): + row = { + "xxxxxxxxxxxxxxx": xxxxxx_xxxxx_xxxx, + # 'xxxxxxxxxxxxxxxxxxxxxxx' + # 'xxxxxxxxxxxxxxxxxxxxxx' + # 'xxxxxxxxxxxxxxxxxx' + # 'xxxxxxxxxxxxxxxxx' + "xxxxxxxxxx": xxxxx_xxxxx, + } + + +class A: + def xxxx_xxx_xx_xxxxxxxxxx_xxxx_xxxxxxxxx(xxxx): + xxxxxxxx = [ + xxxxxxxxxxxxxxxx( + "xxxx", + xxxxxxxxxxx={ + "xxxx": 1.0, + }, + xxxxxx={"xxxxxx 1": xxxxxx(xxxx="xxxxxx 1", xxxxxx=600.0)}, + xxxxxxxx_xxxxxxx=0.0, + ), + xxxxxxxxxxxxxxxx( + "xxxxxxx", + xxxxxxxxxxx={ + "xxxx": 1.0, + }, + xxxxxx={"xxxxxx 1": xxxxxx(xxxx="xxxxxx 1", xxxxxx=200.0)}, + xxxxxxxx_xxxxxxx=0.0, + ), + xxxxxxxxxxxxxxxx( + "xxxx", + ), + ] + + +some_dictionary = { + "xxxxx006": [ + ( + "xxx-xxx" + " xxxxx3xxxx1xx2xxxxxxxxxxxxxx0xx6xxxxxxxxxx2xxxxxx9xxxxxxxxxx0xxxxx1xxx2x/xx9xx6+x+xxxxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxxxx43xxx2xx2x4x++xxx6xxxxxxxxx+xxxxx/xx9x+xxxxxxxxxxxxxx8x15xxxxxxxxxxxxxxxxx82xx/xxxxxxxxxxxxxx/x5xxxxxxxxxxxxxx6xxxxxx74x4/xxx4x+xxxxxxxxx2xxxxxxxx87xxxxx4xxxxxxxx3xx0xxxxx4xxx1xx9xx5xxxxxxx/xxxxx5xx6xx4xxxx1x/x2xxxxxxxxxxxx64xxxxxxx1x0xx5xxxxxxxxxxxxxx==" + " xxxxx000 xxxxxxxxxx\n" + ), + ( + "xxx-xxx" + " xxxxx3xxxx1xx2xxxxxxxxxxxxxx6xxxxxxxxxxxxxx9xxxxxxxxxxxxx3xxx9xxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxxxx2xxxx2xxx6xxxxx/xx54xxxxxxxxx4xxx3xxxxxx9xx3xxxxx39xxxxxxxxx5xx91xxxx7xxxxxx8xxxxxxxxxxxxxxxx9xxx93xxxxxxxxxxxxxxxxx7xxx8xx8xx4/x1xxxxx1x3xxxxxxxxxxxxx3xxxxxx9xx4xx4x7xxxxxxxxxxxxx1xxxxxxxxx7xxxxxxxxxxxxxx4xx6xxxxxxxxx9xxx7xxxx2xxxxxxxxxxxxxxxxxxxxxx8xxxxxxxxxxxxxxxxxxxx6xx==" + " xxxxx010 xxxxxxxxxx\n" + ), + ], + "xxxxx016": [ + ( + "xxx-xxx" + " xxxxx3xxxx1xx2xxxxxxxxxxxxxx0xx6xxxxxxxxxx2xxxxxx9xxxxxxxxxx0xxxxx1xxx2x/xx9xx6+x+xxxxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxxxx43xxx2xx2x4x++xxx6xxxxxxxxx+xxxxx/xx9x+xxxxxxxxxxxxxx8x15xxxxxxxxxxxxxxxxx82xx/xxxxxxxxxxxxxx/x5xxxxxxxxxxxxxx6xxxxxx74x4/xxx4x+xxxxxxxxx2xxxxxxxx87xxxxx4xxxxxxxx3xx0xxxxx4xxx1xx9xx5xxxxxxx/xxxxx5xx6xx4xxxx1x/x2xxxxxxxxxxxx64xxxxxxx1x0xx5xxxxxxxxxxxxxx==" + " xxxxx000 xxxxxxxxxx\n" + ), + ( + "xxx-xxx" + " xxxxx3xxxx1xx2xxxxxxxxxxxxxx6xxxxxxxxxxxxxx9xxxxxxxxxxxxx3xxx9xxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxxxx2xxxx2xxx6xxxxx/xx54xxxxxxxxx4xxx3xxxxxx9xx3xxxxx39xxxxxxxxx5xx91xxxx7xxxxxx8xxxxxxxxxxxxxxxx9xxx93xxxxxxxxxxxxxxxxx7xxx8xx8xx4/x1xxxxx1x3xxxxxxxxxxxxx3xxxxxx9xx4xx4x7xxxxxxxxxxxxx1xxxxxxxxx7xxxxxxxxxxxxxx4xx6xxxxxxxxx9xxx7xxxx2xxxxxxxxxxxxxxxxxxxxxx8xxxxxxxxxxxxxxxxxxxx6xx==" + " xxxxx010 xxxxxxxxxx\n" + ), + ], +} + + +def foo(): + xxx_xxx = ( # xxxx xxxxxxxxxx xxxx xx xxxx xx xxx xxxxxxxx xxxxxx xxxxx. + 'xxxx xxx xxxxxxxx_xxxx xx "xxxxxxxxxx".\n xxx: xxxxxx xxxxxxxx_xxxx=xxxxxxxxxx' + ) + + +some_tuple = ("some string", "some string which should be joined") + +some_commented_string = ( # This comment stays at the top. + "This string is long but not so long that it needs hahahah toooooo be so greatttt" + " {} that I just can't think of any more good words to say about it at" + " allllllllllll".format("ha") # comments here are fine +) + +some_commented_string = ( + "This string is long but not so long that it needs hahahah toooooo be so greatttt" # But these + " {} that I just can't think of any more good words to say about it at" # comments will stay + " allllllllllll".format("ha") # comments here are fine +) + +lpar_and_rpar_have_comments = func_call( # LPAR Comment + "Long really ridiculous type of string that shouldn't really even exist at all. I" + " mean commmme onnn!!!", # Comma Comment +) # RPAR Comment + +cmd_fstring = ( + "sudo -E deluge-console info --detailed --sort-reverse=time_added " + f"{'' if ID is None else ID} | perl -nE 'print if /^{field}:/'" +) + +cmd_fstring = ( + "sudo -E deluge-console info --detailed --sort-reverse=time_added" + f" {'' if ID is None else ID} | perl -nE 'print if /^{field}:/'" +) + +cmd_fstring = ( + "sudo -E deluge-console info --detailed --sort-reverse=time_added" + f" {'{{}}' if ID is None else ID} | perl -nE 'print if /^{field}:/'" +) + +cmd_fstring = ( + "sudo -E deluge-console info --detailed --sort-reverse=time_added {'' if ID is" + f" None else ID}} | perl -nE 'print if /^{field}:/'" +) + +fstring = ( + "This string really doesn't need to be an {{fstring}}, but this one most" + f" certainly, absolutely {does}." +) + +fstring = f"We have to remember to escape {braces}. Like {{these}}. But not {this}." + + +class A: + class B: + def foo(): + st_error = STError( + f"This string ({string_leaf.value}) appears to be pointless (i.e. has" + " no parent)." + ) + + +def foo(): + user_regex = _lazy_re_compile( + r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*\Z" # dot-atom + r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"\Z)', # quoted-string + re.IGNORECASE, + ) + + +def foo(): + user_regex = _lazy_re_compile( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # dot-atom + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", # quoted-string + xyz, + ) + + +def foo(): + user_regex = _lazy_re_compile( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # dot-atom + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", # quoted-string + xyz, + ) + + +class A: + class B: + def foo(): + if not hasattr(module, name): + raise ValueError( + "Could not find object %s in %s.\n" + "Please note that you cannot serialize things like inner " + "classes. Please move the object into the main module " + "body to use migrations.\n" + "For more information, see " + "https://docs.djangoproject.com/en/%s/topics/migrations/#serializing-values" + % (name, module_name, get_docs_version()) + ) + + +class A: + class B: + def foo(): + if not hasattr(module, name): + raise ValueError( + "Could not find object %s in %s.\nPlease note that you cannot" + " serialize things like inner classes. Please move the object into" + " the main module body to use migrations.\nFor more information," + " see https://docs.djangoproject.com/en/%s/topics/migrations/#serializing-values" + % (name, module_name, get_docs_version()) + ) + + +x = ( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +) + + +class Step(StepBase): + def who(self): + self.cmd = ( + "SR AAAA-CORRECT NAME IS {last_name} {first_name}{middle_name}" + " {title}/P{passenger_association}".format( + last_name=last_name, + first_name=first_name, + middle_name=middle_name, + title=title, + passenger_association=passenger_association, + ) + ) + + +xxxxxxx_xxxxxx_xxxxxxx = xxx([ + xxxxxxxxxxxx( + xxxxxx_xxxxxxx=( + '((x.aaaaaaaaa = "xxxxxx.xxxxxxxxxxxxxxxxxxxxx") || (x.xxxxxxxxx =' + ' "xxxxxxxxxxxx")) && ' + # xxxxx xxxxxxxxxxxx xxxx xxx (xxxxxxxxxxxxxxxx) xx x xxxxxxxxx xx xxxxxx. + "(x.bbbbbbbbbbbb.xxx != " + '"xxx:xxx:xxx::cccccccccccc:xxxxxxx-xxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxxxx") && ' + ) + ) +]) + +if __name__ == "__main__": + for i in range(4, 8): + cmd = ( + r"for pid in $(ps aux | grep paster | grep -v grep | grep '\-%d' | awk" + r" '{print $2}'); do kill $pid; done" % (i) + ) + + +def A(): + def B(): + def C(): + def D(): + def E(): + def F(): + def G(): + assert ( + c_float(val[0][0] / val[0][1]).value + == c_float(value[0][0] / value[0][1]).value + ), "%s didn't roundtrip" % tag + + +class xxxxxxxxxxxxxxxxxxxxx(xxxx.xxxxxxxxxxxxx): + def xxxxxxx_xxxxxx(xxxx): + assert xxxxxxx_xxxx in [ + x.xxxxx.xxxxxx.xxxxx.xxxxxx, + x.xxxxx.xxxxxx.xxxxx.xxxx, + ], ( + "xxxxxxxxxxx xxxxxxx xxxx (xxxxxx xxxx) %x xxx xxxxx" % xxxxxxx_xxxx + ) + + +value.__dict__[key] = ( + "test" # set some Thrift field to non-None in the struct aa bb cc dd ee +) + +RE_ONE_BACKSLASH = { + "asdf_hjkl_jkl": re.compile( + r"(?>\n" +) + +assert ( + str(suffix_arr) + == "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert ( + str(suffix_arr) + != "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert ( + str(suffix_arr) + <= "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert ( + str(suffix_arr) + >= "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert ( + str(suffix_arr) + < "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert ( + str(suffix_arr) + > "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert ( + str(suffix_arr) + in "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', 'grykangaroo$'," + " 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', 'o$', 'oo$', 'roo$', 'rykangaroo$'," + " 'ykangaroo$']" +) +assert ( + str(suffix_arr) + not in "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', 'grykangaroo$'," + " 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', 'o$', 'oo$', 'roo$'," + " 'rykangaroo$', 'ykangaroo$']" +) +message = ( + f"1. Go to Google Developers Console and log in with your Google account." + f"(https://console.developers.google.com/)" + f"2. You should be prompted to create a new project (name does not matter)." + f"3. Click on Enable APIs and Services at the top." + f"4. In the list of APIs choose or search for YouTube Data API v3 and " + f"click on it. Choose Enable." + f"5. Click on Credentials on the left navigation bar." + f"6. Click on Create Credential at the top." + f'7. At the top click the link for "API key".' + f"8. No application restrictions are needed. Click Create at the bottom." + f"9. You now have a key to add to `{{prefix}}set api youtube api_key`" +) +message = ( + f"1. Go to Google Developers Console and log in with your Google account." + f"(https://console.developers.google.com/)" + f"2. You should be prompted to create a new project (name does not matter)." + f"3. Click on Enable APIs and Services at the top." + f"4. In the list of APIs choose or search for YouTube Data API v3 and " + f"click on it. Choose Enable." + f"5. Click on Credentials on the left navigation bar." + f"6. Click on Create Credential at the top." + f'7. At the top click the link for "API key".' + f"8. No application restrictions are needed. Click Create at the bottom." + f"9. You now have a key to add to `{{prefix}}set api youtube api_key`" +) +message = ( + "1. Go to Google Developers Console and log in with your Google account." + "(https://console.developers.google.com/)" + "2. You should be prompted to create a new project (name does not matter)." + "3. Click on Enable APIs and Services at the top." + "4. In the list of APIs choose or search for YouTube Data API v3 and " + "click on it. Choose Enable." + "5. Click on Credentials on the left navigation bar." + "6. Click on Create Credential at the top." + '7. At the top click the link for "API key".' + "8. No application restrictions are needed. Click Create at the bottom." + f"9. You now have a key to add to `{prefix}set api youtube api_key`" +) + +# It shouldn't matter if the string prefixes are capitalized. +temp_msg = ( + f"{F'{humanize_number(pos)}.': <{pound_len+2}} " + f"{balance: <{bal_len + 5}} " + f"<<{author.display_name}>>\n" +) + +fstring = f"We have to remember to escape {braces}. Like {{these}}. But not {this}." + +welcome_to_programming = R"hello," R" world!" + +fstring = ( + f"f-strings definitely make things more {difficult} than they need to be for" + " {black}. But boy they sure are handy. The problem is that some lines will need" + f" to have the 'f' whereas others do not. This {line}, for example, needs one." +) + +x = ( + "This is a long string which contains an f-expr that should not split" + f" {{{[i for i in range(5)]}}}." +) + +x = ( + "\N{BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR}\N{VARIATION SELECTOR-16}" +) + +xxxxxx_xxx_xxxx_xx_xxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxx_xxxx_xxxx_xxxxx = xxxx.xxxxxx.xxxxxxxxx.xxxxxxxxxxxxxxxxxxxx( + xx_xxxxxx={ + "x3_xxxxxxxx": ( + "xxx3_xxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxx_xxxxxxxx_xxxxxx_xxxxxxx" + ), + }, +) + +# Regression test for https://github.com/psf/black/issues/3117. +some_dict = { + "something_something": ( + r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t" + r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t" + ), +} + +# Regression test for https://github.com/psf/black/issues/3459. +xxxx( + empty_str_as_first_split=( + "" + f"xxxxxxx {xxxxxxxxxx} xxx xxxxxxxxxx xxxxx xxx xxx xx " + "xxxxx xxxxxxxxx xxxxxxx, xxx xxxxxxxxxxx xxx xxxxx. " + f"xxxxxxxxxxxxx xxxx xx xxxxxxxxxx. xxxxx: {x.xxx}" + ), + empty_u_str_as_first_split=( + "" + f"xxxxxxx {xxxxxxxxxx} xxx xxxxxxxxxx xxxxx xxx xxx xx " + "xxxxx xxxxxxxxx xxxxxxx, xxx xxxxxxxxxxx xxx xxxxx. " + f"xxxxxxxxxxxxx xxxx xx xxxxxxxxxx. xxxxx: {x.xxx}" + ), +) + +# Regression test for https://github.com/psf/black/issues/3455. +a_dict = { + "/this/is/a/very/very/very/very/very/very/very/very/very/very/long/key/without/spaces": + # And there is a comment before the value + ("item1", "item2", "item3"), +} + +# Regression test for https://github.com/psf/black/issues/3506. +s = f"With single quote: ' {my_dict['foo']} With double quote: \" {my_dict['bar']}" + +s = ( + "Lorem Ipsum is simply dummy text of the printing and typesetting" + f" industry:'{my_dict['foo']}'" +) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__type_annotations.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__type_annotations.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__type_annotations.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__type_annotations.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__type_annotations.py new file mode 100644 index 0000000000000..4907fec71c454 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__type_annotations.py @@ -0,0 +1,28 @@ +def func( + arg1, + arg2, +) -> Set["this_is_a_very_long_module_name.AndAVeryLongClasName" + ".WithAVeryVeryVeryVeryVeryLongSubClassName"]: + pass + + +def func( + argument: ( + "VeryLongClassNameWithAwkwardGenericSubtype[int] |" + "VeryLongClassNameWithAwkwardGenericSubtype[str]" + ), +) -> ( + "VeryLongClassNameWithAwkwardGenericSubtype[int] |" + "VeryLongClassNameWithAwkwardGenericSubtype[str]" +): + pass + + +def func( + argument: ( + "int |" + "str" + ), +) -> Set["int |" + " str"]: + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__type_annotations.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__type_annotations.py.expect new file mode 100644 index 0000000000000..679df21eedbff --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__type_annotations.py.expect @@ -0,0 +1,26 @@ +def func( + arg1, + arg2, +) -> Set[ + "this_is_a_very_long_module_name.AndAVeryLongClasName" + ".WithAVeryVeryVeryVeryVeryLongSubClassName" +]: + pass + + +def func( + argument: ( + "VeryLongClassNameWithAwkwardGenericSubtype[int] |" + "VeryLongClassNameWithAwkwardGenericSubtype[str]" + ), +) -> ( + "VeryLongClassNameWithAwkwardGenericSubtype[int] |" + "VeryLongClassNameWithAwkwardGenericSubtype[str]" +): + pass + + +def func( + argument: "int |" "str", +) -> Set["int |" " str"]: + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_multiline_strings.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_multiline_strings.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_multiline_strings.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_multiline_strings.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_multiline_strings.py new file mode 100644 index 0000000000000..717f7b52e80b2 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_multiline_strings.py @@ -0,0 +1,175 @@ +"""cow +say""", +call(3, "dogsay", textwrap.dedent("""dove + coo""" % "cowabunga")) +call(3, "dogsay", textwrap.dedent("""dove +coo""" % "cowabunga")) +call(3, textwrap.dedent("""cow + moo""" % "cowabunga"), "dogsay") +call(3, "dogsay", textwrap.dedent("""crow + caw""" % "cowabunga"),) +call(3, textwrap.dedent("""cat + meow""" % "cowabunga"), {"dog", "say"}) +call(3, {"dog", "say"}, textwrap.dedent("""horse + neigh""" % "cowabunga")) +call(3, {"dog", "say"}, textwrap.dedent("""pig + oink""" % "cowabunga"),) +textwrap.dedent("""A one-line triple-quoted string.""") +textwrap.dedent("""A two-line triple-quoted string +since it goes to the next line.""") +textwrap.dedent("""A three-line triple-quoted string +that not only goes to the next line +but also goes one line beyond.""") +textwrap.dedent("""\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. file contents. +""") +path.write_text(textwrap.dedent("""\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. file contents. +""")) +path.write_text(textwrap.dedent("""\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. {config_filename} file contents. +""".format("config_filename", config_filename))) +# Another use case +data = yaml.load("""\ +a: 1 +b: 2 +""") +data = yaml.load("""\ +a: 1 +b: 2 +""",) +data = yaml.load( + """\ + a: 1 + b: 2 +""" +) + +MULTILINE = """ +foo +""".replace("\n", "") +generated_readme = lambda project_name: """ +{} + + +""".strip().format(project_name) +parser.usage += """ +Custom extra help summary. + +Extra test: +- with +- bullets +""" + + +def get_stuff(cr, value): + # original + cr.execute(""" + SELECT whatever + FROM some_table t + WHERE id = %s + """, [value]) + return cr.fetchone() + + +def get_stuff(cr, value): + # preferred + cr.execute( + """ + SELECT whatever + FROM some_table t + WHERE id = %s + """, + [value], + ) + return cr.fetchone() + + +call(arg1, arg2, """ +short +""", arg3=True) +test_vectors = [ + "one-liner\n", + "two\nliner\n", + """expressed +as a three line +mulitline string""", +] + +_wat = re.compile( + r""" + regex + """, + re.MULTILINE | re.VERBOSE, +) +dis_c_instance_method = """\ +%3d 0 LOAD_FAST 1 (x) + 2 LOAD_CONST 1 (1) + 4 COMPARE_OP 2 (==) + 6 LOAD_FAST 0 (self) + 8 STORE_ATTR 0 (x) + 10 LOAD_CONST 0 (None) + 12 RETURN_VALUE +""" % (_C.__init__.__code__.co_firstlineno + 1,) +path.write_text(textwrap.dedent("""\ + A triple-quoted string + actually {verb} the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. {file_type} file contents. +""".format(verb="using", file_type="test"))) +{"""cow +moos"""} +["""cow +moos"""] +["""cow +moos""", """dog +woofs +and +barks"""] +def dastardly_default_value( + cow: String = json.loads("""this +is +quite +the +dastadardly +value!"""), + **kwargs, +): + pass + +print(f""" + This {animal} + moos and barks +{animal} say +""") +msg = f"""The arguments {bad_arguments} were passed in. +Please use `--build-option` instead, +`--global-option` is reserved to flags like `--verbose` or `--quiet`. +""" + +this_will_become_one_line = ( + "a" + "b" + "c" +) + +this_will_stay_on_three_lines = ( + "a" # comment + "b" + "c" +) + +this_will_also_become_one_line = ( # comment + "a" + "b" + "c" +) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_multiline_strings.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_multiline_strings.py.expect new file mode 100644 index 0000000000000..3983178da9bf8 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_multiline_strings.py.expect @@ -0,0 +1,209 @@ +"""cow +say""", +call( + 3, + "dogsay", + textwrap.dedent("""dove + coo""" % "cowabunga"), +) +call( + 3, + "dogsay", + textwrap.dedent("""dove +coo""" % "cowabunga"), +) +call( + 3, + textwrap.dedent("""cow + moo""" % "cowabunga"), + "dogsay", +) +call( + 3, + "dogsay", + textwrap.dedent("""crow + caw""" % "cowabunga"), +) +call( + 3, + textwrap.dedent("""cat + meow""" % "cowabunga"), + {"dog", "say"}, +) +call( + 3, + {"dog", "say"}, + textwrap.dedent("""horse + neigh""" % "cowabunga"), +) +call( + 3, + {"dog", "say"}, + textwrap.dedent("""pig + oink""" % "cowabunga"), +) +textwrap.dedent("""A one-line triple-quoted string.""") +textwrap.dedent("""A two-line triple-quoted string +since it goes to the next line.""") +textwrap.dedent("""A three-line triple-quoted string +that not only goes to the next line +but also goes one line beyond.""") +textwrap.dedent("""\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. file contents. +""") +path.write_text(textwrap.dedent("""\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. file contents. +""")) +path.write_text(textwrap.dedent("""\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. {config_filename} file contents. +""".format("config_filename", config_filename))) +# Another use case +data = yaml.load("""\ +a: 1 +b: 2 +""") +data = yaml.load( + """\ +a: 1 +b: 2 +""", +) +data = yaml.load("""\ + a: 1 + b: 2 +""") + +MULTILINE = """ +foo +""".replace("\n", "") +generated_readme = lambda project_name: """ +{} + + +""".strip().format(project_name) +parser.usage += """ +Custom extra help summary. + +Extra test: +- with +- bullets +""" + + +def get_stuff(cr, value): + # original + cr.execute( + """ + SELECT whatever + FROM some_table t + WHERE id = %s + """, + [value], + ) + return cr.fetchone() + + +def get_stuff(cr, value): + # preferred + cr.execute( + """ + SELECT whatever + FROM some_table t + WHERE id = %s + """, + [value], + ) + return cr.fetchone() + + +call( + arg1, + arg2, + """ +short +""", + arg3=True, +) +test_vectors = [ + "one-liner\n", + "two\nliner\n", + """expressed +as a three line +mulitline string""", +] + +_wat = re.compile( + r""" + regex + """, + re.MULTILINE | re.VERBOSE, +) +dis_c_instance_method = """\ +%3d 0 LOAD_FAST 1 (x) + 2 LOAD_CONST 1 (1) + 4 COMPARE_OP 2 (==) + 6 LOAD_FAST 0 (self) + 8 STORE_ATTR 0 (x) + 10 LOAD_CONST 0 (None) + 12 RETURN_VALUE +""" % (_C.__init__.__code__.co_firstlineno + 1,) +path.write_text(textwrap.dedent("""\ + A triple-quoted string + actually {verb} the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. {file_type} file contents. +""".format(verb="using", file_type="test"))) +{"""cow +moos"""} +["""cow +moos"""] +[ + """cow +moos""", + """dog +woofs +and +barks""", +] + + +def dastardly_default_value( + cow: String = json.loads("""this +is +quite +the +dastadardly +value!"""), + **kwargs, +): + pass + + +print(f""" + This {animal} + moos and barks +{animal} say +""") +msg = f"""The arguments {bad_arguments} were passed in. +Please use `--build-option` instead, +`--global-option` is reserved to flags like `--verbose` or `--quiet`. +""" + +this_will_become_one_line = "abc" + +this_will_stay_on_three_lines = ( + "a" # comment + "b" + "c" +) + +this_will_also_become_one_line = "abc" # comment diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_no_blank_line_before_docstring.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_no_blank_line_before_docstring.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_no_blank_line_before_docstring.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_no_blank_line_before_docstring.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_no_blank_line_before_docstring.py new file mode 100644 index 0000000000000..43ba2bd20233a --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_no_blank_line_before_docstring.py @@ -0,0 +1,29 @@ +def line_before_docstring(): + + """Please move me up""" + + +class LineBeforeDocstring: + + """Please move me up""" + + +class EvenIfThereIsAMethodAfter: + + """I'm the docstring""" + def method(self): + pass + + +class TwoLinesBeforeDocstring: + + + """I want to be treated the same as if I were closer""" + + +class MultilineDocstringsAsWell: + + """I'm so far + + and on so many lines... + """ diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_no_blank_line_before_docstring.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_no_blank_line_before_docstring.py.expect new file mode 100644 index 0000000000000..78604d9c9247a --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_no_blank_line_before_docstring.py.expect @@ -0,0 +1,24 @@ +def line_before_docstring(): + """Please move me up""" + + +class LineBeforeDocstring: + """Please move me up""" + + +class EvenIfThereIsAMethodAfter: + """I'm the docstring""" + + def method(self): + pass + + +class TwoLinesBeforeDocstring: + """I want to be treated the same as if I were closer""" + + +class MultilineDocstringsAsWell: + """I'm so far + + and on so many lines... + """ diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_long.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_long.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_long.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_long.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_long.py new file mode 100644 index 0000000000000..98b6ac56a2048 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_long.py @@ -0,0 +1,7 @@ +match x: + case "abcd" | "abcd" | "abcd" : + pass + case "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd": + pass + case xxxxxxxxxxxxxxxxxxxxxxx: + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_long.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_long.py.expect new file mode 100644 index 0000000000000..c60e5770a7a41 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_long.py.expect @@ -0,0 +1,23 @@ +match x: + case "abcd" | "abcd" | "abcd": + pass + case ( + "abcd" + | "abcd" + | "abcd" + | "abcd" + | "abcd" + | "abcd" + | "abcd" + | "abcd" + | "abcd" + | "abcd" + | "abcd" + | "abcd" + | "abcd" + | "abcd" + | "abcd" + ): + pass + case xxxxxxxxxxxxxxxxxxxxxxx: + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_trailing_comma.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_trailing_comma.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_trailing_comma.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_trailing_comma.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_trailing_comma.py new file mode 100644 index 0000000000000..002ceea330686 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_trailing_comma.py @@ -0,0 +1,14 @@ +match maybe, multiple: + case perhaps, 5: + pass + case perhaps, 6,: + pass + + +match more := (than, one), indeed,: + case _, (5, 6): + pass + case [[5], (6)], [7],: + pass + case _: + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_trailing_comma.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_trailing_comma.py.expect new file mode 100644 index 0000000000000..6e8ef32f18157 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_trailing_comma.py.expect @@ -0,0 +1,20 @@ +match maybe, multiple: + case perhaps, 5: + pass + case ( + perhaps, + 6, + ): + pass + + +match more := (than, one), indeed,: + case _, (5, 6): + pass + case ( + [[5], (6)], + [7], + ): + pass + case _: + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep_572.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep_572.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep_572.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep_572.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep_572.py new file mode 100644 index 0000000000000..dff98530388cf --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep_572.py @@ -0,0 +1,2 @@ +x[(a:=0):] +x[:(a:=0)] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep_572.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep_572.py.expect new file mode 100644 index 0000000000000..0ae5b9769d12c --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep_572.py.expect @@ -0,0 +1,2 @@ +x[(a := 0):] +x[:(a := 0)] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_percent_precedence.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_percent_precedence.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_percent_precedence.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_percent_precedence.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_percent_precedence.py new file mode 100644 index 0000000000000..ab71177d2e1d7 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_percent_precedence.py @@ -0,0 +1,20 @@ +("" % a) ** 2 +("" % a)[0] +("" % a)() +("" % a).b + +2 * ("" % a) +2 @ ("" % a) +2 / ("" % a) +2 // ("" % a) +2 % ("" % a) ++("" % a) +b + ("" % a) +-("" % a) +b - ("" % a) +b + -("" % a) +~("" % a) +2 ** ("" % a) +await ("" % a) +b[("" % a)] +b(("" % a)) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_percent_precedence.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_percent_precedence.py.expect new file mode 100644 index 0000000000000..bd77adeeb7524 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_percent_precedence.py.expect @@ -0,0 +1,20 @@ +("" % a) ** 2 +("" % a)[0] +("" % a)() +("" % a).b + +2 * ("" % a) +2 @ ("" % a) +2 / ("" % a) +2 // ("" % a) +2 % ("" % a) ++("" % a) +b + "" % a +-("" % a) +b - "" % a +b + -("" % a) +~("" % a) +2 ** ("" % a) +await ("" % a) +b[("" % a)] +b(("" % a)) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_power_op_spacing.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_power_op_spacing.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_power_op_spacing.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_power_op_spacing.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_power_op_spacing.py new file mode 100644 index 0000000000000..af361012ea829 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_power_op_spacing.py @@ -0,0 +1,11 @@ +a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 +b = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 +c = 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 +d = 1**1 ** 1**1 ** 1**1 ** 1**1 ** 1**1**1 ** 1 ** 1**1 ** 1**1**1**1**1 ** 1 ** 1**1**1 **1**1** 1 ** 1 ** 1 +e = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 +f = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 + +a = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 +b = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 +c = 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 +d = 1.0**1.0 ** 1.0**1.0 ** 1.0**1.0 ** 1.0**1.0 ** 1.0**1.0**1.0 ** 1.0 ** 1.0**1.0 ** 1.0**1.0**1.0 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_power_op_spacing.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_power_op_spacing.py.expect new file mode 100644 index 0000000000000..da8b91530b81d --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_power_op_spacing.py.expect @@ -0,0 +1,83 @@ +a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 +b = ( + 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 +) +c = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 +d = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 +e = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 +f = ( + 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 +) + +a = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 +b = ( + 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 +) +c = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 +d = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_prefer_rhs_split.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_prefer_rhs_split.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_prefer_rhs_split.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_prefer_rhs_split.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_prefer_rhs_split.py new file mode 100644 index 0000000000000..f3d9fd672515c --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_prefer_rhs_split.py @@ -0,0 +1,106 @@ +first_item, second_item = ( + some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument + ) +) + +some_dict["with_a_long_key"] = ( + some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument + ) +) + +# Make sure it works when the RHS only has one pair of (optional) parens. +first_item, second_item = ( + some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name +) + +some_dict["with_a_long_key"] = ( + some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name +) + +# Make sure chaining assignments work. +first_item, second_item, third_item, forth_item = m["everything"] = ( + some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument + ) +) + +# Make sure when the RHS's first split at the non-optional paren fits, +# we split there instead of the outer RHS optional paren. +first_item, second_item = some_looooooooong_module.some_loooooog_function_name( + first_argument, second_argument, third_argument +) + +( + first_item, + second_item, + third_item, + forth_item, + fifth_item, + last_item_very_loooooong, +) = some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument +) + +( + first_item, + second_item, + third_item, + forth_item, + fifth_item, + last_item_very_loooooong, +) = everything = some_looooong_function_name( + first_argument, second_argument, third_argument +) + + +# Make sure unsplittable type ignore won't be moved. +some_kind_of_table[some_key] = util.some_function( # type: ignore # noqa: E501 + some_arg +).intersection(pk_cols) + +some_kind_of_table[ + some_key +] = lambda obj: obj.some_long_named_method() # type: ignore # noqa: E501 + +some_kind_of_table[ + some_key # type: ignore # noqa: E501 +] = lambda obj: obj.some_long_named_method() + + +# Make when when the left side of assignment plus the opening paren "... = (" is +# exactly line length limit + 1, it won't be split like that. +xxxxxxxxx_yyy_zzzzzzzz[ + xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxxx=1) +] = 1 + + +# Right side of assignment contains un-nested pairs of inner parens. +some_kind_of_instance.some_kind_of_map[a_key] = ( + isinstance(some_var, SomeClass) + and table.something_and_something != table.something_else +) or ( + isinstance(some_other_var, BaseClass) and table.something != table.some_other_thing +) + +# Multiple targets +a = b = ( + ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +) + +a = b = c = d = e = f = g = ( + hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh +) = i = j = ( + kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk +) + +a = ( + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) = c + +a = ( + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) = ( + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +) = ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_prefer_rhs_split.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_prefer_rhs_split.py.expect new file mode 100644 index 0000000000000..f3d9fd672515c --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_prefer_rhs_split.py.expect @@ -0,0 +1,106 @@ +first_item, second_item = ( + some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument + ) +) + +some_dict["with_a_long_key"] = ( + some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument + ) +) + +# Make sure it works when the RHS only has one pair of (optional) parens. +first_item, second_item = ( + some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name +) + +some_dict["with_a_long_key"] = ( + some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name +) + +# Make sure chaining assignments work. +first_item, second_item, third_item, forth_item = m["everything"] = ( + some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument + ) +) + +# Make sure when the RHS's first split at the non-optional paren fits, +# we split there instead of the outer RHS optional paren. +first_item, second_item = some_looooooooong_module.some_loooooog_function_name( + first_argument, second_argument, third_argument +) + +( + first_item, + second_item, + third_item, + forth_item, + fifth_item, + last_item_very_loooooong, +) = some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument +) + +( + first_item, + second_item, + third_item, + forth_item, + fifth_item, + last_item_very_loooooong, +) = everything = some_looooong_function_name( + first_argument, second_argument, third_argument +) + + +# Make sure unsplittable type ignore won't be moved. +some_kind_of_table[some_key] = util.some_function( # type: ignore # noqa: E501 + some_arg +).intersection(pk_cols) + +some_kind_of_table[ + some_key +] = lambda obj: obj.some_long_named_method() # type: ignore # noqa: E501 + +some_kind_of_table[ + some_key # type: ignore # noqa: E501 +] = lambda obj: obj.some_long_named_method() + + +# Make when when the left side of assignment plus the opening paren "... = (" is +# exactly line length limit + 1, it won't be split like that. +xxxxxxxxx_yyy_zzzzzzzz[ + xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxxx=1) +] = 1 + + +# Right side of assignment contains un-nested pairs of inner parens. +some_kind_of_instance.some_kind_of_map[a_key] = ( + isinstance(some_var, SomeClass) + and table.something_and_something != table.something_else +) or ( + isinstance(some_other_var, BaseClass) and table.something != table.some_other_thing +) + +# Multiple targets +a = b = ( + ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +) + +a = b = c = d = e = f = g = ( + hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh +) = i = j = ( + kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk +) + +a = ( + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) = c + +a = ( + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) = ( + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +) = ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_return_annotation_brackets_string.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_return_annotation_brackets_string.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_return_annotation_brackets_string.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_return_annotation_brackets_string.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_return_annotation_brackets_string.py new file mode 100644 index 0000000000000..474130e48f38f --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_return_annotation_brackets_string.py @@ -0,0 +1,7 @@ +# Long string example +def frobnicate() -> "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisIsTrulyUnreasonablyExtremelyLongClassName]": + pass + +# splitting the string breaks if there's any parameters +def frobnicate(a) -> "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisIsTrulyUnreasonablyExtremelyLongClassName]": + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_return_annotation_brackets_string.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_return_annotation_brackets_string.py.expect new file mode 100644 index 0000000000000..610e399b4ae14 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_return_annotation_brackets_string.py.expect @@ -0,0 +1,13 @@ +# Long string example +def frobnicate() -> ( + "ThisIsTrulyUnreasonablyExtremelyLongClassName |" + " list[ThisIsTrulyUnreasonablyExtremelyLongClassName]" +): + pass + + +# splitting the string breaks if there's any parameters +def frobnicate( + a, +) -> "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisIsTrulyUnreasonablyExtremelyLongClassName]": + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_single_line_format_skip_with_multiple_comments.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_single_line_format_skip_with_multiple_comments.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_single_line_format_skip_with_multiple_comments.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_single_line_format_skip_with_multiple_comments.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_single_line_format_skip_with_multiple_comments.py new file mode 100644 index 0000000000000..812febcf2a19f --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_single_line_format_skip_with_multiple_comments.py @@ -0,0 +1,8 @@ +foo = 123 # fmt: skip # noqa: E501 # pylint +bar = ( + 123 , + ( 1 + 5 ) # pylint # fmt:skip +) +baz = "a" + "b" # pylint; fmt: skip; noqa: E501 +skip_will_not_work = "a" + "b" # pylint fmt:skip +skip_will_not_work2 = "a" + "b" # some text; fmt:skip happens to be part of it diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_single_line_format_skip_with_multiple_comments.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_single_line_format_skip_with_multiple_comments.py.expect new file mode 100644 index 0000000000000..d799b0c790e27 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_single_line_format_skip_with_multiple_comments.py.expect @@ -0,0 +1,8 @@ +foo = 123 # fmt: skip # noqa: E501 # pylint +bar = ( + 123 , + ( 1 + 5 ) # pylint # fmt:skip +) +baz = "a" + "b" # pylint; fmt: skip; noqa: E501 +skip_will_not_work = "a" + "b" # pylint fmt:skip +skip_will_not_work2 = "a" + "b" # some text; fmt:skip happens to be part of it diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_trailing_comma.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_trailing_comma.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_trailing_comma.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_trailing_comma.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_trailing_comma.py new file mode 100644 index 0000000000000..24c53091b9002 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_trailing_comma.py @@ -0,0 +1,24 @@ +e = { + "a": fun(msg, "ts"), + "longggggggggggggggid": ..., + "longgggggggggggggggggggkey": ..., "created": ... + # "longkey": ... +} +f = [ + arg1, + arg2, + arg3, arg4 + # comment +] +g = ( + arg1, + arg2, + arg3, arg4 + # comment +) +h = { + arg1, + arg2, + arg3, arg4 + # comment +} diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_trailing_comma.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_trailing_comma.py.expect new file mode 100644 index 0000000000000..1b2bafa0287ec --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_trailing_comma.py.expect @@ -0,0 +1,28 @@ +e = { + "a": fun(msg, "ts"), + "longggggggggggggggid": ..., + "longgggggggggggggggggggkey": ..., + "created": ..., + # "longkey": ... +} +f = [ + arg1, + arg2, + arg3, + arg4, + # comment +] +g = ( + arg1, + arg2, + arg3, + arg4, + # comment +) +h = { + arg1, + arg2, + arg3, + arg4, + # comment +} diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.py new file mode 100644 index 0000000000000..1f2a3b903f08c --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.py @@ -0,0 +1,5 @@ +x[a:=0] +x[a := 0] +x[a := 0, b := 1] +x[5, b := 0] +x[a:=0,b:=1] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.py.expect new file mode 100644 index 0000000000000..1b3b90bcc0305 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.py.expect @@ -0,0 +1,5 @@ +x[a := 0] +x[a := 0] +x[a := 0, b := 1] +x[5, b := 0] +x[a := 0, b := 1] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_37/python37.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/python37.py similarity index 95% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_37/python37.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/python37.py index 01fd7eede3f3a..3fcf6e0ffc530 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_37/python37.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/python37.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python3.7 - - def f(): return (i * 2 async for i in arange(42)) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_37/python37.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/python37.py.expect similarity index 95% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_37/python37.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/python37.py.expect index 01fd7eede3f3a..3fcf6e0ffc530 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_37/python37.py.expect +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/python37.py.expect @@ -1,6 +1,3 @@ -#!/usr/bin/env python3.7 - - def f(): return (i * 2 async for i in arange(42)) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_38/python38.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/python38.py similarity index 93% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_38/python38.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/python38.py index 391b52f8ce511..54d87b3400eb1 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_38/python38.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/python38.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python3.8 - - def starred_return(): my_list = ["value2", "value3"] return "value1", *my_list diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_38/python38.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/python38.py.expect similarity index 93% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_38/python38.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/python38.py.expect index 5df012410a30b..76e2ae438e5ab 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_38/python38.py.expect +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/python38.py.expect @@ -1,6 +1,3 @@ -#!/usr/bin/env python3.8 - - def starred_return(): my_list = ["value2", "value3"] return "value1", *my_list diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_39/python39.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/python39.py similarity index 92% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_39/python39.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/python39.py index 227faca09a1ab..c0434277f66a0 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_39/python39.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/python39.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3.9 - @relaxed_decorator[0] def f(): ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_39/python39.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/python39.py.expect similarity index 92% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_39/python39.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/python39.py.expect index 4af4beebb250e..99db2993cb218 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_39/python39.py.expect +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/python39.py.expect @@ -1,6 +1,3 @@ -#!/usr/bin/env python3.9 - - @relaxed_decorator[0] def f(): ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/raw_docstring.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/raw_docstring.options.json new file mode 100644 index 0000000000000..ce7c52b163497 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/raw_docstring.options.json @@ -0,0 +1 @@ +{"preview": "enabled"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/raw_docstring.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/raw_docstring.py new file mode 100644 index 0000000000000..72fe443843e9a --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/raw_docstring.py @@ -0,0 +1,15 @@ +class C: + + r"""Raw""" + +def f(): + + r"""Raw""" + +class SingleQuotes: + + + r'''Raw''' + +class UpperCaseR: + R"""Raw""" diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/raw_docstring.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/raw_docstring.py.expect new file mode 100644 index 0000000000000..5be480f7f0e89 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/raw_docstring.py.expect @@ -0,0 +1,14 @@ +class C: + r"""Raw""" + + +def f(): + r"""Raw""" + + +class SingleQuotes: + r'''Raw''' + + +class UpperCaseR: + R"""Raw""" diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_await_parens.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_await_parens.py similarity index 90% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_await_parens.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_await_parens.py index 6b8d15f755cfc..f65336615dcc2 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_await_parens.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_await_parens.py @@ -79,3 +79,12 @@ async def main(): async def main(): await (yield) + +async def main(): + await (a ** b) + await (a[b] ** c) + await (a ** b[c]) + await ((a + b) ** (c + d)) + await (a + b) + await (a[b]) + await (a[b ** c]) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_await_parens.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_await_parens.py.expect similarity index 90% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_await_parens.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_await_parens.py.expect index 91e7eb39e1fab..58e879d21726d 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_await_parens.py.expect +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_await_parens.py.expect @@ -91,3 +91,13 @@ async def main(): async def main(): await (yield) + + +async def main(): + await (a**b) + await (a[b] ** c) + await (a ** b[c]) + await ((a + b) ** (c + d)) + await (a + b) + await a[b] + await a[b**c] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_except_parens.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_except_parens.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_except_parens.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_except_parens.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_except_parens.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_except_parens.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_except_parens.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_except_parens.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_for_brackets.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_for_brackets.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_for_brackets.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_for_brackets.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_for_brackets.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_for_brackets.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_for_brackets.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_for_brackets.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_newline_after_code_block_open.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_newline_after_code_block_open.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_newline_after_code_block_open.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_newline_after_code_block_open.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_newline_after_code_block_open.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_newline_after_code_block_open.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_newline_after_code_block_open.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_newline_after_code_block_open.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/remove_newline_after_match.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_newline_after_match.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/remove_newline_after_match.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_newline_after_match.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/remove_newline_after_match.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_newline_after_match.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/remove_newline_after_match.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_newline_after_match.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_parens.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_parens.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_parens.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_parens.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_parens.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_parens.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_parens.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_parens.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_39/remove_with_brackets.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_with_brackets.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_39/remove_with_brackets.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_with_brackets.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_39/remove_with_brackets.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_with_brackets.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_39/remove_with_brackets.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_with_brackets.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/return_annotation_brackets.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/return_annotation_brackets.py similarity index 93% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/return_annotation_brackets.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/return_annotation_brackets.py index 3e6b45147f2e5..8322c4c7ac1f2 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/return_annotation_brackets.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/return_annotation_brackets.py @@ -86,3 +86,8 @@ def foo() -> tuple[loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo # Magic trailing comma example def foo() -> tuple[int, int, int,]: return 2 + +# Magic trailing comma example, with params +# this is broken - the trailing comma is transferred to the param list. Fixed in preview +def foo(a,b) -> tuple[int, int, int,]: + return 2 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/return_annotation_brackets.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/return_annotation_brackets.py.expect similarity index 92% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/return_annotation_brackets.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/return_annotation_brackets.py.expect index 06880ecbe0bde..c8a8ce2ca29f7 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/return_annotation_brackets.py.expect +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/return_annotation_brackets.py.expect @@ -118,3 +118,11 @@ def foo() -> ( ] ): return 2 + + +# Magic trailing comma example, with params +# this is broken - the trailing comma is transferred to the param list. Fixed in preview +def foo( + a, b +) -> tuple[int, int, int,]: + return 2 diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/skip_magic_trailing_comma.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/skip_magic_trailing_comma.options.json new file mode 100644 index 0000000000000..cbb67df0c6676 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/skip_magic_trailing_comma.options.json @@ -0,0 +1 @@ +{"magic_trailing_comma": "ignore"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/skip_magic_trailing_comma.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/skip_magic_trailing_comma.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/skip_magic_trailing_comma.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/skip_magic_trailing_comma.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/skip_magic_trailing_comma.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/skip_magic_trailing_comma.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/skip_magic_trailing_comma.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/skip_magic_trailing_comma.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/slices.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/slices.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/slices.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/slices.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/slices.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/slices.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/slices.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/slices.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/starred_for_target.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/starred_for_target.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/starred_for_target.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/starred_for_target.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_310/starred_for_target.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/starred_for_target.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_310/starred_for_target.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/starred_for_target.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/string_prefixes.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/string_prefixes.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/string_prefixes.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/string_prefixes.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/string_prefixes.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/string_prefixes.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/string_prefixes.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/string_prefixes.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/stub.pyi b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/stub.pyi new file mode 100644 index 0000000000000..d3ad0ca1dd6f6 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/stub.pyi @@ -0,0 +1,75 @@ +X: int + +def f(): ... + + +class D: + ... + + +class C: + ... + +class B: + this_lack_of_newline_should_be_kept: int + def b(self) -> None: ... + + but_this_newline_should_also_be_kept: int + +class A: + attr: int + attr2: str + + def f(self) -> int: + ... + + def g(self) -> str: ... + + + +def g(): + ... + +def h(): ... + +if sys.version_info >= (3, 8): + class E: + def f(self): ... + class F: + + def f(self): ... + class G: ... + class H: ... +else: + class I: ... + class J: ... + def f(): ... + + class K: + def f(self): ... + def f(): ... + +class Nested: + class dirty: ... + class little: ... + class secret: + def who_has_to_know(self): ... + def verse(self): ... + +class Conditional: + def f(self): ... + if sys.version_info >= (3, 8): + def g(self): ... + else: + def g(self): ... + def h(self): ... + def i(self): ... + if sys.version_info >= (3, 8): + def j(self): ... + def k(self): ... + if sys.version_info >= (3, 8): + class A: ... + class B: ... + class C: + def l(self): ... + def m(self): ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/stub.pyi.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/stub.pyi.expect new file mode 100644 index 0000000000000..5a7ab3a03351f --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/stub.pyi.expect @@ -0,0 +1,73 @@ +X: int + +def f(): ... + +class D: ... +class C: ... + +class B: + this_lack_of_newline_should_be_kept: int + def b(self) -> None: ... + + but_this_newline_should_also_be_kept: int + +class A: + attr: int + attr2: str + + def f(self) -> int: ... + def g(self) -> str: ... + +def g(): ... +def h(): ... + +if sys.version_info >= (3, 8): + class E: + def f(self): ... + + class F: + def f(self): ... + + class G: ... + class H: ... + +else: + class I: ... + class J: ... + + def f(): ... + + class K: + def f(self): ... + + def f(): ... + +class Nested: + class dirty: ... + class little: ... + + class secret: + def who_has_to_know(self): ... + + def verse(self): ... + +class Conditional: + def f(self): ... + if sys.version_info >= (3, 8): + def g(self): ... + else: + def g(self): ... + + def h(self): ... + def i(self): ... + if sys.version_info >= (3, 8): + def j(self): ... + + def k(self): ... + if sys.version_info >= (3, 8): + class A: ... + class B: ... + + class C: + def l(self): ... + def m(self): ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/torture.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/torture.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/torture.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/torture.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/torture.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/torture.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/torture.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/torture.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens1.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_comma_optional_parens1.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens1.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_comma_optional_parens1.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens1.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_comma_optional_parens1.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens1.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_comma_optional_parens1.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens2.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_comma_optional_parens2.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens2.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_comma_optional_parens2.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens2.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_comma_optional_parens2.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens2.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_comma_optional_parens2.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens3.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_comma_optional_parens3.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens3.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_comma_optional_parens3.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens3.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_comma_optional_parens3.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens3.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_comma_optional_parens3.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_commas_in_leading_parts.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_commas_in_leading_parts.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_commas_in_leading_parts.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_commas_in_leading_parts.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_commas_in_leading_parts.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_commas_in_leading_parts.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_commas_in_leading_parts.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_commas_in_leading_parts.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/tricky_unicode_symbols.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/tricky_unicode_symbols.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/tricky_unicode_symbols.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/tricky_unicode_symbols.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/tricky_unicode_symbols.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/tricky_unicode_symbols.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/tricky_unicode_symbols.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/tricky_unicode_symbols.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/tupleassign.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/tupleassign.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/tupleassign.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/tupleassign.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/tupleassign.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/tupleassign.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/tupleassign.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/tupleassign.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/type_comments/type_comment_syntax_error.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_comment_syntax_error.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/type_comments/type_comment_syntax_error.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_comment_syntax_error.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/type_comments/type_comment_syntax_error.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_comment_syntax_error.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/type_comments/type_comment_syntax_error.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_comment_syntax_error.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_312/type_params.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_params.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_312/type_params.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_params.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_312/type_params.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_params.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/py_312/type_params.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_params.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/whitespace.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/whitespace.py similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/whitespace.py rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/whitespace.py diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/whitespace.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/whitespace.py.expect similarity index 100% rename from crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/whitespace.py.expect rename to crates/ruff_python_formatter/resources/test/fixtures/black/cases/whitespace.py.expect diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/decorators.py b/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/decorators.py deleted file mode 100644 index 46e37f69edcb8..0000000000000 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/decorators.py +++ /dev/null @@ -1,150 +0,0 @@ -# This file doesn't use the standard decomposition. -# Decorator syntax test cases are separated by double # comments. -# Those before the 'output' comment are valid under the old syntax. -# Those after the 'ouput' comment require PEP614 relaxed syntax. -# Do not remove the double # separator before the first test case, it allows -# the comment before the test case to be ignored. - -## - -@decorator -def f(): - ... - -## - -@decorator() -def f(): - ... - -## - -@decorator(arg) -def f(): - ... - -## - -@decorator(kwarg=0) -def f(): - ... - -## - -@decorator(*args) -def f(): - ... - -## - -@decorator(**kwargs) -def f(): - ... - -## - -@decorator(*args, **kwargs) -def f(): - ... - -## - -@decorator(*args, **kwargs,) -def f(): - ... - -## - -@dotted.decorator -def f(): - ... - -## - -@dotted.decorator(arg) -def f(): - ... - -## - -@dotted.decorator(kwarg=0) -def f(): - ... - -## - -@dotted.decorator(*args) -def f(): - ... - -## - -@dotted.decorator(**kwargs) -def f(): - ... - -## - -@dotted.decorator(*args, **kwargs) -def f(): - ... - -## - -@dotted.decorator(*args, **kwargs,) -def f(): - ... - -## - -@double.dotted.decorator -def f(): - ... - -## - -@double.dotted.decorator(arg) -def f(): - ... - -## - -@double.dotted.decorator(kwarg=0) -def f(): - ... - -## - -@double.dotted.decorator(*args) -def f(): - ... - -## - -@double.dotted.decorator(**kwargs) -def f(): - ... - -## - -@double.dotted.decorator(*args, **kwargs) -def f(): - ... - -## - -@double.dotted.decorator(*args, **kwargs,) -def f(): - ... - -## - -@_(sequence["decorator"]) -def f(): - ... - -## - -@eval("sequence['decorator']") -def f(): - ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/decorators.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/decorators.py.expect deleted file mode 100644 index df17e1e749f3d..0000000000000 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/decorators.py.expect +++ /dev/null @@ -1,29 +0,0 @@ -## - -@decorator()() -def f(): - ... - -## - -@(decorator) -def f(): - ... - -## - -@sequence["decorator"] -def f(): - ... - -## - -@decorator[List[str]] -def f(): - ... - -## - -@var := decorator -def f(): - ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/force_pyi.py b/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/force_pyi.py index edc7495e66308..9c8c40cc96239 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/force_pyi.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/force_pyi.py @@ -1,4 +1,3 @@ -# flags: --pyi from typing import Union @bird diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/force_pyi.pyi b/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/force_pyi.pyi new file mode 100644 index 0000000000000..9c8c40cc96239 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/force_pyi.pyi @@ -0,0 +1,30 @@ +from typing import Union + +@bird +def zoo(): ... + +class A: ... +@bar +class B: + def BMethod(self) -> None: ... + @overload + def BMethod(self, arg : List[str]) -> None: ... + +class C: ... +@hmm +class D: ... +class E: ... + +@baz +def foo() -> None: + ... + +class F (A , C): ... +def spam() -> None: ... + +@overload +def spam(arg: str) -> str: ... + +var : int = 1 + +def eggs() -> Union[str, int]: ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/force_pyi.pyi.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/force_pyi.pyi.expect new file mode 100644 index 0000000000000..4349ba0a53b5b --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/force_pyi.pyi.expect @@ -0,0 +1,32 @@ +from typing import Union + +@bird +def zoo(): ... + +class A: ... + +@bar +class B: + def BMethod(self) -> None: ... + @overload + def BMethod(self, arg: List[str]) -> None: ... + +class C: ... + +@hmm +class D: ... + +class E: ... + +@baz +def foo() -> None: ... + +class F(A, C): ... + +def spam() -> None: ... +@overload +def spam(arg: str) -> str: ... + +var: int = 1 + +def eggs() -> Union[str, int]: ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_312/type_aliases.py b/crates/ruff_python_formatter/resources/test/fixtures/black/py_312/type_aliases.py deleted file mode 100644 index cdac8402f41e9..0000000000000 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_312/type_aliases.py +++ /dev/null @@ -1,5 +0,0 @@ -type A=int -type Gen[T]=list[T] - -type = aliased -print(type(42)) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/py_312/type_aliases.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/py_312/type_aliases.py.expect deleted file mode 100644 index 308a164e198b6..0000000000000 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/py_312/type_aliases.py.expect +++ /dev/null @@ -1,5 +0,0 @@ -type A = int -type Gen[T] = list[T] - -type = aliased -print(type(42)) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring.options.json deleted file mode 100644 index f709c8d714b52..0000000000000 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring.options.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "indent_width": 4 -} diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/skip_magic_trailing_comma.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/skip_magic_trailing_comma.options.json deleted file mode 100644 index e01e786cb6376..0000000000000 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/skip_magic_trailing_comma.options.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "magic_trailing_comma": "ignore" -} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/import_black_tests.py b/crates/ruff_python_formatter/resources/test/fixtures/import_black_tests.py index ad45c017847d7..31d1515aefe3e 100755 --- a/crates/ruff_python_formatter/resources/test/fixtures/import_black_tests.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/import_black_tests.py @@ -3,6 +3,8 @@ from __future__ import annotations import argparse +import json +import os from pathlib import Path @@ -14,22 +16,18 @@ def import_fixture(fixture: Path, fixture_set: str): output_directory = Path(__file__).parent.joinpath("black").joinpath(fixture_set) output_directory.mkdir(parents=True, exist_ok=True) - fixture_path = output_directory.joinpath(fixture.name) - expect_path = fixture_path.with_suffix(".py.expect") - - with ( - fixture.open("r") as black_file, - fixture_path.open("w") as fixture_file, - expect_path.open("w") as expect_file - ): + with fixture.open("r") as black_file: lines = iter(black_file) expected = [] input = [] + flags = None for line in lines: if line.rstrip() == "# output": expected = list(lines) break + elif not input and line.startswith("# flags:"): + flags = line else: input.append(line) @@ -37,24 +35,46 @@ def import_fixture(fixture: Path, fixture_set: str): # If there's no output marker, tread the whole file as already pre-formatted expected = input - fixture_file.write("".join(input).strip() + "\n") - expect_file.write("".join(expected).strip() + "\n") + options = {} + extension = "py" + + if flags: + if "--preview" in flags: + options["preview"] = "enabled" + + if "--pyi" in flags: + extension = "pyi" + + if "--line-length=" in flags: + [_, length_and_rest] = flags.split("--line-length=", 1) + length = length_and_rest.split(" ", 1)[0] + options["line_length"] = int(length) + + if "--skip-magic-trailing-comma" in flags: + options["magic_trailing_comma"] = "ignore" + + fixture_path = output_directory.joinpath(fixture.name).with_suffix(f".{extension}") + expect_path = fixture_path.with_suffix(f".{extension}.expect") + options_path = fixture_path.with_suffix(".options.json") + + if len(options) > 0: + with options_path.open("w") as options_file: + json.dump(options, options_file) + elif os.path.exists(options_path): + os.remove(options_path) + + with ( + fixture_path.open("w") as fixture_file, + expect_path.open("w") as expect_file + ): + fixture_file.write("".join(input).strip() + "\n") + expect_file.write("".join(expected).strip() + "\n") # The name of the folders in the `data` for which the tests should be imported FIXTURE_SETS = [ - "fast", - "py_36", - "py_37", - "py_38", - "py_39", - "py_310", - "py_311", - "py_312", - "simple_cases", + "cases", "miscellaneous", - ".", - "type_comments" ] # Tests that ruff doesn't fully support yet and, therefore, should not be imported @@ -63,9 +83,16 @@ def import_fixture(fixture: Path, fixture_set: str): "async_as_identifier.py", "invalid_header.py", "pattern_matching_invalid.py", + "pep_572_do_not_remove_parens.py", # Python 2 - "python2_detection.py" + "python2_detection.py", + + # Uses a different output format + "decorators.py", + + # Ruff fails to parse because of a parser bug + "type_aliases.py" # #8900 #8899 ] diff --git a/crates/ruff_python_formatter/src/expression/string/docstring.rs b/crates/ruff_python_formatter/src/expression/string/docstring.rs index 21057e4645ceb..3155fa1a0f532 100644 --- a/crates/ruff_python_formatter/src/expression/string/docstring.rs +++ b/crates/ruff_python_formatter/src/expression/string/docstring.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; +use ruff_python_trivia::PythonWhitespace; use { ruff_formatter::{write, Printed}, ruff_source_file::Locator, @@ -99,7 +100,7 @@ pub(super) fn format(normalized: &NormalizedString, f: &mut PyFormatter) -> Form let docstring = &normalized.text; // Black doesn't change the indentation of docstrings that contain an escaped newline - if docstring.contains("\\\n") { + if contains_unescaped_newline(docstring) { return normalized.fmt(f); } @@ -200,6 +201,20 @@ pub(super) fn format(normalized: &NormalizedString, f: &mut PyFormatter) -> Form write!(f, [source_position(normalized.end()), normalized.quotes]) } +fn contains_unescaped_newline(haystack: &str) -> bool { + let mut rest = haystack; + + while let Some(index) = memchr::memchr(b'\\', rest.as_bytes()) { + rest = &rest[index + 1..].trim_whitespace_start(); + + if rest.starts_with('\n') { + return true; + } + } + + false +} + /// An abstraction for printing each line of a docstring. struct DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { f: &'fmt mut PyFormatter<'ast, 'buf>, diff --git a/crates/ruff_python_formatter/tests/fixtures.rs b/crates/ruff_python_formatter/tests/fixtures.rs index 1b949c7b73d0b..3c48027d98408 100644 --- a/crates/ruff_python_formatter/tests/fixtures.rs +++ b/crates/ruff_python_formatter/tests/fixtures.rs @@ -20,9 +20,10 @@ fn black_compatibility() { let options_path = input_path.with_extension("options.json"); - let options: PyFormatOptions = if let Ok(options_file) = fs::File::open(options_path) { + let options: PyFormatOptions = if let Ok(options_file) = fs::File::open(&options_path) { let reader = BufReader::new(options_file); - serde_json::from_reader(reader).expect("Options to be a valid Json file") + serde_json::from_reader(reader) + .unwrap_or_else(|_| panic!("Option file {options_path:?} to be a valid Json file")) } else { PyFormatOptions::from_extension(input_path) }; @@ -34,7 +35,11 @@ fn black_compatibility() { ) }); - let expected_path = input_path.with_extension("py.expect"); + let extension = input_path + .extension() + .expect("Test file to have py or pyi extension") + .to_string_lossy(); + let expected_path = input_path.with_extension(format!("{extension}.expect")); let expected_output = fs::read_to_string(&expected_path) .unwrap_or_else(|_| panic!("Expected Black output file '{expected_path:?}' to exist")); @@ -106,7 +111,11 @@ fn black_compatibility() { } }; - insta::glob!("../resources", "test/fixtures/black/**/*.py", test_file); + insta::glob!( + "../resources", + "test/fixtures/black/**/*.{py,pyi}", + test_file + ); } #[test] diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__comment_after_escaped_newline.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comment_after_escaped_newline.py.snap similarity index 93% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__comment_after_escaped_newline.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comment_after_escaped_newline.py.snap index 9656ed1e16fe5..d936affef1eb1 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__comment_after_escaped_newline.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comment_after_escaped_newline.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comment_after_escaped_newline.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/comment_after_escaped_newline.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__comments2.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comments2.py.snap similarity index 99% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__comments2.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comments2.py.snap index 9c0622bce3e52..d9273e29931e1 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__comments2.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comments2.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments2.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments2.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__comments6.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comments6.py.snap similarity index 99% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__comments6.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comments6.py.snap index 45ab60a21a43b..f1bc3b617373d 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__comments6.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comments6.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments6.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments6.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__comments9.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comments9.py.snap similarity index 99% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__comments9.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comments9.py.snap index 743906edda155..5e25b161c919a 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__comments9.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comments9.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments9.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments9.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comments_in_blocks.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comments_in_blocks.py.snap new file mode 100644 index 0000000000000..7524d7c7a7717 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__comments_in_blocks.py.snap @@ -0,0 +1,382 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/comments_in_blocks.py +--- +## Input + +```python +# Test cases from: +# - https://github.com/psf/black/issues/1798 +# - https://github.com/psf/black/issues/1499 +# - https://github.com/psf/black/issues/1211 +# - https://github.com/psf/black/issues/563 + +( + lambda + # a comment + : None +) + +( + lambda: + # b comment + None +) + +( + lambda + # a comment + : + # b comment + None +) + +[ + x + # Let's do this + for + # OK? + x + # Some comment + # And another + in + # One more + y +] + +return [ + (offers[offer_index], 1.0) + for offer_index, _ + # avoid returning any offers that don't match the grammar so + # that the return values here are consistent with what would be + # returned in AcceptValidHeader + in self._parse_and_normalize_offers(offers) +] + +from foo import ( + bar, + # qux +) + + +def convert(collection): + # replace all variables by integers + replacement_dict = { + variable: f"{index}" + for index, variable + # 0 is reserved as line terminator + in enumerate(collection.variables(), start=1) + } + + +{ + i: i + for i + # a comment + in range(5) +} + + +def get_subtree_proof_nodes( + chunk_index_groups: Sequence[Tuple[int, ...], ...], +) -> Tuple[int, ...]: + subtree_node_paths = ( + # We take a candidate element from each group and shift it to + # remove the bits that are not common to other group members, then + # we convert it to a tree path that all elements from this group + # have in common. + chunk_index + for chunk_index, bits_to_truncate + # Each group will contain an even "power-of-two" number of# elements. + # This tells us how many tailing bits each element has# which need to + # be truncated to get the group's common prefix. + in ((group[0], (len(group) - 1).bit_length()) for group in chunk_index_groups) + ) + return subtree_node_paths + + +if ( + # comment1 + a + # comment2 + or ( + # comment3 + ( + # comment4 + b + ) + # comment5 + and + # comment6 + c + or ( + # comment7 + d + ) + ) +): + print("Foo") +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -5,9 +5,9 @@ + # - https://github.com/psf/black/issues/563 + + ( +- lambda ++ lambda: + # a comment +- : None ++ None + ) + + ( +@@ -17,9 +17,8 @@ + ) + + ( +- lambda ++ lambda: + # a comment +- : + # b comment + None + ) +``` + +## Ruff Output + +```python +# Test cases from: +# - https://github.com/psf/black/issues/1798 +# - https://github.com/psf/black/issues/1499 +# - https://github.com/psf/black/issues/1211 +# - https://github.com/psf/black/issues/563 + +( + lambda: + # a comment + None +) + +( + lambda: + # b comment + None +) + +( + lambda: + # a comment + # b comment + None +) + +[ + x + # Let's do this + for + # OK? + x + # Some comment + # And another + in + # One more + y +] + +return [ + (offers[offer_index], 1.0) + for offer_index, _ + # avoid returning any offers that don't match the grammar so + # that the return values here are consistent with what would be + # returned in AcceptValidHeader + in self._parse_and_normalize_offers(offers) +] + +from foo import ( + bar, + # qux +) + + +def convert(collection): + # replace all variables by integers + replacement_dict = { + variable: f"{index}" + for index, variable + # 0 is reserved as line terminator + in enumerate(collection.variables(), start=1) + } + + +{ + i: i + for i + # a comment + in range(5) +} + + +def get_subtree_proof_nodes( + chunk_index_groups: Sequence[Tuple[int, ...], ...], +) -> Tuple[int, ...]: + subtree_node_paths = ( + # We take a candidate element from each group and shift it to + # remove the bits that are not common to other group members, then + # we convert it to a tree path that all elements from this group + # have in common. + chunk_index + for chunk_index, bits_to_truncate + # Each group will contain an even "power-of-two" number of# elements. + # This tells us how many tailing bits each element has# which need to + # be truncated to get the group's common prefix. + in ((group[0], (len(group) - 1).bit_length()) for group in chunk_index_groups) + ) + return subtree_node_paths + + +if ( + # comment1 + a + # comment2 + or ( + # comment3 + ( + # comment4 + b + ) + # comment5 + and + # comment6 + c + or ( + # comment7 + d + ) + ) +): + print("Foo") +``` + +## Black Output + +```python +# Test cases from: +# - https://github.com/psf/black/issues/1798 +# - https://github.com/psf/black/issues/1499 +# - https://github.com/psf/black/issues/1211 +# - https://github.com/psf/black/issues/563 + +( + lambda + # a comment + : None +) + +( + lambda: + # b comment + None +) + +( + lambda + # a comment + : + # b comment + None +) + +[ + x + # Let's do this + for + # OK? + x + # Some comment + # And another + in + # One more + y +] + +return [ + (offers[offer_index], 1.0) + for offer_index, _ + # avoid returning any offers that don't match the grammar so + # that the return values here are consistent with what would be + # returned in AcceptValidHeader + in self._parse_and_normalize_offers(offers) +] + +from foo import ( + bar, + # qux +) + + +def convert(collection): + # replace all variables by integers + replacement_dict = { + variable: f"{index}" + for index, variable + # 0 is reserved as line terminator + in enumerate(collection.variables(), start=1) + } + + +{ + i: i + for i + # a comment + in range(5) +} + + +def get_subtree_proof_nodes( + chunk_index_groups: Sequence[Tuple[int, ...], ...], +) -> Tuple[int, ...]: + subtree_node_paths = ( + # We take a candidate element from each group and shift it to + # remove the bits that are not common to other group members, then + # we convert it to a tree path that all elements from this group + # have in common. + chunk_index + for chunk_index, bits_to_truncate + # Each group will contain an even "power-of-two" number of# elements. + # This tells us how many tailing bits each element has# which need to + # be truncated to get the group's common prefix. + in ((group[0], (len(group) - 1).bit_length()) for group in chunk_index_groups) + ) + return subtree_node_paths + + +if ( + # comment1 + a + # comment2 + or ( + # comment3 + ( + # comment4 + b + ) + # comment5 + and + # comment6 + c + or ( + # comment7 + d + ) + ) +): + print("Foo") +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__composition.py.snap similarity index 99% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__composition.py.snap index 756ef81dd3b62..c1c42e11bbb3d 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__composition.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/composition.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/composition.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition_no_trailing_comma.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__composition_no_trailing_comma.py.snap similarity index 99% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition_no_trailing_comma.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__composition_no_trailing_comma.py.snap index 89664dc7c155b..4888f9a617d8c 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition_no_trailing_comma.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__composition_no_trailing_comma.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/composition_no_trailing_comma.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/composition_no_trailing_comma.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__conditional_expression.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__conditional_expression.py.snap new file mode 100644 index 0000000000000..55b4f12034c43 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__conditional_expression.py.snap @@ -0,0 +1,334 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/conditional_expression.py +--- +## Input + +```python +long_kwargs_single_line = my_function( + foo="test, this is a sample value", + bar=some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz, + baz="hello, this is a another value", +) + +multiline_kwargs_indented = my_function( + foo="test, this is a sample value", + bar=some_long_value_name_foo_bar_baz + if some_boolean_variable + else some_fallback_value_foo_bar_baz, + baz="hello, this is a another value", +) + +imploding_kwargs = my_function( + foo="test, this is a sample value", + bar=a + if foo + else b, + baz="hello, this is a another value", +) + +imploding_line = ( + 1 + if 1 + 1 == 2 + else 0 +) + +exploding_line = "hello this is a slightly long string" if some_long_value_name_foo_bar_baz else "this one is a little shorter" + +positional_argument_test(some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz) + +def weird_default_argument(x=some_long_value_name_foo_bar_baz + if SOME_CONSTANT + else some_fallback_value_foo_bar_baz): + pass + +nested = "hello this is a slightly long string" if (some_long_value_name_foo_bar_baz if + nesting_test_expressions else some_fallback_value_foo_bar_baz) \ + else "this one is a little shorter" + +generator_expression = ( + some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz for some_boolean_variable in some_iterable +) + + +def limit_offset_sql(self, low_mark, high_mark): + """Return LIMIT/OFFSET SQL clause.""" + limit, offset = self._get_limit_offset_params(low_mark, high_mark) + return " ".join( + sql + for sql in ( + "LIMIT %d" % limit if limit else None, + ("OFFSET %d" % offset) if offset else None, + ) + if sql + ) + + +def something(): + clone._iterable_class = ( + NamedValuesListIterable + if named + else FlatValuesListIterable + if flat + else ValuesListIterable + ) +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,20 +1,16 @@ + long_kwargs_single_line = my_function( + foo="test, this is a sample value", +- bar=( +- some_long_value_name_foo_bar_baz +- if some_boolean_variable +- else some_fallback_value_foo_bar_baz +- ), ++ bar=some_long_value_name_foo_bar_baz ++ if some_boolean_variable ++ else some_fallback_value_foo_bar_baz, + baz="hello, this is a another value", + ) + + multiline_kwargs_indented = my_function( + foo="test, this is a sample value", +- bar=( +- some_long_value_name_foo_bar_baz +- if some_boolean_variable +- else some_fallback_value_foo_bar_baz +- ), ++ bar=some_long_value_name_foo_bar_baz ++ if some_boolean_variable ++ else some_fallback_value_foo_bar_baz, + baz="hello, this is a another value", + ) + +@@ -40,11 +36,9 @@ + + + def weird_default_argument( +- x=( +- some_long_value_name_foo_bar_baz +- if SOME_CONSTANT +- else some_fallback_value_foo_bar_baz +- ), ++ x=some_long_value_name_foo_bar_baz ++ if SOME_CONSTANT ++ else some_fallback_value_foo_bar_baz, + ): + pass + +@@ -60,11 +54,9 @@ + ) + + generator_expression = ( +- ( +- some_long_value_name_foo_bar_baz +- if some_boolean_variable +- else some_fallback_value_foo_bar_baz +- ) ++ some_long_value_name_foo_bar_baz ++ if some_boolean_variable ++ else some_fallback_value_foo_bar_baz + for some_boolean_variable in some_iterable + ) + +@@ -86,5 +78,7 @@ + clone._iterable_class = ( + NamedValuesListIterable + if named +- else FlatValuesListIterable if flat else ValuesListIterable ++ else FlatValuesListIterable ++ if flat ++ else ValuesListIterable + ) +``` + +## Ruff Output + +```python +long_kwargs_single_line = my_function( + foo="test, this is a sample value", + bar=some_long_value_name_foo_bar_baz + if some_boolean_variable + else some_fallback_value_foo_bar_baz, + baz="hello, this is a another value", +) + +multiline_kwargs_indented = my_function( + foo="test, this is a sample value", + bar=some_long_value_name_foo_bar_baz + if some_boolean_variable + else some_fallback_value_foo_bar_baz, + baz="hello, this is a another value", +) + +imploding_kwargs = my_function( + foo="test, this is a sample value", + bar=a if foo else b, + baz="hello, this is a another value", +) + +imploding_line = 1 if 1 + 1 == 2 else 0 + +exploding_line = ( + "hello this is a slightly long string" + if some_long_value_name_foo_bar_baz + else "this one is a little shorter" +) + +positional_argument_test( + some_long_value_name_foo_bar_baz + if some_boolean_variable + else some_fallback_value_foo_bar_baz +) + + +def weird_default_argument( + x=some_long_value_name_foo_bar_baz + if SOME_CONSTANT + else some_fallback_value_foo_bar_baz, +): + pass + + +nested = ( + "hello this is a slightly long string" + if ( + some_long_value_name_foo_bar_baz + if nesting_test_expressions + else some_fallback_value_foo_bar_baz + ) + else "this one is a little shorter" +) + +generator_expression = ( + some_long_value_name_foo_bar_baz + if some_boolean_variable + else some_fallback_value_foo_bar_baz + for some_boolean_variable in some_iterable +) + + +def limit_offset_sql(self, low_mark, high_mark): + """Return LIMIT/OFFSET SQL clause.""" + limit, offset = self._get_limit_offset_params(low_mark, high_mark) + return " ".join( + sql + for sql in ( + "LIMIT %d" % limit if limit else None, + ("OFFSET %d" % offset) if offset else None, + ) + if sql + ) + + +def something(): + clone._iterable_class = ( + NamedValuesListIterable + if named + else FlatValuesListIterable + if flat + else ValuesListIterable + ) +``` + +## Black Output + +```python +long_kwargs_single_line = my_function( + foo="test, this is a sample value", + bar=( + some_long_value_name_foo_bar_baz + if some_boolean_variable + else some_fallback_value_foo_bar_baz + ), + baz="hello, this is a another value", +) + +multiline_kwargs_indented = my_function( + foo="test, this is a sample value", + bar=( + some_long_value_name_foo_bar_baz + if some_boolean_variable + else some_fallback_value_foo_bar_baz + ), + baz="hello, this is a another value", +) + +imploding_kwargs = my_function( + foo="test, this is a sample value", + bar=a if foo else b, + baz="hello, this is a another value", +) + +imploding_line = 1 if 1 + 1 == 2 else 0 + +exploding_line = ( + "hello this is a slightly long string" + if some_long_value_name_foo_bar_baz + else "this one is a little shorter" +) + +positional_argument_test( + some_long_value_name_foo_bar_baz + if some_boolean_variable + else some_fallback_value_foo_bar_baz +) + + +def weird_default_argument( + x=( + some_long_value_name_foo_bar_baz + if SOME_CONSTANT + else some_fallback_value_foo_bar_baz + ), +): + pass + + +nested = ( + "hello this is a slightly long string" + if ( + some_long_value_name_foo_bar_baz + if nesting_test_expressions + else some_fallback_value_foo_bar_baz + ) + else "this one is a little shorter" +) + +generator_expression = ( + ( + some_long_value_name_foo_bar_baz + if some_boolean_variable + else some_fallback_value_foo_bar_baz + ) + for some_boolean_variable in some_iterable +) + + +def limit_offset_sql(self, low_mark, high_mark): + """Return LIMIT/OFFSET SQL clause.""" + limit, offset = self._get_limit_offset_params(low_mark, high_mark) + return " ".join( + sql + for sql in ( + "LIMIT %d" % limit if limit else None, + ("OFFSET %d" % offset) if offset else None, + ) + if sql + ) + + +def something(): + clone._iterable_class = ( + NamedValuesListIterable + if named + else FlatValuesListIterable if flat else ValuesListIterable + ) +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__docstring_no_string_normalization.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__docstring_no_string_normalization.py.snap similarity index 99% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__docstring_no_string_normalization.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__docstring_no_string_normalization.py.snap index bdc68fe77bcbb..17915fd54dd78 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__docstring_no_string_normalization.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__docstring_no_string_normalization.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/docstring_no_string_normalization.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/docstring_no_string_normalization.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__expression.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__expression.py.snap similarity index 99% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__expression.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__expression.py.snap index ea14186d298f3..5b60337c94cda 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__expression.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__expression.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/expression.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/expression.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__fmtonoff.py.snap similarity index 99% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__fmtonoff.py.snap index 2df0b531f8ef7..44fe937154f9d 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__fmtonoff.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff4.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__fmtonoff4.py.snap similarity index 96% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff4.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__fmtonoff4.py.snap index 529e50d32cbd2..9162f859213cc 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff4.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__fmtonoff4.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff4.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff4.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff5.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__fmtonoff5.py.snap similarity index 99% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff5.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__fmtonoff5.py.snap index a531a87c052d4..1346480b808e6 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtonoff5.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__fmtonoff5.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff5.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtonoff5.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtpass_imports.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__fmtpass_imports.py.snap similarity index 96% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtpass_imports.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__fmtpass_imports.py.snap index 8dceca43bc0d5..6a8042f10d6c1 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtpass_imports.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__fmtpass_imports.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtpass_imports.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtpass_imports.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtskip5.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__fmtskip5.py.snap similarity index 96% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtskip5.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__fmtskip5.py.snap index 597ccdeeba38a..325b315501abd 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__fmtskip5.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__fmtskip5.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip5.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/fmtskip5.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__funcdef_return_type_trailing_comma.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__funcdef_return_type_trailing_comma.py.snap new file mode 100644 index 0000000000000..a10744872cd4a --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__funcdef_return_type_trailing_comma.py.snap @@ -0,0 +1,608 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.py +--- +## Input + +```python +# normal, short, function definition +def foo(a, b) -> tuple[int, float]: ... + + +# normal, short, function definition w/o return type +def foo(a, b): ... + + +# no splitting +def foo(a: A, b: B) -> list[p, q]: + pass + + +# magic trailing comma in param list +def foo(a, b,): ... + + +# magic trailing comma in nested params in param list +def foo(a, b: tuple[int, float,]): ... + + +# magic trailing comma in return type, no params +def a() -> tuple[ + a, + b, +]: ... + + +# magic trailing comma in return type, params +def foo(a: A, b: B) -> list[ + p, + q, +]: + pass + + +# magic trailing comma in param list and in return type +def foo( + a: a, + b: b, +) -> list[ + a, + a, +]: + pass + + +# long function definition, param list is longer +def aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa( + bbbbbbbbbbbbbbbbbb, +) -> cccccccccccccccccccccccccccccc: ... + + +# long function definition, return type is longer +# this should maybe split on rhs? +def aaaaaaaaaaaaaaaaa(bbbbbbbbbbbbbbbbbb) -> list[ + Ccccccccccccccccccccccccccccccccccccccccccccccccccc, Dddddd +]: ... + + +# long return type, no param list +def foo() -> list[ + Loooooooooooooooooooooooooooooooooooong, + Loooooooooooooooooooong, + Looooooooooooong, +]: ... + + +# long function name, no param list, no return value +def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeeeeery_looooooong(): + pass + + +# long function name, no param list +def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeeeeery_looooooong() -> ( + list[int, float] +): ... + + +# long function name, no return value +def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeeeeery_looooooong( + a, b +): ... + + +# unskippable type hint (??) +def foo(a) -> list[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]: # type: ignore + pass + + +def foo(a) -> list[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +]: # abpedeifnore + pass + +def foo(a, b: list[Bad],): ... # type: ignore + +# don't lose any comments (no magic) +def foo( # 1 + a, # 2 + b) -> list[ # 3 + a, # 4 + b]: # 5 + ... # 6 + + +# don't lose any comments (param list magic) +def foo( # 1 + a, # 2 + b,) -> list[ # 3 + a, # 4 + b]: # 5 + ... # 6 + + +# don't lose any comments (return type magic) +def foo( # 1 + a, # 2 + b) -> list[ # 3 + a, # 4 + b,]: # 5 + ... # 6 + + +# don't lose any comments (both magic) +def foo( # 1 + a, # 2 + b,) -> list[ # 3 + a, # 4 + b,]: # 5 + ... # 6 + +# real life example +def SimplePyFn( + context: hl.GeneratorContext, + buffer_input: Buffer[UInt8, 2], + func_input: Buffer[Int32, 2], + float_arg: Scalar[Float32], + offset: int = 0, +) -> tuple[ + Buffer[UInt8, 2], + Buffer[UInt8, 2], +]: ... +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -29,14 +29,18 @@ + + + # magic trailing comma in return type, no params +-def a() -> tuple[ +- a, +- b, +-]: ... ++def a() -> ( ++ tuple[ ++ a, ++ b, ++ ] ++): ... + + + # magic trailing comma in return type, params +-def foo(a: A, b: B) -> list[ ++def foo( ++ a: A, b: B ++) -> list[ + p, + q, + ]: +@@ -63,16 +67,18 @@ + # long function definition, return type is longer + # this should maybe split on rhs? + def aaaaaaaaaaaaaaaaa( +- bbbbbbbbbbbbbbbbbb, ++ bbbbbbbbbbbbbbbbbb + ) -> list[Ccccccccccccccccccccccccccccccccccccccccccccccccccc, Dddddd]: ... + + + # long return type, no param list +-def foo() -> list[ +- Loooooooooooooooooooooooooooooooooooong, +- Loooooooooooooooooooong, +- Looooooooooooong, +-]: ... ++def foo() -> ( ++ list[ ++ Loooooooooooooooooooooooooooooooooooong, ++ Loooooooooooooooooooong, ++ Looooooooooooong, ++ ] ++): ... + + + # long function name, no param list, no return value +@@ -93,12 +99,16 @@ + + + # unskippable type hint (??) +-def foo(a) -> list[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]: # type: ignore ++def foo( ++ a ++) -> list[ ++ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++]: # type: ignore + pass + + + def foo( +- a, ++ a + ) -> list[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ]: # abpedeifnore +@@ -112,7 +122,13 @@ + + + # don't lose any comments (no magic) +-def foo(a, b) -> list[a, b]: # 1 # 2 # 3 # 4 # 5 ++def foo( # 1 ++ a, # 2 ++ b, ++) -> list[ # 3 ++ a, # 4 ++ b, ++]: # 5 + ... # 6 + + +@@ -120,12 +136,18 @@ + def foo( # 1 + a, # 2 + b, +-) -> list[a, b]: # 3 # 4 # 5 ++) -> list[ # 3 ++ a, # 4 ++ b, ++]: # 5 + ... # 6 + + + # don't lose any comments (return type magic) +-def foo(a, b) -> list[ # 1 # 2 # 3 ++def foo( # 1 ++ a, # 2 ++ b, ++) -> list[ # 3 + a, # 4 + b, + ]: # 5 +``` + +## Ruff Output + +```python +# normal, short, function definition +def foo(a, b) -> tuple[int, float]: ... + + +# normal, short, function definition w/o return type +def foo(a, b): ... + + +# no splitting +def foo(a: A, b: B) -> list[p, q]: + pass + + +# magic trailing comma in param list +def foo( + a, + b, +): ... + + +# magic trailing comma in nested params in param list +def foo( + a, + b: tuple[ + int, + float, + ], +): ... + + +# magic trailing comma in return type, no params +def a() -> ( + tuple[ + a, + b, + ] +): ... + + +# magic trailing comma in return type, params +def foo( + a: A, b: B +) -> list[ + p, + q, +]: + pass + + +# magic trailing comma in param list and in return type +def foo( + a: a, + b: b, +) -> list[ + a, + a, +]: + pass + + +# long function definition, param list is longer +def aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa( + bbbbbbbbbbbbbbbbbb, +) -> cccccccccccccccccccccccccccccc: ... + + +# long function definition, return type is longer +# this should maybe split on rhs? +def aaaaaaaaaaaaaaaaa( + bbbbbbbbbbbbbbbbbb +) -> list[Ccccccccccccccccccccccccccccccccccccccccccccccccccc, Dddddd]: ... + + +# long return type, no param list +def foo() -> ( + list[ + Loooooooooooooooooooooooooooooooooooong, + Loooooooooooooooooooong, + Looooooooooooong, + ] +): ... + + +# long function name, no param list, no return value +def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeeeeery_looooooong(): + pass + + +# long function name, no param list +def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeeeeery_looooooong() -> ( + list[int, float] +): ... + + +# long function name, no return value +def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeeeeery_looooooong( + a, b +): ... + + +# unskippable type hint (??) +def foo( + a +) -> list[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +]: # type: ignore + pass + + +def foo( + a +) -> list[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +]: # abpedeifnore + pass + + +def foo( + a, + b: list[Bad], +): ... # type: ignore + + +# don't lose any comments (no magic) +def foo( # 1 + a, # 2 + b, +) -> list[ # 3 + a, # 4 + b, +]: # 5 + ... # 6 + + +# don't lose any comments (param list magic) +def foo( # 1 + a, # 2 + b, +) -> list[ # 3 + a, # 4 + b, +]: # 5 + ... # 6 + + +# don't lose any comments (return type magic) +def foo( # 1 + a, # 2 + b, +) -> list[ # 3 + a, # 4 + b, +]: # 5 + ... # 6 + + +# don't lose any comments (both magic) +def foo( # 1 + a, # 2 + b, +) -> list[ # 3 + a, # 4 + b, +]: # 5 + ... # 6 + + +# real life example +def SimplePyFn( + context: hl.GeneratorContext, + buffer_input: Buffer[UInt8, 2], + func_input: Buffer[Int32, 2], + float_arg: Scalar[Float32], + offset: int = 0, +) -> tuple[ + Buffer[UInt8, 2], + Buffer[UInt8, 2], +]: ... +``` + +## Black Output + +```python +# normal, short, function definition +def foo(a, b) -> tuple[int, float]: ... + + +# normal, short, function definition w/o return type +def foo(a, b): ... + + +# no splitting +def foo(a: A, b: B) -> list[p, q]: + pass + + +# magic trailing comma in param list +def foo( + a, + b, +): ... + + +# magic trailing comma in nested params in param list +def foo( + a, + b: tuple[ + int, + float, + ], +): ... + + +# magic trailing comma in return type, no params +def a() -> tuple[ + a, + b, +]: ... + + +# magic trailing comma in return type, params +def foo(a: A, b: B) -> list[ + p, + q, +]: + pass + + +# magic trailing comma in param list and in return type +def foo( + a: a, + b: b, +) -> list[ + a, + a, +]: + pass + + +# long function definition, param list is longer +def aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa( + bbbbbbbbbbbbbbbbbb, +) -> cccccccccccccccccccccccccccccc: ... + + +# long function definition, return type is longer +# this should maybe split on rhs? +def aaaaaaaaaaaaaaaaa( + bbbbbbbbbbbbbbbbbb, +) -> list[Ccccccccccccccccccccccccccccccccccccccccccccccccccc, Dddddd]: ... + + +# long return type, no param list +def foo() -> list[ + Loooooooooooooooooooooooooooooooooooong, + Loooooooooooooooooooong, + Looooooooooooong, +]: ... + + +# long function name, no param list, no return value +def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeeeeery_looooooong(): + pass + + +# long function name, no param list +def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeeeeery_looooooong() -> ( + list[int, float] +): ... + + +# long function name, no return value +def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeeeeery_looooooong( + a, b +): ... + + +# unskippable type hint (??) +def foo(a) -> list[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]: # type: ignore + pass + + +def foo( + a, +) -> list[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +]: # abpedeifnore + pass + + +def foo( + a, + b: list[Bad], +): ... # type: ignore + + +# don't lose any comments (no magic) +def foo(a, b) -> list[a, b]: # 1 # 2 # 3 # 4 # 5 + ... # 6 + + +# don't lose any comments (param list magic) +def foo( # 1 + a, # 2 + b, +) -> list[a, b]: # 3 # 4 # 5 + ... # 6 + + +# don't lose any comments (return type magic) +def foo(a, b) -> list[ # 1 # 2 # 3 + a, # 4 + b, +]: # 5 + ... # 6 + + +# don't lose any comments (both magic) +def foo( # 1 + a, # 2 + b, +) -> list[ # 3 + a, # 4 + b, +]: # 5 + ... # 6 + + +# real life example +def SimplePyFn( + context: hl.GeneratorContext, + buffer_input: Buffer[UInt8, 2], + func_input: Buffer[Int32, 2], + float_arg: Scalar[Float32], + offset: int = 0, +) -> tuple[ + Buffer[UInt8, 2], + Buffer[UInt8, 2], +]: ... +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__function.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__function.py.snap similarity index 99% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__function.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__function.py.snap index 317d6c6a188b6..df6fda9a85cac 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__function.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__function.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/function.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__function2.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__function2.py.snap similarity index 99% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__function2.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__function2.py.snap index 2fc0696b9ba42..f85dbd5fef575 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__function2.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__function2.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function2.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/function2.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__ignore_pyi.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__ignore_pyi.pyi.snap similarity index 71% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__ignore_pyi.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__ignore_pyi.pyi.snap index 9027c47633afd..ed9ee11309184 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__ignore_pyi.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__ignore_pyi.pyi.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/ignore_pyi.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/ignore_pyi.pyi --- ## Input @@ -22,9 +22,10 @@ def g(): # hi ... -def h(): - ... - # bye +# FIXME(#8905): Uncomment, leads to unstable formatting +# def h(): +# ... +# # bye ``` ## Black Differences @@ -32,34 +33,25 @@ def h(): ```diff --- Black +++ Ruff -@@ -1,18 +1,25 @@ - def f(): # type: ignore - ... +@@ -3,7 +3,6 @@ -+ class x: # some comment ... +- + class y: ... # comment --class y: ... # comment - -+class y: -+ ... # comment -+ -+ # whitespace doesn't matter (note the next line has a trailing space and tab) --class z: ... -+class z: -+ ... -+ - - def g(): +@@ -13,6 +12,7 @@ # hi ... -+ - def h(): - ... - # bye +-def h(): +- ... +- # bye ++# FIXME(#8905): Uncomment, leads to unstable formatting ++# def h(): ++# ... ++# # bye ``` ## Ruff Output @@ -68,28 +60,21 @@ def h(): def f(): # type: ignore ... - class x: # some comment ... - - -class y: - ... # comment - +class y: ... # comment # whitespace doesn't matter (note the next line has a trailing space and tab) -class z: - ... - +class z: ... def g(): # hi ... - -def h(): - ... - # bye +# FIXME(#8905): Uncomment, leads to unstable formatting +# def h(): +# ... +# # bye ``` ## Black Output diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_basic.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_basic.py.snap new file mode 100644 index 0000000000000..a37d5fec5ad81 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_basic.py.snap @@ -0,0 +1,317 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_basic.py +--- +## Input + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. +def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass +def foo2(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass +def foo3(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass +def foo4(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass + +# Adding some unformated code covering a wide range of syntaxes. + +if True: + # Incorrectly indented prefix comments. + pass + +import typing +from typing import ( + Any , + ) +class MyClass( object): # Trailing comment with extra leading space. + #NOTE: The following indentation is incorrect: + @decor( 1 * 3 ) + def my_func( arg): + pass + +try: # Trailing comment with extra leading space. + for i in range(10): # Trailing comment with extra leading space. + while condition: + if something: + then_something( ) + elif something_else: + then_something_else( ) +except ValueError as e: + unformatted( ) +finally: + unformatted( ) + +async def test_async_unformatted( ): # Trailing comment with extra leading space. + async for i in some_iter( unformatted ): # Trailing comment with extra leading space. + await asyncio.sleep( 1 ) + async with some_context( unformatted ): + print( "unformatted" ) +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,7 +1,17 @@ +-# flags: --line-ranges=5-6 + # NOTE: If you need to modify this file, pay special attention to the --line-ranges= + # flag above as it's formatting specifically these lines. +-def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass ++def foo1( ++ parameter_1, ++ parameter_2, ++ parameter_3, ++ parameter_4, ++ parameter_5, ++ parameter_6, ++ parameter_7, ++): ++ pass ++ ++ + def foo2( + parameter_1, + parameter_2, +@@ -26,38 +36,52 @@ + pass + + +-def foo4(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass ++def foo4( ++ parameter_1, ++ parameter_2, ++ parameter_3, ++ parameter_4, ++ parameter_5, ++ parameter_6, ++ parameter_7, ++): ++ pass ++ + + # Adding some unformated code covering a wide range of syntaxes. + + if True: +- # Incorrectly indented prefix comments. +- pass ++ # Incorrectly indented prefix comments. ++ pass ++ ++import typing ++from typing import ( ++ Any, ++) ++ ++ ++class MyClass(object): # Trailing comment with extra leading space. ++ # NOTE: The following indentation is incorrect: ++ @decor(1 * 3) ++ def my_func(arg): ++ pass + +-import typing +-from typing import ( +- Any , +- ) +-class MyClass( object): # Trailing comment with extra leading space. +- #NOTE: The following indentation is incorrect: +- @decor( 1 * 3 ) +- def my_func( arg): +- pass + +-try: # Trailing comment with extra leading space. +- for i in range(10): # Trailing comment with extra leading space. +- while condition: +- if something: +- then_something( ) +- elif something_else: +- then_something_else( ) +-except ValueError as e: +- unformatted( ) ++try: # Trailing comment with extra leading space. ++ for i in range(10): # Trailing comment with extra leading space. ++ while condition: ++ if something: ++ then_something() ++ elif something_else: ++ then_something_else() ++except ValueError as e: ++ unformatted() + finally: +- unformatted( ) ++ unformatted() ++ + +-async def test_async_unformatted( ): # Trailing comment with extra leading space. +- async for i in some_iter( unformatted ): # Trailing comment with extra leading space. +- await asyncio.sleep( 1 ) +- async with some_context( unformatted ): +- print( "unformatted" ) ++async def test_async_unformatted(): # Trailing comment with extra leading space. ++ async for i in some_iter(unformatted): # Trailing comment with extra leading space. ++ await asyncio.sleep(1) ++ async with some_context(unformatted): ++ print("unformatted") +``` + +## Ruff Output + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. +def foo1( + parameter_1, + parameter_2, + parameter_3, + parameter_4, + parameter_5, + parameter_6, + parameter_7, +): + pass + + +def foo2( + parameter_1, + parameter_2, + parameter_3, + parameter_4, + parameter_5, + parameter_6, + parameter_7, +): + pass + + +def foo3( + parameter_1, + parameter_2, + parameter_3, + parameter_4, + parameter_5, + parameter_6, + parameter_7, +): + pass + + +def foo4( + parameter_1, + parameter_2, + parameter_3, + parameter_4, + parameter_5, + parameter_6, + parameter_7, +): + pass + + +# Adding some unformated code covering a wide range of syntaxes. + +if True: + # Incorrectly indented prefix comments. + pass + +import typing +from typing import ( + Any, +) + + +class MyClass(object): # Trailing comment with extra leading space. + # NOTE: The following indentation is incorrect: + @decor(1 * 3) + def my_func(arg): + pass + + +try: # Trailing comment with extra leading space. + for i in range(10): # Trailing comment with extra leading space. + while condition: + if something: + then_something() + elif something_else: + then_something_else() +except ValueError as e: + unformatted() +finally: + unformatted() + + +async def test_async_unformatted(): # Trailing comment with extra leading space. + async for i in some_iter(unformatted): # Trailing comment with extra leading space. + await asyncio.sleep(1) + async with some_context(unformatted): + print("unformatted") +``` + +## Black Output + +```python +# flags: --line-ranges=5-6 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. +def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass +def foo2( + parameter_1, + parameter_2, + parameter_3, + parameter_4, + parameter_5, + parameter_6, + parameter_7, +): + pass + + +def foo3( + parameter_1, + parameter_2, + parameter_3, + parameter_4, + parameter_5, + parameter_6, + parameter_7, +): + pass + + +def foo4(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass + +# Adding some unformated code covering a wide range of syntaxes. + +if True: + # Incorrectly indented prefix comments. + pass + +import typing +from typing import ( + Any , + ) +class MyClass( object): # Trailing comment with extra leading space. + #NOTE: The following indentation is incorrect: + @decor( 1 * 3 ) + def my_func( arg): + pass + +try: # Trailing comment with extra leading space. + for i in range(10): # Trailing comment with extra leading space. + while condition: + if something: + then_something( ) + elif something_else: + then_something_else( ) +except ValueError as e: + unformatted( ) +finally: + unformatted( ) + +async def test_async_unformatted( ): # Trailing comment with extra leading space. + async for i in some_iter( unformatted ): # Trailing comment with extra leading space. + await asyncio.sleep( 1 ) + async with some_context( unformatted ): + print( "unformatted" ) +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_diff_edge_case.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_diff_edge_case.py.snap new file mode 100644 index 0000000000000..ee8fb11d45870 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_diff_edge_case.py.snap @@ -0,0 +1,79 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_diff_edge_case.py +--- +## Input + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# Reproducible example for https://github.com/psf/black/issues/4033. +# This can be fixed in the future if we use a better diffing algorithm, or make Black +# perform formatting in a single pass. + +print ( "format me" ) +print ( "format me" ) +print ( "format me" ) +print ( "format me" ) +print ( "format me" ) +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,4 +1,3 @@ +-# flags: --line-ranges=10-11 + # NOTE: If you need to modify this file, pay special attention to the --line-ranges= + # flag above as it's formatting specifically these lines. + +@@ -6,8 +5,8 @@ + # This can be fixed in the future if we use a better diffing algorithm, or make Black + # perform formatting in a single pass. + +-print ( "format me" ) + print("format me") + print("format me") + print("format me") + print("format me") ++print("format me") +``` + +## Ruff Output + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# Reproducible example for https://github.com/psf/black/issues/4033. +# This can be fixed in the future if we use a better diffing algorithm, or make Black +# perform formatting in a single pass. + +print("format me") +print("format me") +print("format me") +print("format me") +print("format me") +``` + +## Black Output + +```python +# flags: --line-ranges=10-11 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# Reproducible example for https://github.com/psf/black/issues/4033. +# This can be fixed in the future if we use a better diffing algorithm, or make Black +# perform formatting in a single pass. + +print ( "format me" ) +print("format me") +print("format me") +print("format me") +print("format me") +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off.py.snap new file mode 100644 index 0000000000000..119237fb5d4af --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off.py.snap @@ -0,0 +1,114 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off.py +--- +## Input + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# fmt: off +import os +def myfunc( ): # Intentionally unformatted. + pass +# fmt: on + + +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: off +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: on + + +def myfunc( ): # This will be reformatted. + print( {"this will be reformatted"} ) +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,4 +1,3 @@ +-# flags: --line-ranges=7-7 --line-ranges=17-23 + # NOTE: If you need to modify this file, pay special attention to the --line-ranges= + # flag above as it's formatting specifically these lines. + +@@ -9,8 +8,10 @@ + # fmt: on + + +-def myfunc( ): # This will not be reformatted. +- print( {"also won't be reformatted"} ) ++def myfunc(): # This will not be reformatted. ++ print({"also won't be reformatted"}) ++ ++ + # fmt: off + def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +``` + +## Ruff Output + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# fmt: off +import os +def myfunc( ): # Intentionally unformatted. + pass +# fmt: on + + +def myfunc(): # This will not be reformatted. + print({"also won't be reformatted"}) + + +# fmt: off +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: on + + +def myfunc(): # This will be reformatted. + print({"this will be reformatted"}) +``` + +## Black Output + +```python +# flags: --line-ranges=7-7 --line-ranges=17-23 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# fmt: off +import os +def myfunc( ): # Intentionally unformatted. + pass +# fmt: on + + +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: off +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: on + + +def myfunc(): # This will be reformatted. + print({"this will be reformatted"}) +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off_decorator.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off_decorator.py.snap new file mode 100644 index 0000000000000..4ac42448f3593 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off_decorator.py.snap @@ -0,0 +1,74 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py +--- +## Input + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# Regression test for an edge case involving decorators and fmt: off/on. +class MyClass: + + # fmt: off + @decorator ( ) + # fmt: on + def method(): + print ( "str" ) +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,12 +1,10 @@ +-# flags: --line-ranges=12-12 + # NOTE: If you need to modify this file, pay special attention to the --line-ranges= + # flag above as it's formatting specifically these lines. + + # Regression test for an edge case involving decorators and fmt: off/on. + class MyClass: +- + # fmt: off + @decorator ( ) + # fmt: on + def method(): +- print("str") ++ print ( "str" ) +``` + +## Ruff Output + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# Regression test for an edge case involving decorators and fmt: off/on. +class MyClass: + # fmt: off + @decorator ( ) + # fmt: on + def method(): + print ( "str" ) +``` + +## Black Output + +```python +# flags: --line-ranges=12-12 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# Regression test for an edge case involving decorators and fmt: off/on. +class MyClass: + + # fmt: off + @decorator ( ) + # fmt: on + def method(): + print("str") +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off_overlap.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off_overlap.py.snap new file mode 100644 index 0000000000000..5130df3f7cd32 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off_overlap.py.snap @@ -0,0 +1,93 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_overlap.py +--- +## Input + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + + +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: off +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: on + + +def myfunc( ): # This will be reformatted. + print( {"this will be reformatted"} ) +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,10 +1,11 @@ +-# flags: --line-ranges=11-17 + # NOTE: If you need to modify this file, pay special attention to the --line-ranges= + # flag above as it's formatting specifically these lines. + + +-def myfunc( ): # This will not be reformatted. +- print( {"also won't be reformatted"} ) ++def myfunc(): # This will not be reformatted. ++ print({"also won't be reformatted"}) ++ ++ + # fmt: off + def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +``` + +## Ruff Output + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + + +def myfunc(): # This will not be reformatted. + print({"also won't be reformatted"}) + + +# fmt: off +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: on + + +def myfunc(): # This will be reformatted. + print({"this will be reformatted"}) +``` + +## Black Output + +```python +# flags: --line-ranges=11-17 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + + +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: off +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +def myfunc( ): # This will not be reformatted. + print( {"also won't be reformatted"} ) +# fmt: on + + +def myfunc(): # This will be reformatted. + print({"this will be reformatted"}) +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_indentation.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_indentation.py.snap new file mode 100644 index 0000000000000..53fac2515565b --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_indentation.py.snap @@ -0,0 +1,72 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_indentation.py +--- +## Input + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. +if cond1: + print("first") + if cond2: + print("second") + else: + print("else") + +if another_cond: + print("will not be changed") +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,4 +1,3 @@ +-# flags: --line-ranges=5-5 + # NOTE: If you need to modify this file, pay special attention to the --line-ranges= + # flag above as it's formatting specifically these lines. + if cond1: +@@ -9,4 +8,4 @@ + print("else") + + if another_cond: +- print("will not be changed") ++ print("will not be changed") +``` + +## Ruff Output + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. +if cond1: + print("first") + if cond2: + print("second") + else: + print("else") + +if another_cond: + print("will not be changed") +``` + +## Black Output + +```python +# flags: --line-ranges=5-5 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. +if cond1: + print("first") + if cond2: + print("second") + else: + print("else") + +if another_cond: + print("will not be changed") +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_two_passes.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_two_passes.py.snap new file mode 100644 index 0000000000000..b12db8172060f --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_two_passes.py.snap @@ -0,0 +1,77 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_two_passes.py +--- +## Input + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# This is a specific case for Black's two-pass formatting behavior in `format_str`. +# The second pass must respect the line ranges before the first pass. + + +def restrict_to_this_line(arg1, + arg2, + arg3): + print ( "This should not be formatted." ) + print ( "Note that in the second pass, the original line range 9-11 will cover these print lines.") +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,4 +1,3 @@ +-# flags: --line-ranges=9-11 + # NOTE: If you need to modify this file, pay special attention to the --line-ranges= + # flag above as it's formatting specifically these lines. + +@@ -7,5 +6,7 @@ + + + def restrict_to_this_line(arg1, arg2, arg3): +- print ( "This should not be formatted." ) +- print ( "Note that in the second pass, the original line range 9-11 will cover these print lines.") ++ print("This should not be formatted.") ++ print( ++ "Note that in the second pass, the original line range 9-11 will cover these print lines." ++ ) +``` + +## Ruff Output + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# This is a specific case for Black's two-pass formatting behavior in `format_str`. +# The second pass must respect the line ranges before the first pass. + + +def restrict_to_this_line(arg1, arg2, arg3): + print("This should not be formatted.") + print( + "Note that in the second pass, the original line range 9-11 will cover these print lines." + ) +``` + +## Black Output + +```python +# flags: --line-ranges=9-11 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. + +# This is a specific case for Black's two-pass formatting behavior in `format_str`. +# The second pass must respect the line ranges before the first pass. + + +def restrict_to_this_line(arg1, arg2, arg3): + print ( "This should not be formatted." ) + print ( "Note that in the second pass, the original line range 9-11 will cover these print lines.") +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_unwrapping.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_unwrapping.py.snap new file mode 100644 index 0000000000000..02466fbfa2f8a --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_unwrapping.py.snap @@ -0,0 +1,60 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_unwrapping.py +--- +## Input + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. +alist = [ + 1, 2 +] + +adict = { + "key" : "value" +} + +func_call ( + arg = value +) +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,4 +1,3 @@ +-# flags: --line-ranges=5-5 --line-ranges=9-9 --line-ranges=13-13 + # NOTE: If you need to modify this file, pay special attention to the --line-ranges= + # flag above as it's formatting specifically these lines. + alist = [1, 2] +``` + +## Ruff Output + +```python +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. +alist = [1, 2] + +adict = {"key": "value"} + +func_call(arg=value) +``` + +## Black Output + +```python +# flags: --line-ranges=5-5 --line-ranges=9-9 --line-ranges=13-13 +# NOTE: If you need to modify this file, pay special attention to the --line-ranges= +# flag above as it's formatting specifically these lines. +alist = [1, 2] + +adict = {"key": "value"} + +func_call(arg=value) +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__long_strings_flag_disabled.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__long_strings_flag_disabled.py.snap similarity index 99% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__long_strings_flag_disabled.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__long_strings_flag_disabled.py.snap index 554b9b0fb365a..47c71cf9a2863 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__long_strings_flag_disabled.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__long_strings_flag_disabled.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/long_strings_flag_disabled.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/long_strings_flag_disabled.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__multiline_consecutive_open_parentheses_ignore.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__multiline_consecutive_open_parentheses_ignore.py.snap similarity index 95% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__multiline_consecutive_open_parentheses_ignore.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__multiline_consecutive_open_parentheses_ignore.py.snap index 66ce78e5b1d94..45a41abfe2ea4 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__multiline_consecutive_open_parentheses_ignore.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__multiline_consecutive_open_parentheses_ignore.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/multiline_consecutive_open_parentheses_ignore.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/multiline_consecutive_open_parentheses_ignore.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__nested_stub.pyi.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__nested_stub.pyi.snap new file mode 100644 index 0000000000000..9ebdd53453119 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__nested_stub.pyi.snap @@ -0,0 +1,126 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/nested_stub.pyi +--- +## Input + +```python +import sys + +class Outer: + class InnerStub: ... + outer_attr_after_inner_stub: int + class Inner: + inner_attr: int + outer_attr: int + +if sys.version_info > (3, 7): + if sys.platform == "win32": + assignment = 1 + def function_definition(self): ... + def f1(self) -> str: ... + if sys.platform != "win32": + def function_definition(self): ... + assignment = 1 + def f2(self) -> str: ... +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,7 +1,9 @@ + import sys + ++ + class Outer: + class InnerStub: ... ++ + outer_attr_after_inner_stub: int + + class Inner: +@@ -9,14 +11,19 @@ + + outer_attr: int + ++ + if sys.version_info > (3, 7): + if sys.platform == "win32": + assignment = 1 ++ + def function_definition(self): ... + + def f1(self) -> str: ... ++ + if sys.platform != "win32": ++ + def function_definition(self): ... ++ + assignment = 1 + + def f2(self) -> str: ... +``` + +## Ruff Output + +```python +import sys + + +class Outer: + class InnerStub: ... + + outer_attr_after_inner_stub: int + + class Inner: + inner_attr: int + + outer_attr: int + + +if sys.version_info > (3, 7): + if sys.platform == "win32": + assignment = 1 + + def function_definition(self): ... + + def f1(self) -> str: ... + + if sys.platform != "win32": + + def function_definition(self): ... + + assignment = 1 + + def f2(self) -> str: ... +``` + +## Black Output + +```python +import sys + +class Outer: + class InnerStub: ... + outer_attr_after_inner_stub: int + + class Inner: + inner_attr: int + + outer_attr: int + +if sys.version_info > (3, 7): + if sys.platform == "win32": + assignment = 1 + def function_definition(self): ... + + def f1(self) -> str: ... + if sys.platform != "win32": + def function_definition(self): ... + assignment = 1 + + def f2(self) -> str: ... +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_style.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pattern_matching_style.py.snap similarity index 98% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_style.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pattern_matching_style.py.snap index 51669107f8a53..06422b3718754 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_style.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pattern_matching_style.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_style.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_style.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pep604_union_types_line_breaks.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pep604_union_types_line_breaks.py.snap new file mode 100644 index 0000000000000..278a20e4a6650 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pep604_union_types_line_breaks.py.snap @@ -0,0 +1,370 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.py +--- +## Input + +```python +# This has always worked +z= Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong + +# "AnnAssign"s now also work +z: Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong +z: (Short + | Short2 + | Short3 + | Short4) +z: (int) +z: ((int)) + + +z: Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong = 7 +z: (Short + | Short2 + | Short3 + | Short4) = 8 +z: (int) = 2.3 +z: ((int)) = foo() + +# In case I go for not enforcing parantheses, this might get improved at the same time +x = ( + z + == 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999, + y + == 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999, +) + +x = ( + z == (9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999), + y == (9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999), +) + +# handle formatting of "tname"s in parameter list + +# remove unnecessary paren +def foo(i: (int)) -> None: ... + + +# this is a syntax error in the type annotation according to mypy, but it's not invalid *python* code, so make sure we don't mess with it and make it so. +def foo(i: (int,)) -> None: ... + +def foo( + i: int, + x: Loooooooooooooooooooooooong + | Looooooooooooooooong + | Looooooooooooooooooooong + | Looooooong, + *, + s: str, +) -> None: + pass + + +@app.get("/path/") +async def foo( + q: str + | None = Query(None, title="Some long title", description="Some long description") +): + pass + + +def f( + max_jobs: int + | None = Option( + None, help="Maximum number of jobs to launch. And some additional text." + ), + another_option: bool = False + ): + ... +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -7,26 +7,16 @@ + ) + + # "AnnAssign"s now also work +-z: ( +- Loooooooooooooooooooooooong +- | Loooooooooooooooooooooooong +- | Loooooooooooooooooooooooong +- | Loooooooooooooooooooooooong +-) +-z: Short | Short2 | Short3 | Short4 +-z: int +-z: int ++z: Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong ++z: (Short | Short2 | Short3 | Short4) ++z: (int) ++z: (int) + + +-z: ( +- Loooooooooooooooooooooooong +- | Loooooooooooooooooooooooong +- | Loooooooooooooooooooooooong +- | Loooooooooooooooooooooooong +-) = 7 +-z: Short | Short2 | Short3 | Short4 = 8 +-z: int = 2.3 +-z: int = foo() ++z: Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong = 7 ++z: (Short | Short2 | Short3 | Short4) = 8 ++z: (int) = 2.3 ++z: (int) = foo() + + # In case I go for not enforcing parantheses, this might get improved at the same time + x = ( +@@ -63,7 +53,7 @@ + + + # remove unnecessary paren +-def foo(i: int) -> None: ... ++def foo(i: (int)) -> None: ... + + + # this is a syntax error in the type annotation according to mypy, but it's not invalid *python* code, so make sure we don't mess with it and make it so. +@@ -72,12 +62,10 @@ + + def foo( + i: int, +- x: ( +- Loooooooooooooooooooooooong +- | Looooooooooooooooong +- | Looooooooooooooooooooong +- | Looooooong +- ), ++ x: Loooooooooooooooooooooooong ++ | Looooooooooooooooong ++ | Looooooooooooooooooooong ++ | Looooooong, + *, + s: str, + ) -> None: +@@ -88,7 +76,7 @@ + async def foo( + q: str | None = Query( + None, title="Some long title", description="Some long description" +- ) ++ ), + ): + pass + +``` + +## Ruff Output + +```python +# This has always worked +z = ( + Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong +) + +# "AnnAssign"s now also work +z: Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong +z: (Short | Short2 | Short3 | Short4) +z: (int) +z: (int) + + +z: Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong = 7 +z: (Short | Short2 | Short3 | Short4) = 8 +z: (int) = 2.3 +z: (int) = foo() + +# In case I go for not enforcing parantheses, this might get improved at the same time +x = ( + z + == 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999, + y + == 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999, +) + +x = ( + z + == ( + 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + ), + y + == ( + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + ), +) + +# handle formatting of "tname"s in parameter list + + +# remove unnecessary paren +def foo(i: (int)) -> None: ... + + +# this is a syntax error in the type annotation according to mypy, but it's not invalid *python* code, so make sure we don't mess with it and make it so. +def foo(i: (int,)) -> None: ... + + +def foo( + i: int, + x: Loooooooooooooooooooooooong + | Looooooooooooooooong + | Looooooooooooooooooooong + | Looooooong, + *, + s: str, +) -> None: + pass + + +@app.get("/path/") +async def foo( + q: str | None = Query( + None, title="Some long title", description="Some long description" + ), +): + pass + + +def f( + max_jobs: int | None = Option( + None, help="Maximum number of jobs to launch. And some additional text." + ), + another_option: bool = False, +): ... +``` + +## Black Output + +```python +# This has always worked +z = ( + Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong +) + +# "AnnAssign"s now also work +z: ( + Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong +) +z: Short | Short2 | Short3 | Short4 +z: int +z: int + + +z: ( + Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong + | Loooooooooooooooooooooooong +) = 7 +z: Short | Short2 | Short3 | Short4 = 8 +z: int = 2.3 +z: int = foo() + +# In case I go for not enforcing parantheses, this might get improved at the same time +x = ( + z + == 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999, + y + == 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999, +) + +x = ( + z + == ( + 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + | 9999999999999999999999999999999999999999 + ), + y + == ( + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + + 9999999999999999999999999999999999999999 + ), +) + +# handle formatting of "tname"s in parameter list + + +# remove unnecessary paren +def foo(i: int) -> None: ... + + +# this is a syntax error in the type annotation according to mypy, but it's not invalid *python* code, so make sure we don't mess with it and make it so. +def foo(i: (int,)) -> None: ... + + +def foo( + i: int, + x: ( + Loooooooooooooooooooooooong + | Looooooooooooooooong + | Looooooooooooooooooooong + | Looooooong + ), + *, + s: str, +) -> None: + pass + + +@app.get("/path/") +async def foo( + q: str | None = Query( + None, title="Some long title", description="Some long description" + ) +): + pass + + +def f( + max_jobs: int | None = Option( + None, help="Maximum number of jobs to launch. And some additional text." + ), + another_option: bool = False, +): ... +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pep_572_py310.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pep_572_py310.py.snap similarity index 98% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pep_572_py310.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pep_572_py310.py.snap index b694f46cfdfaa..a49397f429243 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pep_572_py310.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pep_572_py310.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pep_572_py310.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_py310.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_38__pep_572_remove_parens.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pep_572_remove_parens.py.snap similarity index 98% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_38__pep_572_remove_parens.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pep_572_remove_parens.py.snap index 49c78e65597e9..ac78124cef0f4 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_38__pep_572_remove_parens.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pep_572_remove_parens.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/py_38/pep_572_remove_parens.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_remove_parens.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__power_op_newline.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__power_op_newline.py.snap similarity index 91% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__power_op_newline.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__power_op_newline.py.snap index b9ff9703eb179..1796017091aa5 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__power_op_newline.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__power_op_newline.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/power_op_newline.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_newline.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_allow_empty_first_line_in_special_cases.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_allow_empty_first_line_in_special_cases.py.snap new file mode 100644 index 0000000000000..2dce9bc3af03b --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_allow_empty_first_line_in_special_cases.py.snap @@ -0,0 +1,218 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_allow_empty_first_line_in_special_cases.py +--- +## Input + +```python +def foo(): + """ + Docstring + """ + + # Here we go + if x: + + # This is also now fine + a = 123 + + else: + # But not necessary + a = 123 + + if y: + + while True: + + """ + Long comment here + """ + a = 123 + + if z: + + for _ in range(100): + a = 123 + else: + + try: + + # this should be ok + a = 123 + except: + + """also this""" + a = 123 + + +def bar(): + + if x: + a = 123 + + +def baz(): + + # OK + if x: + a = 123 +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -5,7 +5,6 @@ + + # Here we go + if x: +- + # This is also now fine + a = 123 + +@@ -14,38 +13,30 @@ + a = 123 + + if y: +- + while True: +- + """ + Long comment here + """ + a = 123 + + if z: +- + for _ in range(100): + a = 123 + else: +- + try: +- + # this should be ok + a = 123 + except: +- + """also this""" + a = 123 + + + def bar(): +- + if x: + a = 123 + + + def baz(): +- + # OK + if x: + a = 123 +``` + +## Ruff Output + +```python +def foo(): + """ + Docstring + """ + + # Here we go + if x: + # This is also now fine + a = 123 + + else: + # But not necessary + a = 123 + + if y: + while True: + """ + Long comment here + """ + a = 123 + + if z: + for _ in range(100): + a = 123 + else: + try: + # this should be ok + a = 123 + except: + """also this""" + a = 123 + + +def bar(): + if x: + a = 123 + + +def baz(): + # OK + if x: + a = 123 +``` + +## Black Output + +```python +def foo(): + """ + Docstring + """ + + # Here we go + if x: + + # This is also now fine + a = 123 + + else: + # But not necessary + a = 123 + + if y: + + while True: + + """ + Long comment here + """ + a = 123 + + if z: + + for _ in range(100): + a = 123 + else: + + try: + + # this should be ok + a = 123 + except: + + """also this""" + a = 123 + + +def bar(): + + if x: + a = 123 + + +def baz(): + + # OK + if x: + a = 123 +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_cantfit.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_cantfit.py.snap new file mode 100644 index 0000000000000..c22c4b6ea4a72 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_cantfit.py.snap @@ -0,0 +1,219 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_cantfit.py +--- +## Input + +```python +# long variable name +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = 0 +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = 1 # with a comment +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = [ + 1, 2, 3 +] +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function() +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + arg1, arg2, arg3 +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 +) +# long function name +normal_name = but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying() +normal_name = but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying( + arg1, arg2, arg3 +) +normal_name = but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 +) +# long arguments +normal_name = normal_function_name( + "but with super long string arguments that on their own exceed the line limit so there's no way it can ever fit", + "eggs with spam and eggs and spam with eggs with spam and eggs and spam with eggs with spam and eggs and spam with eggs", + this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it=0, +) +string_variable_name = ( + "a string that is waaaaaaaayyyyyyyy too long, even in parens, there's nothing you can do" # noqa +) +for key in """ + hostname + port + username +""".split(): + if key in self.connect_kwargs: + raise ValueError(err.format(key)) +concatenated_strings = "some strings that are " "concatenated implicitly, so if you put them on separate " "lines it will fit" +del concatenated_strings, string_variable_name, normal_function_name, normal_name, need_more_to_make_the_line_long_enough +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,18 +1,12 @@ + # long variable name +-this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = ( +- 0 +-) +-this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = ( +- 1 # with a comment +-) ++this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = 0 ++this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = 1 # with a comment + this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = [ + 1, + 2, + 3, + ] +-this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = ( +- function() +-) ++this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function() + this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + arg1, arg2, arg3 + ) +@@ -35,10 +29,8 @@ + ) + # long arguments + normal_name = normal_function_name( +- "but with super long string arguments that on their own exceed the line limit so" +- " there's no way it can ever fit", +- "eggs with spam and eggs and spam with eggs with spam and eggs and spam with eggs" +- " with spam and eggs and spam with eggs", ++ "but with super long string arguments that on their own exceed the line limit so there's no way it can ever fit", ++ "eggs with spam and eggs and spam with eggs with spam and eggs and spam with eggs with spam and eggs and spam with eggs", + this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it=0, + ) + string_variable_name = "a string that is waaaaaaaayyyyyyyy too long, even in parens, there's nothing you can do" # noqa +``` + +## Ruff Output + +```python +# long variable name +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = 0 +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = 1 # with a comment +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = [ + 1, + 2, + 3, +] +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function() +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + arg1, arg2, arg3 +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 +) +# long function name +normal_name = ( + but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying() +) +normal_name = ( + but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying( + arg1, arg2, arg3 + ) +) +normal_name = ( + but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 + ) +) +# long arguments +normal_name = normal_function_name( + "but with super long string arguments that on their own exceed the line limit so there's no way it can ever fit", + "eggs with spam and eggs and spam with eggs with spam and eggs and spam with eggs with spam and eggs and spam with eggs", + this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it=0, +) +string_variable_name = "a string that is waaaaaaaayyyyyyyy too long, even in parens, there's nothing you can do" # noqa +for key in """ + hostname + port + username +""".split(): + if key in self.connect_kwargs: + raise ValueError(err.format(key)) +concatenated_strings = ( + "some strings that are " + "concatenated implicitly, so if you put them on separate " + "lines it will fit" +) +del ( + concatenated_strings, + string_variable_name, + normal_function_name, + normal_name, + need_more_to_make_the_line_long_enough, +) +``` + +## Black Output + +```python +# long variable name +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = ( + 0 +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = ( + 1 # with a comment +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = [ + 1, + 2, + 3, +] +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = ( + function() +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + arg1, arg2, arg3 +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 +) +# long function name +normal_name = ( + but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying() +) +normal_name = ( + but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying( + arg1, arg2, arg3 + ) +) +normal_name = ( + but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 + ) +) +# long arguments +normal_name = normal_function_name( + "but with super long string arguments that on their own exceed the line limit so" + " there's no way it can ever fit", + "eggs with spam and eggs and spam with eggs with spam and eggs and spam with eggs" + " with spam and eggs and spam with eggs", + this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it=0, +) +string_variable_name = "a string that is waaaaaaaayyyyyyyy too long, even in parens, there's nothing you can do" # noqa +for key in """ + hostname + port + username +""".split(): + if key in self.connect_kwargs: + raise ValueError(err.format(key)) +concatenated_strings = ( + "some strings that are " + "concatenated implicitly, so if you put them on separate " + "lines it will fit" +) +del ( + concatenated_strings, + string_variable_name, + normal_function_name, + normal_name, + need_more_to_make_the_line_long_enough, +) +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_comments7.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_comments7.py.snap new file mode 100644 index 0000000000000..337c78698d551 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_comments7.py.snap @@ -0,0 +1,600 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_comments7.py +--- +## Input + +```python +from .config import ( + Any, + Bool, + ConfigType, + ConfigTypeAttributes, + Int, + Path, + # String, + # resolve_to_config_type, + # DEFAULT_TYPE_ATTRIBUTES, +) + + +from .config import ( + Any, + Bool, + ConfigType, + ConfigTypeAttributes, + Int, + no_comma_here_yet + # and some comments, + # resolve_to_config_type, + # DEFAULT_TYPE_ATTRIBUTES, +) +from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( + MyLovelyCompanyTeamProjectComponent # NOT DRY +) +from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( + MyLovelyCompanyTeamProjectComponent as component # DRY +) + + +result = 1 # look ma, no comment migration xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +result = ( + 1 # look ma, no comment migration xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +) + +result = ( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # aaa +) + +result = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # aaa + + +def func(): + c = call( + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0789, + a[-1], # type: ignore + ) + c = call( + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0789, + a[-1] # type: ignore + ) + c = call( + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0456, + 0.0789, + a[-1] # type: ignore + ) + + # The type: ignore exception only applies to line length, not + # other types of formatting. + c = call( + "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", # type: ignore + "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" + ) + + +class C: + @pytest.mark.parametrize( + ("post_data", "message"), + [ + # metadata_version errors. + ( + {}, + "None is an invalid value for Metadata-Version. Error: This field is" + " required. see" + " https://packaging.python.org/specifications/core-metadata" + ), + ( + {"metadata_version": "-1"}, + "'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata" + " Version see" + " https://packaging.python.org/specifications/core-metadata" + ), + # name errors. + ( + {"metadata_version": "1.2"}, + "'' is an invalid value for Name. Error: This field is required. see" + " https://packaging.python.org/specifications/core-metadata" + ), + ( + {"metadata_version": "1.2", "name": "foo-"}, + "'foo-' is an invalid value for Name. Error: Must start and end with a" + " letter or numeral and contain only ascii numeric and '.', '_' and" + " '-'. see https://packaging.python.org/specifications/core-metadata" + ), + # version errors. + ( + {"metadata_version": "1.2", "name": "example"}, + "'' is an invalid value for Version. Error: This field is required. see" + " https://packaging.python.org/specifications/core-metadata" + ), + ( + {"metadata_version": "1.2", "name": "example", "version": "dog"}, + "'dog' is an invalid value for Version. Error: Must start and end with" + " a letter or numeral and contain only ascii numeric and '.', '_' and" + " '-'. see https://packaging.python.org/specifications/core-metadata" + ) + ] + ) + def test_fails_invalid_post_data( + self, pyramid_config, db_request, post_data, message + ): + ... + +square = Square(4) # type: Optional[Square] + +# Regression test for https://github.com/psf/black/issues/3756. +[ + ( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ), +] +[ + ( # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ), +] +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -34,13 +34,9 @@ + + result = 1 # look ma, no comment migration xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +-result = ( # aaa +- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +-) ++result = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # aaa + +-result = ( # aaa +- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +-) ++result = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # aaa + + + def func(): +@@ -52,12 +48,19 @@ + 0.0789, + a[-1], # type: ignore + ) +- c = call(0.0123, 0.0456, 0.0789, 0.0123, 0.0789, a[-1]) # type: ignore + c = call( + 0.0123, + 0.0456, + 0.0789, + 0.0123, ++ 0.0789, ++ a[-1], # type: ignore ++ ) ++ c = call( ++ 0.0123, ++ 0.0456, ++ 0.0789, ++ 0.0123, + 0.0456, + 0.0789, + 0.0123, +@@ -91,53 +94,39 @@ + # metadata_version errors. + ( + {}, +- ( +- "None is an invalid value for Metadata-Version. Error: This field" +- " is required. see" +- " https://packaging.python.org/specifications/core-metadata" +- ), ++ "None is an invalid value for Metadata-Version. Error: This field is" ++ " required. see" ++ " https://packaging.python.org/specifications/core-metadata", + ), + ( + {"metadata_version": "-1"}, +- ( +- "'-1' is an invalid value for Metadata-Version. Error: Unknown" +- " Metadata Version see" +- " https://packaging.python.org/specifications/core-metadata" +- ), ++ "'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata" ++ " Version see" ++ " https://packaging.python.org/specifications/core-metadata", + ), + # name errors. + ( + {"metadata_version": "1.2"}, +- ( +- "'' is an invalid value for Name. Error: This field is required." +- " see https://packaging.python.org/specifications/core-metadata" +- ), ++ "'' is an invalid value for Name. Error: This field is required. see" ++ " https://packaging.python.org/specifications/core-metadata", + ), + ( + {"metadata_version": "1.2", "name": "foo-"}, +- ( +- "'foo-' is an invalid value for Name. Error: Must start and end" +- " with a letter or numeral and contain only ascii numeric and '.'," +- " '_' and '-'. see" +- " https://packaging.python.org/specifications/core-metadata" +- ), ++ "'foo-' is an invalid value for Name. Error: Must start and end with a" ++ " letter or numeral and contain only ascii numeric and '.', '_' and" ++ " '-'. see https://packaging.python.org/specifications/core-metadata", + ), + # version errors. + ( + {"metadata_version": "1.2", "name": "example"}, +- ( +- "'' is an invalid value for Version. Error: This field is required." +- " see https://packaging.python.org/specifications/core-metadata" +- ), ++ "'' is an invalid value for Version. Error: This field is required. see" ++ " https://packaging.python.org/specifications/core-metadata", + ), + ( + {"metadata_version": "1.2", "name": "example", "version": "dog"}, +- ( +- "'dog' is an invalid value for Version. Error: Must start and end" +- " with a letter or numeral and contain only ascii numeric and '.'," +- " '_' and '-'. see" +- " https://packaging.python.org/specifications/core-metadata" +- ), ++ "'dog' is an invalid value for Version. Error: Must start and end with" ++ " a letter or numeral and contain only ascii numeric and '.', '_' and" ++ " '-'. see https://packaging.python.org/specifications/core-metadata", + ), + ], + ) +@@ -150,8 +139,8 @@ + + # Regression test for https://github.com/psf/black/issues/3756. + [ +- ( # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ++ ( ++ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ), + ] + [ +``` + +## Ruff Output + +```python +from .config import ( + Any, + Bool, + ConfigType, + ConfigTypeAttributes, + Int, + Path, + # String, + # resolve_to_config_type, + # DEFAULT_TYPE_ATTRIBUTES, +) + + +from .config import ( + Any, + Bool, + ConfigType, + ConfigTypeAttributes, + Int, + no_comma_here_yet, + # and some comments, + # resolve_to_config_type, + # DEFAULT_TYPE_ATTRIBUTES, +) +from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( + MyLovelyCompanyTeamProjectComponent, # NOT DRY +) +from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( + MyLovelyCompanyTeamProjectComponent as component, # DRY +) + + +result = 1 # look ma, no comment migration xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +result = 1 # look ma, no comment migration xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +result = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # aaa + +result = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # aaa + + +def func(): + c = call( + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0789, + a[-1], # type: ignore + ) + c = call( + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0789, + a[-1], # type: ignore + ) + c = call( + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0456, + 0.0789, + a[-1], # type: ignore + ) + + # The type: ignore exception only applies to line length, not + # other types of formatting. + c = call( + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", # type: ignore + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + ) + + +class C: + @pytest.mark.parametrize( + ("post_data", "message"), + [ + # metadata_version errors. + ( + {}, + "None is an invalid value for Metadata-Version. Error: This field is" + " required. see" + " https://packaging.python.org/specifications/core-metadata", + ), + ( + {"metadata_version": "-1"}, + "'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata" + " Version see" + " https://packaging.python.org/specifications/core-metadata", + ), + # name errors. + ( + {"metadata_version": "1.2"}, + "'' is an invalid value for Name. Error: This field is required. see" + " https://packaging.python.org/specifications/core-metadata", + ), + ( + {"metadata_version": "1.2", "name": "foo-"}, + "'foo-' is an invalid value for Name. Error: Must start and end with a" + " letter or numeral and contain only ascii numeric and '.', '_' and" + " '-'. see https://packaging.python.org/specifications/core-metadata", + ), + # version errors. + ( + {"metadata_version": "1.2", "name": "example"}, + "'' is an invalid value for Version. Error: This field is required. see" + " https://packaging.python.org/specifications/core-metadata", + ), + ( + {"metadata_version": "1.2", "name": "example", "version": "dog"}, + "'dog' is an invalid value for Version. Error: Must start and end with" + " a letter or numeral and contain only ascii numeric and '.', '_' and" + " '-'. see https://packaging.python.org/specifications/core-metadata", + ), + ], + ) + def test_fails_invalid_post_data( + self, pyramid_config, db_request, post_data, message + ): ... + + +square = Square(4) # type: Optional[Square] + +# Regression test for https://github.com/psf/black/issues/3756. +[ + ( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ), +] +[ + ( # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ), +] +``` + +## Black Output + +```python +from .config import ( + Any, + Bool, + ConfigType, + ConfigTypeAttributes, + Int, + Path, + # String, + # resolve_to_config_type, + # DEFAULT_TYPE_ATTRIBUTES, +) + + +from .config import ( + Any, + Bool, + ConfigType, + ConfigTypeAttributes, + Int, + no_comma_here_yet, + # and some comments, + # resolve_to_config_type, + # DEFAULT_TYPE_ATTRIBUTES, +) +from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( + MyLovelyCompanyTeamProjectComponent, # NOT DRY +) +from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( + MyLovelyCompanyTeamProjectComponent as component, # DRY +) + + +result = 1 # look ma, no comment migration xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +result = 1 # look ma, no comment migration xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +result = ( # aaa + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +) + +result = ( # aaa + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +) + + +def func(): + c = call( + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0789, + a[-1], # type: ignore + ) + c = call(0.0123, 0.0456, 0.0789, 0.0123, 0.0789, a[-1]) # type: ignore + c = call( + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0456, + 0.0789, + a[-1], # type: ignore + ) + + # The type: ignore exception only applies to line length, not + # other types of formatting. + c = call( + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", # type: ignore + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + ) + + +class C: + @pytest.mark.parametrize( + ("post_data", "message"), + [ + # metadata_version errors. + ( + {}, + ( + "None is an invalid value for Metadata-Version. Error: This field" + " is required. see" + " https://packaging.python.org/specifications/core-metadata" + ), + ), + ( + {"metadata_version": "-1"}, + ( + "'-1' is an invalid value for Metadata-Version. Error: Unknown" + " Metadata Version see" + " https://packaging.python.org/specifications/core-metadata" + ), + ), + # name errors. + ( + {"metadata_version": "1.2"}, + ( + "'' is an invalid value for Name. Error: This field is required." + " see https://packaging.python.org/specifications/core-metadata" + ), + ), + ( + {"metadata_version": "1.2", "name": "foo-"}, + ( + "'foo-' is an invalid value for Name. Error: Must start and end" + " with a letter or numeral and contain only ascii numeric and '.'," + " '_' and '-'. see" + " https://packaging.python.org/specifications/core-metadata" + ), + ), + # version errors. + ( + {"metadata_version": "1.2", "name": "example"}, + ( + "'' is an invalid value for Version. Error: This field is required." + " see https://packaging.python.org/specifications/core-metadata" + ), + ), + ( + {"metadata_version": "1.2", "name": "example", "version": "dog"}, + ( + "'dog' is an invalid value for Version. Error: Must start and end" + " with a letter or numeral and contain only ascii numeric and '.'," + " '_' and '-'. see" + " https://packaging.python.org/specifications/core-metadata" + ), + ), + ], + ) + def test_fails_invalid_post_data( + self, pyramid_config, db_request, post_data, message + ): ... + + +square = Square(4) # type: Optional[Square] + +# Regression test for https://github.com/psf/black/issues/3756. +[ + ( # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + ), +] +[ + ( # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" # aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ), +] +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_39.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_39.py.snap new file mode 100644 index 0000000000000..ed87cfaba128d --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_39.py.snap @@ -0,0 +1,342 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_39.py +--- +## Input + +```python +with \ + make_context_manager1() as cm1, \ + make_context_manager2() as cm2, \ + make_context_manager3() as cm3, \ + make_context_manager4() as cm4 \ +: + pass + + +# Leading comment +with \ + make_context_manager1() as cm1, \ + make_context_manager2(), \ + make_context_manager3() as cm3, \ + make_context_manager4() \ +: + pass + + +with \ + new_new_new1() as cm1, \ + new_new_new2() \ +: + pass + + +with ( + new_new_new1() as cm1, + new_new_new2() +): + pass + + +# Leading comment. +with ( + # First comment. + new_new_new1() as cm1, + # Second comment. + new_new_new2() + # Last comment. +): + pass + + +with \ + this_is_a_very_long_call(looong_arg1=looong_value1, looong_arg2=looong_value2) as cm1, \ + this_is_a_very_long_call(looong_arg1=looong_value1, looong_arg2=looong_value2, looong_arg3=looong_value3, looong_arg4=looong_value4) as cm2 \ +: + pass + + +with mock.patch.object( + self.my_runner, "first_method", autospec=True +) as mock_run_adb, mock.patch.object( + self.my_runner, "second_method", autospec=True, return_value="foo" +): + pass + + +with xxxxxxxx.some_kind_of_method( + some_argument=[ + "first", + "second", + "third", + ] +).another_method() as cmd: + pass + + +async def func(): + async with \ + make_context_manager1() as cm1, \ + make_context_manager2() as cm2, \ + make_context_manager3() as cm3, \ + make_context_manager4() as cm4 \ + : + pass + + async with some_function( + argument1, argument2, argument3="some_value" + ) as some_cm, some_other_function( + argument1, argument2, argument3="some_value" + ): + pass +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,19 +1,9 @@ +-with ( +- make_context_manager1() as cm1, +- make_context_manager2() as cm2, +- make_context_manager3() as cm3, +- make_context_manager4() as cm4, +-): ++with make_context_manager1() as cm1, make_context_manager2() as cm2, make_context_manager3() as cm3, make_context_manager4() as cm4: + pass + + + # Leading comment +-with ( +- make_context_manager1() as cm1, +- make_context_manager2(), +- make_context_manager3() as cm3, +- make_context_manager4(), +-): ++with make_context_manager1() as cm1, make_context_manager2(), make_context_manager3() as cm3, make_context_manager4(): + pass + + +@@ -36,25 +26,21 @@ + pass + + +-with ( +- this_is_a_very_long_call( +- looong_arg1=looong_value1, looong_arg2=looong_value2 +- ) as cm1, +- this_is_a_very_long_call( +- looong_arg1=looong_value1, +- looong_arg2=looong_value2, +- looong_arg3=looong_value3, +- looong_arg4=looong_value4, +- ) as cm2, +-): ++with this_is_a_very_long_call( ++ looong_arg1=looong_value1, looong_arg2=looong_value2 ++) as cm1, this_is_a_very_long_call( ++ looong_arg1=looong_value1, ++ looong_arg2=looong_value2, ++ looong_arg3=looong_value3, ++ looong_arg4=looong_value4, ++) as cm2: + pass + + +-with ( +- mock.patch.object(self.my_runner, "first_method", autospec=True) as mock_run_adb, +- mock.patch.object( +- self.my_runner, "second_method", autospec=True, return_value="foo" +- ), ++with mock.patch.object( ++ self.my_runner, "first_method", autospec=True ++) as mock_run_adb, mock.patch.object( ++ self.my_runner, "second_method", autospec=True, return_value="foo" + ): + pass + +@@ -70,16 +56,10 @@ + + + async def func(): +- async with ( +- make_context_manager1() as cm1, +- make_context_manager2() as cm2, +- make_context_manager3() as cm3, +- make_context_manager4() as cm4, +- ): ++ async with make_context_manager1() as cm1, make_context_manager2() as cm2, make_context_manager3() as cm3, make_context_manager4() as cm4: + pass + +- async with ( +- some_function(argument1, argument2, argument3="some_value") as some_cm, +- some_other_function(argument1, argument2, argument3="some_value"), +- ): ++ async with some_function( ++ argument1, argument2, argument3="some_value" ++ ) as some_cm, some_other_function(argument1, argument2, argument3="some_value"): + pass +``` + +## Ruff Output + +```python +with make_context_manager1() as cm1, make_context_manager2() as cm2, make_context_manager3() as cm3, make_context_manager4() as cm4: + pass + + +# Leading comment +with make_context_manager1() as cm1, make_context_manager2(), make_context_manager3() as cm3, make_context_manager4(): + pass + + +with new_new_new1() as cm1, new_new_new2(): + pass + + +with new_new_new1() as cm1, new_new_new2(): + pass + + +# Leading comment. +with ( + # First comment. + new_new_new1() as cm1, + # Second comment. + new_new_new2(), + # Last comment. +): + pass + + +with this_is_a_very_long_call( + looong_arg1=looong_value1, looong_arg2=looong_value2 +) as cm1, this_is_a_very_long_call( + looong_arg1=looong_value1, + looong_arg2=looong_value2, + looong_arg3=looong_value3, + looong_arg4=looong_value4, +) as cm2: + pass + + +with mock.patch.object( + self.my_runner, "first_method", autospec=True +) as mock_run_adb, mock.patch.object( + self.my_runner, "second_method", autospec=True, return_value="foo" +): + pass + + +with xxxxxxxx.some_kind_of_method( + some_argument=[ + "first", + "second", + "third", + ] +).another_method() as cmd: + pass + + +async def func(): + async with make_context_manager1() as cm1, make_context_manager2() as cm2, make_context_manager3() as cm3, make_context_manager4() as cm4: + pass + + async with some_function( + argument1, argument2, argument3="some_value" + ) as some_cm, some_other_function(argument1, argument2, argument3="some_value"): + pass +``` + +## Black Output + +```python +with ( + make_context_manager1() as cm1, + make_context_manager2() as cm2, + make_context_manager3() as cm3, + make_context_manager4() as cm4, +): + pass + + +# Leading comment +with ( + make_context_manager1() as cm1, + make_context_manager2(), + make_context_manager3() as cm3, + make_context_manager4(), +): + pass + + +with new_new_new1() as cm1, new_new_new2(): + pass + + +with new_new_new1() as cm1, new_new_new2(): + pass + + +# Leading comment. +with ( + # First comment. + new_new_new1() as cm1, + # Second comment. + new_new_new2(), + # Last comment. +): + pass + + +with ( + this_is_a_very_long_call( + looong_arg1=looong_value1, looong_arg2=looong_value2 + ) as cm1, + this_is_a_very_long_call( + looong_arg1=looong_value1, + looong_arg2=looong_value2, + looong_arg3=looong_value3, + looong_arg4=looong_value4, + ) as cm2, +): + pass + + +with ( + mock.patch.object(self.my_runner, "first_method", autospec=True) as mock_run_adb, + mock.patch.object( + self.my_runner, "second_method", autospec=True, return_value="foo" + ), +): + pass + + +with xxxxxxxx.some_kind_of_method( + some_argument=[ + "first", + "second", + "third", + ] +).another_method() as cmd: + pass + + +async def func(): + async with ( + make_context_manager1() as cm1, + make_context_manager2() as cm2, + make_context_manager3() as cm3, + make_context_manager4() as cm4, + ): + pass + + async with ( + some_function(argument1, argument2, argument3="some_value") as some_cm, + some_other_function(argument1, argument2, argument3="some_value"), + ): + pass +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_autodetect_310.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_autodetect_310.py.snap new file mode 100644 index 0000000000000..abee1610d434c --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_autodetect_310.py.snap @@ -0,0 +1,79 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_310.py +--- +## Input + +```python +# This file uses pattern matching introduced in Python 3.10. + + +match http_code: + case 404: + print("Not found") + + +with \ + make_context_manager1() as cm1, \ + make_context_manager2() as cm2, \ + make_context_manager3() as cm3, \ + make_context_manager4() as cm4 \ +: + pass +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -6,10 +6,5 @@ + print("Not found") + + +-with ( +- make_context_manager1() as cm1, +- make_context_manager2() as cm2, +- make_context_manager3() as cm3, +- make_context_manager4() as cm4, +-): ++with make_context_manager1() as cm1, make_context_manager2() as cm2, make_context_manager3() as cm3, make_context_manager4() as cm4: + pass +``` + +## Ruff Output + +```python +# This file uses pattern matching introduced in Python 3.10. + + +match http_code: + case 404: + print("Not found") + + +with make_context_manager1() as cm1, make_context_manager2() as cm2, make_context_manager3() as cm3, make_context_manager4() as cm4: + pass +``` + +## Black Output + +```python +# This file uses pattern matching introduced in Python 3.10. + + +match http_code: + case 404: + print("Not found") + + +with ( + make_context_manager1() as cm1, + make_context_manager2() as cm2, + make_context_manager3() as cm3, + make_context_manager4() as cm4, +): + pass +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_autodetect_311.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_autodetect_311.py.snap new file mode 100644 index 0000000000000..71002c8d5d700 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_autodetect_311.py.snap @@ -0,0 +1,82 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_311.py +--- +## Input + +```python +# This file uses except* clause in Python 3.11. + + +try: + some_call() +except* Error as e: + pass + + +with \ + make_context_manager1() as cm1, \ + make_context_manager2() as cm2, \ + make_context_manager3() as cm3, \ + make_context_manager4() as cm4 \ +: + pass +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -7,10 +7,5 @@ + pass + + +-with ( +- make_context_manager1() as cm1, +- make_context_manager2() as cm2, +- make_context_manager3() as cm3, +- make_context_manager4() as cm4, +-): ++with make_context_manager1() as cm1, make_context_manager2() as cm2, make_context_manager3() as cm3, make_context_manager4() as cm4: + pass +``` + +## Ruff Output + +```python +# This file uses except* clause in Python 3.11. + + +try: + some_call() +except* Error as e: + pass + + +with make_context_manager1() as cm1, make_context_manager2() as cm2, make_context_manager3() as cm3, make_context_manager4() as cm4: + pass +``` + +## Black Output + +```python +# This file uses except* clause in Python 3.11. + + +try: + some_call() +except* Error as e: + pass + + +with ( + make_context_manager1() as cm1, + make_context_manager2() as cm2, + make_context_manager3() as cm3, + make_context_manager4() as cm4, +): + pass +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_autodetect_39.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_autodetect_39.py.snap new file mode 100644 index 0000000000000..e1aeaa9faf8b9 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_context_managers_autodetect_39.py.snap @@ -0,0 +1,81 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_context_managers_autodetect_39.py +--- +## Input + +```python +# This file uses parenthesized context managers introduced in Python 3.9. + + +with \ + make_context_manager1() as cm1, \ + make_context_manager2() as cm2, \ + make_context_manager3() as cm3, \ + make_context_manager4() as cm4 \ +: + pass + + +with ( + new_new_new1() as cm1, + new_new_new2() +): + pass +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,12 +1,7 @@ + # This file uses parenthesized context managers introduced in Python 3.9. + + +-with ( +- make_context_manager1() as cm1, +- make_context_manager2() as cm2, +- make_context_manager3() as cm3, +- make_context_manager4() as cm4, +-): ++with make_context_manager1() as cm1, make_context_manager2() as cm2, make_context_manager3() as cm3, make_context_manager4() as cm4: + pass + + +``` + +## Ruff Output + +```python +# This file uses parenthesized context managers introduced in Python 3.9. + + +with make_context_manager1() as cm1, make_context_manager2() as cm2, make_context_manager3() as cm3, make_context_manager4() as cm4: + pass + + +with new_new_new1() as cm1, new_new_new2(): + pass +``` + +## Black Output + +```python +# This file uses parenthesized context managers introduced in Python 3.9. + + +with ( + make_context_manager1() as cm1, + make_context_manager2() as cm2, + make_context_manager3() as cm3, + make_context_manager4() as cm4, +): + pass + + +with new_new_new1() as cm1, new_new_new2(): + pass +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__docstring_preview_no_string_normalization.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_docstring_no_string_normalization.py.snap similarity index 96% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__docstring_preview_no_string_normalization.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_docstring_no_string_normalization.py.snap index a2969f3e403b4..70b323e49317e 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__docstring_preview_no_string_normalization.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_docstring_no_string_normalization.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/docstring_preview_no_string_normalization.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_docstring_no_string_normalization.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_dummy_implementations.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_dummy_implementations.py.snap new file mode 100644 index 0000000000000..a5ec909765730 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_dummy_implementations.py.snap @@ -0,0 +1,231 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_dummy_implementations.py +--- +## Input + +```python +from typing import NoReturn, Protocol, Union, overload + + +def dummy(a): ... +def other(b): ... + + +@overload +def a(arg: int) -> int: ... +@overload +def a(arg: str) -> str: ... +@overload +def a(arg: object) -> NoReturn: ... +def a(arg: Union[int, str, object]) -> Union[int, str]: + if not isinstance(arg, (int, str)): + raise TypeError + return arg + +class Proto(Protocol): + def foo(self, a: int) -> int: + ... + + def bar(self, b: str) -> str: ... + def baz(self, c: bytes) -> str: + ... + + +def dummy_two(): + ... +@dummy +def dummy_three(): + ... + +def dummy_four(): + ... + +@overload +def b(arg: int) -> int: ... + +@overload +def b(arg: str) -> str: ... +@overload +def b(arg: object) -> NoReturn: ... + +def b(arg: Union[int, str, object]) -> Union[int, str]: + if not isinstance(arg, (int, str)): + raise TypeError + return arg +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -2,15 +2,23 @@ + + + def dummy(a): ... ++ ++ + def other(b): ... + + + @overload + def a(arg: int) -> int: ... ++ ++ + @overload + def a(arg: str) -> str: ... ++ ++ + @overload + def a(arg: object) -> NoReturn: ... ++ ++ + def a(arg: Union[int, str, object]) -> Union[int, str]: + if not isinstance(arg, (int, str)): + raise TypeError +@@ -21,10 +29,13 @@ + def foo(self, a: int) -> int: ... + + def bar(self, b: str) -> str: ... ++ + def baz(self, c: bytes) -> str: ... + + + def dummy_two(): ... ++ ++ + @dummy + def dummy_three(): ... + +@@ -38,6 +49,8 @@ + + @overload + def b(arg: str) -> str: ... ++ ++ + @overload + def b(arg: object) -> NoReturn: ... + +``` + +## Ruff Output + +```python +from typing import NoReturn, Protocol, Union, overload + + +def dummy(a): ... + + +def other(b): ... + + +@overload +def a(arg: int) -> int: ... + + +@overload +def a(arg: str) -> str: ... + + +@overload +def a(arg: object) -> NoReturn: ... + + +def a(arg: Union[int, str, object]) -> Union[int, str]: + if not isinstance(arg, (int, str)): + raise TypeError + return arg + + +class Proto(Protocol): + def foo(self, a: int) -> int: ... + + def bar(self, b: str) -> str: ... + + def baz(self, c: bytes) -> str: ... + + +def dummy_two(): ... + + +@dummy +def dummy_three(): ... + + +def dummy_four(): ... + + +@overload +def b(arg: int) -> int: ... + + +@overload +def b(arg: str) -> str: ... + + +@overload +def b(arg: object) -> NoReturn: ... + + +def b(arg: Union[int, str, object]) -> Union[int, str]: + if not isinstance(arg, (int, str)): + raise TypeError + return arg +``` + +## Black Output + +```python +from typing import NoReturn, Protocol, Union, overload + + +def dummy(a): ... +def other(b): ... + + +@overload +def a(arg: int) -> int: ... +@overload +def a(arg: str) -> str: ... +@overload +def a(arg: object) -> NoReturn: ... +def a(arg: Union[int, str, object]) -> Union[int, str]: + if not isinstance(arg, (int, str)): + raise TypeError + return arg + + +class Proto(Protocol): + def foo(self, a: int) -> int: ... + + def bar(self, b: str) -> str: ... + def baz(self, c: bytes) -> str: ... + + +def dummy_two(): ... +@dummy +def dummy_three(): ... + + +def dummy_four(): ... + + +@overload +def b(arg: int) -> int: ... + + +@overload +def b(arg: str) -> str: ... +@overload +def b(arg: object) -> NoReturn: ... + + +def b(arg: Union[int, str, object]) -> Union[int, str]: + if not isinstance(arg, (int, str)): + raise TypeError + return arg +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_form_feeds.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_form_feeds.py.snap new file mode 100644 index 0000000000000..ae94587cd425e --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_form_feeds.py.snap @@ -0,0 +1,446 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_form_feeds.py +--- +## Input + +```python +# Warning! This file contains form feeds (ASCII 0x0C, often represented by \f or ^L). +# These may be invisible in your editor: ensure you can see them before making changes here. + +# There's one at the start that'll get stripped + +# Comment and statement processing is different enough that we'll test variations of both +# contexts here + +# + + +# + + +# + + + +# + + + +# + + + +# + + +# + + + +# + +# + +# + + \ +# +pass + +pass + + +pass + + +pass + + + +pass + + + +pass + + + +pass + + +pass + + + +pass + +pass + +pass + + +# form feed after a dedent +def foo(): + pass + +pass + + +# form feeds are prohibited inside blocks, or on a line with nonwhitespace + def bar( a = 1 ,b : bool = False ) : + + + pass + + +class Baz: + + def __init__(self): + pass + + + def something(self): + pass + + + +# +pass +pass # +a = 1 + # + pass + a = 1 + +a = [ + +] + +# as internal whitespace of a comment is allowed but why +"form feed literal in a string is okay " + +# form feeds at the very end get removed. +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -5,62 +5,62 @@ + + # Comment and statement processing is different enough that we'll test variations of both + # contexts here +- ++ + # + +- ++ + # + +- ++ + # + +- ++ + # + +- ++ + # + +- ++ + # + +- ++ + # + +- ++ + # +- ++ + # +- ++ + # + + # + pass +- ++ + pass + +- ++ + pass + +- ++ + pass + +- ++ + pass + +- ++ + pass + +- ++ + pass + +- ++ + pass + +- ++ + pass +- ++ + pass +- ++ + pass + + +@@ -68,7 +68,7 @@ + def foo(): + pass + +- ++ + pass + + +@@ -84,7 +84,7 @@ + def something(self): + pass + +- ++ + # + pass + pass # +``` + +## Ruff Output + +```python +# Warning! This file contains form feeds (ASCII 0x0C, often represented by \f or ^L). +# These may be invisible in your editor: ensure you can see them before making changes here. + +# There's one at the start that'll get stripped + +# Comment and statement processing is different enough that we'll test variations of both +# contexts here + +# + + +# + + +# + + +# + + +# + + +# + + +# + + +# + +# + +# + +# +pass + +pass + + +pass + + +pass + + +pass + + +pass + + +pass + + +pass + + +pass + +pass + +pass + + +# form feed after a dedent +def foo(): + pass + + +pass + + +# form feeds are prohibited inside blocks, or on a line with nonwhitespace +def bar(a=1, b: bool = False): + pass + + +class Baz: + def __init__(self): + pass + + def something(self): + pass + + +# +pass +pass # +a = 1 +# +pass +a = 1 + +a = [] + +# as internal whitespace of a comment is allowed but why +"form feed literal in a string is okay " + +# form feeds at the very end get removed. +``` + +## Black Output + +```python +# Warning! This file contains form feeds (ASCII 0x0C, often represented by \f or ^L). +# These may be invisible in your editor: ensure you can see them before making changes here. + +# There's one at the start that'll get stripped + +# Comment and statement processing is different enough that we'll test variations of both +# contexts here + +# + + +# + + +# + + +# + + +# + + +# + + +# + + +# + +# + +# + +# +pass + +pass + + +pass + + +pass + + +pass + + +pass + + +pass + + +pass + + +pass + +pass + +pass + + +# form feed after a dedent +def foo(): + pass + + +pass + + +# form feeds are prohibited inside blocks, or on a line with nonwhitespace +def bar(a=1, b: bool = False): + pass + + +class Baz: + def __init__(self): + pass + + def something(self): + pass + + +# +pass +pass # +a = 1 +# +pass +a = 1 + +a = [] + +# as internal whitespace of a comment is allowed but why +"form feed literal in a string is okay " + +# form feeds at the very end get removed. +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_format_unicode_escape_seq.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_format_unicode_escape_seq.py.snap new file mode 100644 index 0000000000000..c523ecc557c70 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_format_unicode_escape_seq.py.snap @@ -0,0 +1,97 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_format_unicode_escape_seq.py +--- +## Input + +```python +x = "\x1F" +x = "\\x1B" +x = "\\\x1B" +x = "\U0001F60E" +x = "\u0001F60E" +x = r"\u0001F60E" +x = "don't format me" +x = "\xA3" +x = "\u2717" +x = "\uFaCe" +x = "\N{ox}\N{OX}" +x = "\N{lAtIn smaLL letteR x}" +x = "\N{CYRILLIC small LETTER BYELORUSSIAN-UKRAINIAN I}" +x = b"\x1Fdon't byte" +x = rb"\x1Fdon't format" +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,15 +1,15 @@ +-x = "\x1f" ++x = "\x1F" + x = "\\x1B" +-x = "\\\x1b" +-x = "\U0001f60e" ++x = "\\\x1B" ++x = "\U0001F60E" + x = "\u0001F60E" + x = r"\u0001F60E" + x = "don't format me" +-x = "\xa3" ++x = "\xA3" + x = "\u2717" +-x = "\uface" +-x = "\N{OX}\N{OX}" +-x = "\N{LATIN SMALL LETTER X}" +-x = "\N{CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I}" +-x = b"\x1fdon't byte" ++x = "\uFaCe" ++x = "\N{ox}\N{OX}" ++x = "\N{lAtIn smaLL letteR x}" ++x = "\N{CYRILLIC small LETTER BYELORUSSIAN-UKRAINIAN I}" ++x = b"\x1Fdon't byte" + x = rb"\x1Fdon't format" +``` + +## Ruff Output + +```python +x = "\x1F" +x = "\\x1B" +x = "\\\x1B" +x = "\U0001F60E" +x = "\u0001F60E" +x = r"\u0001F60E" +x = "don't format me" +x = "\xA3" +x = "\u2717" +x = "\uFaCe" +x = "\N{ox}\N{OX}" +x = "\N{lAtIn smaLL letteR x}" +x = "\N{CYRILLIC small LETTER BYELORUSSIAN-UKRAINIAN I}" +x = b"\x1Fdon't byte" +x = rb"\x1Fdon't format" +``` + +## Black Output + +```python +x = "\x1f" +x = "\\x1B" +x = "\\\x1b" +x = "\U0001f60e" +x = "\u0001F60E" +x = r"\u0001F60E" +x = "don't format me" +x = "\xa3" +x = "\u2717" +x = "\uface" +x = "\N{OX}\N{OX}" +x = "\N{LATIN SMALL LETTER X}" +x = "\N{CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I}" +x = b"\x1fdon't byte" +x = rb"\x1Fdon't format" +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_hug_parens_with_braces_and_square_brackets.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_hug_parens_with_braces_and_square_brackets.py.snap new file mode 100644 index 0000000000000..d9a87a05c5987 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_hug_parens_with_braces_and_square_brackets.py.snap @@ -0,0 +1,1212 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_hug_parens_with_braces_and_square_brackets.py +--- +## Input + +```python +def foo_brackets(request): + return JsonResponse( + { + "var_1": foo, + "var_2": bar, + } + ) + +def foo_square_brackets(request): + return JsonResponse( + [ + "var_1", + "var_2", + ] + ) + +func({"a": 37, "b": 42, "c": 927, "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111}) + +func(["random_string_number_one","random_string_number_two","random_string_number_three","random_string_number_four"]) + +func( + { + # expand me + 'a':37, + 'b':42, + 'c':927 + } +) + +func( + [ + 'a', + 'b', + 'c', + ] +) + +func( + [ + 'a', + 'b', + 'c', + ], +) + +func( # a + [ # b + "c", # c + "d", # d + "e", # e + ] # f +) # g + +func( # a + { # b + "c": 1, # c + "d": 2, # d + "e": 3, # e + } # f +) # g + +func( + # preserve me + [ + "c", + "d", + "e", + ] +) + +func( + [ # preserve me but hug brackets + "c", + "d", + "e", + ] +) + +func( + [ + # preserve me but hug brackets + "c", + "d", + "e", + ] +) + +func( + [ + "c", + # preserve me but hug brackets + "d", + "e", + ] +) + +func( + [ + "c", + "d", + "e", + # preserve me but hug brackets + ] +) + +func( + [ + "c", + "d", + "e", + ] # preserve me but hug brackets +) + +func( + [ + "c", + "d", + "e", + ] + # preserve me +) + +func([x for x in "short line"]) +func([x for x in "long line long line long line long line long line long line long line"]) +func([x for x in [x for x in "long line long line long line long line long line long line long line"]]) + +func({"short line"}) +func({"long line", "long long line", "long long long line", "long long long long line", "long long long long long line"}) +func({{"long line", "long long line", "long long long line", "long long long long line", "long long long long long line"}}) +func(("long line", "long long line", "long long long line", "long long long long line", "long long long long long line")) +func((("long line", "long long line", "long long long line", "long long long long line", "long long long long long line"))) +func([["long line", "long long line", "long long long line", "long long long long line", "long long long long long line"]]) + +# Do not hug if the argument fits on a single line. +func({"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"}) +func(("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line")) +func(["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"]) +func(**{"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit---"}) +func(*("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit----")) +array = [{"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"}] +array = [("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line")] +array = [["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"]] + +foooooooooooooooooooo( + [{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size} +) + +baaaaaaaaaaaaar( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +) + +nested_mapping = {"key": [{"a very long key 1": "with a very long value", "a very long key 2": "with a very long value"}]} +nested_array = [[["long line", "long long line", "long long long line", "long long long long line", "long long long long long line"]]] +explicit_exploding = [[["short", "line",],],] +single_item_do_not_explode = Context({ + "version": get_docs_version(), +}) + +foo(*["long long long long long line", "long long long long long line", "long long long long long line"]) + +foo(*[str(i) for i in range(100000000000000000000000000000000000000000000000000000000000)]) + +foo( + **{ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": 1, + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb": 2, + "ccccccccccccccccccccccccccccccccc": 3, + **other, + } +) + +foo(**{x: y for x, y in enumerate(["long long long long line","long long long long line"])}) + +# Edge case when deciding whether to hug the brackets without inner content. +very_very_very_long_variable = very_very_very_long_module.VeryVeryVeryVeryLongClassName([[]]) + +for foo in ["a", "b"]: + output.extend([ + individual + for + # Foobar + container in xs_by_y[foo] + # Foobar + for individual in container["nested"] + ]) +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,43 +1,55 @@ + def foo_brackets(request): +- return JsonResponse({ +- "var_1": foo, +- "var_2": bar, +- }) ++ return JsonResponse( ++ { ++ "var_1": foo, ++ "var_2": bar, ++ } ++ ) + + + def foo_square_brackets(request): +- return JsonResponse([ +- "var_1", +- "var_2", +- ]) ++ return JsonResponse( ++ [ ++ "var_1", ++ "var_2", ++ ] ++ ) + + +-func({ +- "a": 37, +- "b": 42, +- "c": 927, +- "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111, +-}) ++func( ++ { ++ "a": 37, ++ "b": 42, ++ "c": 927, ++ "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111, ++ } ++) + +-func([ +- "random_string_number_one", +- "random_string_number_two", +- "random_string_number_three", +- "random_string_number_four", +-]) ++func( ++ [ ++ "random_string_number_one", ++ "random_string_number_two", ++ "random_string_number_three", ++ "random_string_number_four", ++ ] ++) + +-func({ +- # expand me +- "a": 37, +- "b": 42, +- "c": 927, +-}) ++func( ++ { ++ # expand me ++ "a": 37, ++ "b": 42, ++ "c": 927, ++ } ++) + +-func([ +- "a", +- "b", +- "c", +-]) ++func( ++ [ ++ "a", ++ "b", ++ "c", ++ ] ++) + + func( + [ +@@ -47,17 +59,21 @@ + ], + ) + +-func([ # a # b +- "c", # c +- "d", # d +- "e", # e +-]) # f # g ++func( # a ++ [ # b ++ "c", # c ++ "d", # d ++ "e", # e ++ ] # f ++) # g + +-func({ # a # b +- "c": 1, # c +- "d": 2, # d +- "e": 3, # e +-}) # f # g ++func( # a ++ { # b ++ "c": 1, # c ++ "d": 2, # d ++ "e": 3, # e ++ } # f ++) # g + + func( + # preserve me +@@ -68,38 +84,48 @@ + ] + ) + +-func([ # preserve me but hug brackets +- "c", +- "d", +- "e", +-]) ++func( ++ [ # preserve me but hug brackets ++ "c", ++ "d", ++ "e", ++ ] ++) + +-func([ +- # preserve me but hug brackets +- "c", +- "d", +- "e", +-]) ++func( ++ [ ++ # preserve me but hug brackets ++ "c", ++ "d", ++ "e", ++ ] ++) + +-func([ +- "c", +- # preserve me but hug brackets +- "d", +- "e", +-]) ++func( ++ [ ++ "c", ++ # preserve me but hug brackets ++ "d", ++ "e", ++ ] ++) + +-func([ +- "c", +- "d", +- "e", +- # preserve me but hug brackets +-]) ++func( ++ [ ++ "c", ++ "d", ++ "e", ++ # preserve me but hug brackets ++ ] ++) + +-func([ +- "c", +- "d", +- "e", +-]) # preserve me but hug brackets ++func( ++ [ ++ "c", ++ "d", ++ "e", ++ ] # preserve me but hug brackets ++) + + func( + [ +@@ -114,50 +140,68 @@ + func( + [x for x in "long line long line long line long line long line long line long line"] + ) +-func([ +- x +- for x in [ ++func( ++ [ + x +- for x in "long line long line long line long line long line long line long line" ++ for x in [ ++ x ++ for x in "long line long line long line long line long line long line long line" ++ ] + ] +-]) ++) + + func({"short line"}) +-func({ +- "long line", +- "long long line", +- "long long long line", +- "long long long long line", +- "long long long long long line", +-}) +-func({{ +- "long line", +- "long long line", +- "long long long line", +- "long long long long line", +- "long long long long long line", +-}}) +-func(( +- "long line", +- "long long line", +- "long long long line", +- "long long long long line", +- "long long long long long line", +-)) +-func((( +- "long line", +- "long long line", +- "long long long line", +- "long long long long line", +- "long long long long long line", +-))) +-func([[ +- "long line", +- "long long line", +- "long long long line", +- "long long long long line", +- "long long long long long line", +-]]) ++func( ++ { ++ "long line", ++ "long long line", ++ "long long long line", ++ "long long long long line", ++ "long long long long long line", ++ } ++) ++func( ++ { ++ { ++ "long line", ++ "long long line", ++ "long long long line", ++ "long long long long line", ++ "long long long long long line", ++ } ++ } ++) ++func( ++ ( ++ "long line", ++ "long long line", ++ "long long long line", ++ "long long long long line", ++ "long long long long long line", ++ ) ++) ++func( ++ ( ++ ( ++ "long line", ++ "long long line", ++ "long long long line", ++ "long long long long line", ++ "long long long long long line", ++ ) ++ ) ++) ++func( ++ [ ++ [ ++ "long line", ++ "long long line", ++ "long long long line", ++ "long long long long line", ++ "long long long long long line", ++ ] ++ ] ++) + + # Do not hug if the argument fits on a single line. + func( +@@ -194,18 +238,24 @@ + ) + + nested_mapping = { +- "key": [{ +- "a very long key 1": "with a very long value", +- "a very long key 2": "with a very long value", +- }] ++ "key": [ ++ { ++ "a very long key 1": "with a very long value", ++ "a very long key 2": "with a very long value", ++ } ++ ] + } +-nested_array = [[[ +- "long line", +- "long long line", +- "long long long line", +- "long long long long line", +- "long long long long long line", +-]]] ++nested_array = [ ++ [ ++ [ ++ "long line", ++ "long long line", ++ "long long long line", ++ "long long long long line", ++ "long long long long long line", ++ ] ++ ] ++] + explicit_exploding = [ + [ + [ +@@ -214,30 +264,42 @@ + ], + ], + ] +-single_item_do_not_explode = Context({ +- "version": get_docs_version(), +-}) ++single_item_do_not_explode = Context( ++ { ++ "version": get_docs_version(), ++ } ++) + +-foo(*[ +- "long long long long long line", +- "long long long long long line", +- "long long long long long line", +-]) ++foo( ++ *[ ++ "long long long long long line", ++ "long long long long long line", ++ "long long long long long line", ++ ] ++) + +-foo(*[ +- str(i) for i in range(100000000000000000000000000000000000000000000000000000000000) +-]) ++foo( ++ *[ ++ str(i) ++ for i in range(100000000000000000000000000000000000000000000000000000000000) ++ ] ++) + +-foo(**{ +- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": 1, +- "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb": 2, +- "ccccccccccccccccccccccccccccccccc": 3, +- **other, +-}) ++foo( ++ **{ ++ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": 1, ++ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb": 2, ++ "ccccccccccccccccccccccccccccccccc": 3, ++ **other, ++ } ++) + +-foo(**{ +- x: y for x, y in enumerate(["long long long long line", "long long long long line"]) +-}) ++foo( ++ **{ ++ x: y ++ for x, y in enumerate(["long long long long line", "long long long long line"]) ++ } ++) + + # Edge case when deciding whether to hug the brackets without inner content. + very_very_very_long_variable = very_very_very_long_module.VeryVeryVeryVeryLongClassName( +@@ -245,11 +307,13 @@ + ) + + for foo in ["a", "b"]: +- output.extend([ +- individual +- for +- # Foobar +- container in xs_by_y[foo] +- # Foobar +- for individual in container["nested"] +- ]) ++ output.extend( ++ [ ++ individual ++ for ++ # Foobar ++ container in xs_by_y[foo] ++ # Foobar ++ for individual in container["nested"] ++ ] ++ ) +``` + +## Ruff Output + +```python +def foo_brackets(request): + return JsonResponse( + { + "var_1": foo, + "var_2": bar, + } + ) + + +def foo_square_brackets(request): + return JsonResponse( + [ + "var_1", + "var_2", + ] + ) + + +func( + { + "a": 37, + "b": 42, + "c": 927, + "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111, + } +) + +func( + [ + "random_string_number_one", + "random_string_number_two", + "random_string_number_three", + "random_string_number_four", + ] +) + +func( + { + # expand me + "a": 37, + "b": 42, + "c": 927, + } +) + +func( + [ + "a", + "b", + "c", + ] +) + +func( + [ + "a", + "b", + "c", + ], +) + +func( # a + [ # b + "c", # c + "d", # d + "e", # e + ] # f +) # g + +func( # a + { # b + "c": 1, # c + "d": 2, # d + "e": 3, # e + } # f +) # g + +func( + # preserve me + [ + "c", + "d", + "e", + ] +) + +func( + [ # preserve me but hug brackets + "c", + "d", + "e", + ] +) + +func( + [ + # preserve me but hug brackets + "c", + "d", + "e", + ] +) + +func( + [ + "c", + # preserve me but hug brackets + "d", + "e", + ] +) + +func( + [ + "c", + "d", + "e", + # preserve me but hug brackets + ] +) + +func( + [ + "c", + "d", + "e", + ] # preserve me but hug brackets +) + +func( + [ + "c", + "d", + "e", + ] + # preserve me +) + +func([x for x in "short line"]) +func( + [x for x in "long line long line long line long line long line long line long line"] +) +func( + [ + x + for x in [ + x + for x in "long line long line long line long line long line long line long line" + ] + ] +) + +func({"short line"}) +func( + { + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", + } +) +func( + { + { + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", + } + } +) +func( + ( + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", + ) +) +func( + ( + ( + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", + ) + ) +) +func( + [ + [ + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", + ] + ] +) + +# Do not hug if the argument fits on a single line. +func( + {"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"} +) +func( + ("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line") +) +func( + ["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"] +) +func( + **{"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit---"} +) +func( + *("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit----") +) +array = [ + {"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"} +] +array = [ + ("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line") +] +array = [ + ["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"] +] + +foooooooooooooooooooo( + [{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size} +) + +baaaaaaaaaaaaar( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +) + +nested_mapping = { + "key": [ + { + "a very long key 1": "with a very long value", + "a very long key 2": "with a very long value", + } + ] +} +nested_array = [ + [ + [ + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", + ] + ] +] +explicit_exploding = [ + [ + [ + "short", + "line", + ], + ], +] +single_item_do_not_explode = Context( + { + "version": get_docs_version(), + } +) + +foo( + *[ + "long long long long long line", + "long long long long long line", + "long long long long long line", + ] +) + +foo( + *[ + str(i) + for i in range(100000000000000000000000000000000000000000000000000000000000) + ] +) + +foo( + **{ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": 1, + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb": 2, + "ccccccccccccccccccccccccccccccccc": 3, + **other, + } +) + +foo( + **{ + x: y + for x, y in enumerate(["long long long long line", "long long long long line"]) + } +) + +# Edge case when deciding whether to hug the brackets without inner content. +very_very_very_long_variable = very_very_very_long_module.VeryVeryVeryVeryLongClassName( + [[]] +) + +for foo in ["a", "b"]: + output.extend( + [ + individual + for + # Foobar + container in xs_by_y[foo] + # Foobar + for individual in container["nested"] + ] + ) +``` + +## Black Output + +```python +def foo_brackets(request): + return JsonResponse({ + "var_1": foo, + "var_2": bar, + }) + + +def foo_square_brackets(request): + return JsonResponse([ + "var_1", + "var_2", + ]) + + +func({ + "a": 37, + "b": 42, + "c": 927, + "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111, +}) + +func([ + "random_string_number_one", + "random_string_number_two", + "random_string_number_three", + "random_string_number_four", +]) + +func({ + # expand me + "a": 37, + "b": 42, + "c": 927, +}) + +func([ + "a", + "b", + "c", +]) + +func( + [ + "a", + "b", + "c", + ], +) + +func([ # a # b + "c", # c + "d", # d + "e", # e +]) # f # g + +func({ # a # b + "c": 1, # c + "d": 2, # d + "e": 3, # e +}) # f # g + +func( + # preserve me + [ + "c", + "d", + "e", + ] +) + +func([ # preserve me but hug brackets + "c", + "d", + "e", +]) + +func([ + # preserve me but hug brackets + "c", + "d", + "e", +]) + +func([ + "c", + # preserve me but hug brackets + "d", + "e", +]) + +func([ + "c", + "d", + "e", + # preserve me but hug brackets +]) + +func([ + "c", + "d", + "e", +]) # preserve me but hug brackets + +func( + [ + "c", + "d", + "e", + ] + # preserve me +) + +func([x for x in "short line"]) +func( + [x for x in "long line long line long line long line long line long line long line"] +) +func([ + x + for x in [ + x + for x in "long line long line long line long line long line long line long line" + ] +]) + +func({"short line"}) +func({ + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +}) +func({{ + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +}}) +func(( + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +)) +func((( + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +))) +func([[ + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +]]) + +# Do not hug if the argument fits on a single line. +func( + {"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"} +) +func( + ("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line") +) +func( + ["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"] +) +func( + **{"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit---"} +) +func( + *("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit----") +) +array = [ + {"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"} +] +array = [ + ("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line") +] +array = [ + ["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"] +] + +foooooooooooooooooooo( + [{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size} +) + +baaaaaaaaaaaaar( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +) + +nested_mapping = { + "key": [{ + "a very long key 1": "with a very long value", + "a very long key 2": "with a very long value", + }] +} +nested_array = [[[ + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +]]] +explicit_exploding = [ + [ + [ + "short", + "line", + ], + ], +] +single_item_do_not_explode = Context({ + "version": get_docs_version(), +}) + +foo(*[ + "long long long long long line", + "long long long long long line", + "long long long long long line", +]) + +foo(*[ + str(i) for i in range(100000000000000000000000000000000000000000000000000000000000) +]) + +foo(**{ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": 1, + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb": 2, + "ccccccccccccccccccccccccccccccccc": 3, + **other, +}) + +foo(**{ + x: y for x, y in enumerate(["long long long long line", "long long long long line"]) +}) + +# Edge case when deciding whether to hug the brackets without inner content. +very_very_very_long_variable = very_very_very_long_module.VeryVeryVeryVeryLongClassName( + [[]] +) + +for foo in ["a", "b"]: + output.extend([ + individual + for + # Foobar + container in xs_by_y[foo] + # Foobar + for individual in container["nested"] + ]) +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_dict_values.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_dict_values.py.snap new file mode 100644 index 0000000000000..d60d394b858fb --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_dict_values.py.snap @@ -0,0 +1,201 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_dict_values.py +--- +## Input + +```python +my_dict = { + "something_something": + r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t" + r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t" + r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t", +} + +my_dict = { + "a key in my dict": a_very_long_variable * and_a_very_long_function_call() / 100000.0 +} + +my_dict = { + "a key in my dict": a_very_long_variable * and_a_very_long_function_call() * and_another_long_func() / 100000.0 +} + +my_dict = { + "a key in my dict": MyClass.some_attribute.first_call().second_call().third_call(some_args="some value") +} + +{ + 'xxxxxx': + xxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxx( + xxxxxxxxxxxxxx={ + 'x': + xxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + .xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + xxxxxxxxxxxxx=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + .xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx={ + 'x': x.xx, + 'x': x.x, + })))) + }), +} +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,32 +1,26 @@ + my_dict = { +- "something_something": ( +- r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t" +- r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t" +- r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t" +- ), ++ "something_something": r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t" ++ r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t" ++ r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t", + } + + my_dict = { +- "a key in my dict": ( +- a_very_long_variable * and_a_very_long_function_call() / 100000.0 +- ) ++ "a key in my dict": a_very_long_variable ++ * and_a_very_long_function_call() ++ / 100000.0 + } + + my_dict = { +- "a key in my dict": ( +- a_very_long_variable +- * and_a_very_long_function_call() +- * and_another_long_func() +- / 100000.0 +- ) ++ "a key in my dict": a_very_long_variable ++ * and_a_very_long_function_call() ++ * and_another_long_func() ++ / 100000.0 + } + + my_dict = { +- "a key in my dict": ( +- MyClass.some_attribute.first_call() +- .second_call() +- .third_call(some_args="some value") +- ) ++ "a key in my dict": MyClass.some_attribute.first_call() ++ .second_call() ++ .third_call(some_args="some value") + } + + { +``` + +## Ruff Output + +```python +my_dict = { + "something_something": r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t" + r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t" + r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t", +} + +my_dict = { + "a key in my dict": a_very_long_variable + * and_a_very_long_function_call() + / 100000.0 +} + +my_dict = { + "a key in my dict": a_very_long_variable + * and_a_very_long_function_call() + * and_another_long_func() + / 100000.0 +} + +my_dict = { + "a key in my dict": MyClass.some_attribute.first_call() + .second_call() + .third_call(some_args="some value") +} + +{ + "xxxxxx": xxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxx( + xxxxxxxxxxxxxx={ + "x": xxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + xxxxxxxxxxxxx=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx={ + "x": x.xx, + "x": x.x, + } + ) + ) + ) + ) + } + ), +} +``` + +## Black Output + +```python +my_dict = { + "something_something": ( + r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t" + r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t" + r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t" + ), +} + +my_dict = { + "a key in my dict": ( + a_very_long_variable * and_a_very_long_function_call() / 100000.0 + ) +} + +my_dict = { + "a key in my dict": ( + a_very_long_variable + * and_a_very_long_function_call() + * and_another_long_func() + / 100000.0 + ) +} + +my_dict = { + "a key in my dict": ( + MyClass.some_attribute.first_call() + .second_call() + .third_call(some_args="some value") + ) +} + +{ + "xxxxxx": xxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxx( + xxxxxxxxxxxxxx={ + "x": xxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + xxxxxxxxxxxxx=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx={ + "x": x.xx, + "x": x.x, + } + ) + ) + ) + ) + } + ), +} +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings.py.snap new file mode 100644 index 0000000000000..b3a03820fa4ca --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings.py.snap @@ -0,0 +1,2038 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings.py +--- +## Input + +```python +x = "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three." + +x += "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three." + +y = ( + 'Short string' +) + +print('This is a really long string inside of a print statement with extra arguments attached at the end of it.', x, y, z) + +print("This is a really long string inside of a print statement with no extra arguments attached at the end of it.") + +D1 = {"The First": "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.", "The Second": "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary."} + +D2 = {1.0: "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.", 2.0: "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary."} + +D3 = {x: "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.", y: "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary."} + +D4 = {"A long and ridiculous {}".format(string_key): "This is a really really really long string that has to go i,side of a dictionary. It is soooo bad.", some_func("calling", "some", "stuff"): "This is a really really really long string that has to go inside of a dictionary. It is {soooo} bad (#{x}).".format(sooo="soooo", x=2), "A %s %s" % ("formatted", "string"): "This is a really really really long string that has to go inside of a dictionary. It is %s bad (#%d)." % ("soooo", 2)} + +D5 = { # Test for https://github.com/psf/black/issues/3261 + ("This is a really long string that can't be expected to fit in one line and is used as a nested dict's key"): {"inner": "value"}, +} + +D6 = { # Test for https://github.com/psf/black/issues/3261 + ("This is a really long string that can't be expected to fit in one line and is used as a dict's key"): ["value1", "value2"], +} + +L1 = ["The is a short string", "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a list literal, so it's expected to be wrapped in parens when splitting to avoid implicit str concatenation.", short_call("arg", {"key": "value"}), "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a list literal.", ("parens should be stripped for short string in list")] + +L2 = ["This is a really long string that can't be expected to fit in one line and is the only child of a list literal."] + +S1 = {"The is a short string", "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a set literal, so it's expected to be wrapped in parens when splitting to avoid implicit str concatenation.", short_call("arg", {"key": "value"}), "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a set literal.", ("parens should be stripped for short string in set")} + +S2 = {"This is a really long string that can't be expected to fit in one line and is the only child of a set literal."} + +T1 = ("The is a short string", "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a tuple literal, so it's expected to be wrapped in parens when splitting to avoid implicit str concatenation.", short_call("arg", {"key": "value"}), "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a tuple literal.", ("parens should be stripped for short string in list")) + +T2 = ("This is a really long string that can't be expected to fit in one line and is the only child of a tuple literal.",) + +func_with_keywords(my_arg, my_kwarg="Long keyword strings also need to be wrapped, but they will probably need to be handled a little bit differently.") + +bad_split1 = ( + 'But what should happen when code has already been formatted but in the wrong way? Like' + " with a space at the end instead of the beginning. Or what about when it is split too soon?" +) + +bad_split2 = "But what should happen when code has already " \ + "been formatted but in the wrong way? Like " \ + "with a space at the end instead of the " \ + "beginning. Or what about when it is split too " \ + "soon? In the case of a split that is too " \ + "short, black will try to honer the custom " \ + "split." + +bad_split3 = ( + "What if we have inline comments on " # First Comment + "each line of a bad split? In that " # Second Comment + "case, we should just leave it alone." # Third Comment +) + +bad_split_func1( + "But what should happen when code has already " + "been formatted but in the wrong way? Like " + "with a space at the end instead of the " + "beginning. Or what about when it is split too " + "soon? In the case of a split that is too " + "short, black will try to honer the custom " + "split.", + xxx, yyy, zzz +) + +bad_split_func2( + xxx, yyy, zzz, + long_string_kwarg="But what should happen when code has already been formatted but in the wrong way? Like " + "with a space at the end instead of the beginning. Or what about when it is split too " + "soon?", +) + +bad_split_func3( + ( + "But what should happen when code has already " + r"been formatted but in the wrong way? Like " + "with a space at the end instead of the " + r"beginning. Or what about when it is split too " + r"soon? In the case of a split that is too " + "short, black will try to honer the custom " + "split." + ), + xxx, + yyy, + zzz, +) + +inline_comments_func1( + "if there are inline " + "comments in the middle " + # Here is the standard alone comment. + "of the implicitly concatenated " + "string, we should handle " + "them correctly", + xxx, +) + +inline_comments_func2( + "what if the string is very very very very very very very very very very long and this part does " + "not fit into a single line? " + # Here is the standard alone comment. + "then the string should still be properly handled by merging and splitting " + "it into parts that fit in line length.", + xxx, +) + +raw_string = r"This is a long raw string. When re-formatting this string, black needs to make sure it prepends the 'r' onto the new string." + +fmt_string1 = "We also need to be sure to preserve any and all {} which may or may not be attached to the string in question.".format("method calls") + +fmt_string2 = "But what about when the string is {} but {}".format("short", "the method call is really really really really really really really really long?") + +old_fmt_string1 = "While we are on the topic of %s, we should also note that old-style formatting must also be preserved, since some %s still uses it." % ("formatting", "code") + +old_fmt_string2 = "This is a %s %s %s %s" % ("really really really really really", "old", "way to format strings!", "Use f-strings instead!") + +old_fmt_string3 = "Whereas only the strings after the percent sign were long in the last example, this example uses a long initial string as well. This is another %s %s %s %s" % ("really really really really really", "old", "way to format strings!", "Use f-strings instead!") + +fstring = f"f-strings definitely make things more {difficult} than they need to be for {{black}}. But boy they sure are handy. The problem is that some lines will need to have the 'f' whereas others do not. This {line}, for example, needs one." + +fstring_with_no_fexprs = f"Some regular string that needs to get split certainly but is NOT an fstring by any means whatsoever." + +comment_string = "Long lines with inline comments should have their comments appended to the reformatted string's enclosing right parentheses." # This comment gets thrown to the top. + +arg_comment_string = print("Long lines with inline comments which are apart of (and not the only member of) an argument list should have their comments appended to the reformatted string's enclosing left parentheses.", # This comment gets thrown to the top. + "Arg #2", "Arg #3", "Arg #4", "Arg #5") + +pragma_comment_string1 = "Lines which end with an inline pragma comment of the form `# : <...>` should be left alone." # noqa: E501 + +pragma_comment_string2 = "Lines which end with an inline pragma comment of the form `# : <...>` should be left alone." # noqa + +"""This is a really really really long triple quote string and it should not be touched.""" + +triple_quote_string = """This is a really really really long triple quote string assignment and it should not be touched.""" + +assert some_type_of_boolean_expression, "Followed by a really really really long string that is used to provide context to the AssertionError exception." + +assert some_type_of_boolean_expression, "Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic string {}.".format("formatting") + +assert some_type_of_boolean_expression, "Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic string %s." % "formatting" + +assert some_type_of_boolean_expression, "Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic %s %s." % ("string", "formatting") + +some_function_call("With a reallly generic name and with a really really long string that is, at some point down the line, " + added + " to a variable and then added to another string.") + +some_function_call("With a reallly generic name and with a really really long string that is, at some point down the line, " + added + " to a variable and then added to another string. But then what happens when the final string is also supppppperrrrr long?! Well then that second (realllllllly long) string should be split too.", "and a second argument", and_a_third) + +return "A really really really really really really really really really really really really really long {} {}".format("return", "value") + +func_with_bad_comma( + "This is a really long string argument to a function that has a trailing comma which should NOT be there.", +) + +func_with_bad_comma( + "This is a really long string argument to a function that has a trailing comma which should NOT be there.", # comment after comma +) + +func_with_bad_comma( + ( + "This is a really long string argument to a function that has a trailing comma" + " which should NOT be there." + ), +) + +func_with_bad_comma( + ( + "This is a really long string argument to a function that has a trailing comma" + " which should NOT be there." + ), # comment after comma +) + +func_with_bad_parens_that_wont_fit_in_one_line( + ("short string that should have parens stripped"), + x, + y, + z +) + +func_with_bad_parens_that_wont_fit_in_one_line( + x, + y, + ("short string that should have parens stripped"), + z +) + +func_with_bad_parens( + ("short string that should have parens stripped"), + x, + y, + z, +) + +func_with_bad_parens( + x, + y, + ("short string that should have parens stripped"), + z, +) + +annotated_variable: Final = "This is a large " + STRING + " that has been " + CONCATENATED + "using the '+' operator." +annotated_variable: Final = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped." +annotated_variable: Literal["fakse_literal"] = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped." + +backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\" +backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\\\" +backslashes = "This is a really 'long' string with \"embedded double quotes\" and 'single' quotes that also handles checking for an odd number of backslashes \\\", like this...\\\\\\" + +short_string = ( + "Hi" + " there." +) + +func_call( + short_string=( + "Hi" + " there." + ) +) + +raw_strings = r"Don't" " get" r" merged" " unless they are all raw." + +def foo(): + yield "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three." + +x = f"This is a {{really}} long string that needs to be split without a doubt (i.e. most definitely). In short, this {string} that can't possibly be {{expected}} to fit all together on one line. In {fact} it may even take up three or more lines... like four or five... but probably just four." + +long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # type: ignore + " of it." +) + +long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # noqa + " of it." +) + +long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # pylint: disable=some-pylint-check + " of it." +) + +string_with_nameescape = ( + "........................................................................ \N{LAO KO LA}" +) + +string_with_nameescape = ( + "........................................................................... \N{LAO KO LA}" +) + +string_with_nameescape = ( + "............................................................................ \N{LAO KO LA}" +) + +string_with_nameescape_and_escaped_backslash = ( + "...................................................................... \\\N{LAO KO LA}" +) + +string_with_nameescape_and_escaped_backslash = ( + "......................................................................... \\\N{LAO KO LA}" +) + +string_with_nameescape_and_escaped_backslash = ( + ".......................................................................... \\\N{LAO KO LA}" +) + +string_with_escaped_nameescape = ( + "........................................................................ \\N{LAO KO LA}" +) + +string_with_escaped_nameescape = ( + "........................................................................... \\N{LAO KO LA}" +) + +msg = lambda x: f"this is a very very very long lambda value {x} that doesn't fit on a single line" + +dict_with_lambda_values = { + "join": lambda j: ( + f"{j.__class__.__name__}({some_function_call(j.left)}, " + f"{some_function_call(j.right)})" + ), +} + +# Complex string concatenations with a method call in the middle. +code = ( + (" return [\n") + + ( + ", \n".join( + " (%r, self.%s, visitor.%s)" + % (attrname, attrname, visit_name) + for attrname, visit_name in names + ) + ) + + ("\n ]\n") +) + + +# Test case of an outer string' parens enclose an inner string's parens. +call(body=("%s %s" % ((",".join(items)), suffix))) + +log.info(f'Skipping: {desc["db_id"]=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]=} {desc["exposure_max"]=}') + +log.info(f"Skipping: {desc['db_id']=} {desc['ms_name']} {money=} {dte=} {pos_share=} {desc['status']=} {desc['exposure_max']=}") + +log.info(f'Skipping: {desc["db_id"]} {foo("bar",x=123)} {"foo" != "bar"} {(x := "abc=")} {pos_share=} {desc["status"]} {desc["exposure_max"]}') + +log.info(f'Skipping: {desc["db_id"]} {desc["ms_name"]} {money=} {(x := "abc=")=} {pos_share=} {desc["status"]} {desc["exposure_max"]}') + +log.info(f'Skipping: {desc["db_id"]} {foo("bar",x=123)=} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}') + +log.info(f'Skipping: {foo("asdf")=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}') + +log.info(f'Skipping: {"a" == "b" == "c" == "d"} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}') + +log.info(f'Skipping: {"a" == "b" == "c" == "d"=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}') + +log.info(f'Skipping: { longer_longer_longer_longer_longer_longer_name [ "db_id" ] [ "another_key" ] = : .3f }') + +log.info(f'''Skipping: {"a" == 'b'} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}''') + +log.info(f'''Skipping: {'a' == "b"=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}''') + +log.info(f"""Skipping: {'a' == 'b'} {desc['ms_name']} {money=} {dte=} {pos_share=} {desc['status']} {desc['exposure_max']}""") +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,175 +1,108 @@ +-x = ( +- "This is a really long string that can't possibly be expected to fit all together" +- " on one line. In fact it may even take up three or more lines... like four or" +- " five... but probably just three." +-) ++x = "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three." + +-x += ( +- "This is a really long string that can't possibly be expected to fit all together" +- " on one line. In fact it may even take up three or more lines... like four or" +- " five... but probably just three." +-) ++x += "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three." + + y = "Short string" + + print( +- "This is a really long string inside of a print statement with extra arguments" +- " attached at the end of it.", ++ "This is a really long string inside of a print statement with extra arguments attached at the end of it.", + x, + y, + z, + ) + + print( +- "This is a really long string inside of a print statement with no extra arguments" +- " attached at the end of it." ++ "This is a really long string inside of a print statement with no extra arguments attached at the end of it." + ) + + D1 = { +- "The First": ( +- "This is a really long string that can't possibly be expected to fit all" +- " together on one line. Also it is inside a dictionary, so formatting is more" +- " difficult." +- ), +- "The Second": ( +- "This is another really really (not really) long string that also can't be" +- " expected to fit on one line and is, like the other string, inside a" +- " dictionary." +- ), ++ "The First": "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.", ++ "The Second": "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary.", + } + + D2 = { +- 1.0: ( +- "This is a really long string that can't possibly be expected to fit all" +- " together on one line. Also it is inside a dictionary, so formatting is more" +- " difficult." +- ), +- 2.0: ( +- "This is another really really (not really) long string that also can't be" +- " expected to fit on one line and is, like the other string, inside a" +- " dictionary." +- ), ++ 1.0: "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.", ++ 2.0: "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary.", + } + + D3 = { +- x: ( +- "This is a really long string that can't possibly be expected to fit all" +- " together on one line. Also it is inside a dictionary, so formatting is more" +- " difficult." +- ), +- y: ( +- "This is another really really (not really) long string that also can't be" +- " expected to fit on one line and is, like the other string, inside a" +- " dictionary." +- ), ++ x: "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.", ++ y: "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary.", + } + + D4 = { +- "A long and ridiculous {}".format(string_key): ( +- "This is a really really really long string that has to go i,side of a" +- " dictionary. It is soooo bad." +- ), +- some_func("calling", "some", "stuff"): ( +- "This is a really really really long string that has to go inside of a" +- " dictionary. It is {soooo} bad (#{x}).".format(sooo="soooo", x=2) ++ "A long and ridiculous {}".format( ++ string_key ++ ): "This is a really really really long string that has to go i,side of a dictionary. It is soooo bad.", ++ some_func( ++ "calling", "some", "stuff" ++ ): "This is a really really really long string that has to go inside of a dictionary. It is {soooo} bad (#{x}).".format( ++ sooo="soooo", x=2 + ), + "A %s %s" +- % ("formatted", "string"): ( +- "This is a really really really long string that has to go inside of a" +- " dictionary. It is %s bad (#%d)." % ("soooo", 2) +- ), ++ % ( ++ "formatted", ++ "string", ++ ): "This is a really really really long string that has to go inside of a dictionary. It is %s bad (#%d)." ++ % ("soooo", 2), + } + + D5 = { # Test for https://github.com/psf/black/issues/3261 +- "This is a really long string that can't be expected to fit in one line and is used as a nested dict's key": { +- "inner": "value" +- }, ++ ( ++ "This is a really long string that can't be expected to fit in one line and is used as a nested dict's key" ++ ): {"inner": "value"}, + } + + D6 = { # Test for https://github.com/psf/black/issues/3261 +- "This is a really long string that can't be expected to fit in one line and is used as a dict's key": [ +- "value1", +- "value2", +- ], ++ ( ++ "This is a really long string that can't be expected to fit in one line and is used as a dict's key" ++ ): ["value1", "value2"], + } + + L1 = [ + "The is a short string", +- ( +- "This is a really long string that can't possibly be expected to fit all" +- " together on one line. Also it is inside a list literal, so it's expected to" +- " be wrapped in parens when splitting to avoid implicit str concatenation." +- ), ++ "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a list literal, so it's expected to be wrapped in parens when splitting to avoid implicit str concatenation.", + short_call("arg", {"key": "value"}), +- ( +- "This is another really really (not really) long string that also can't be" +- " expected to fit on one line and is, like the other string, inside a list" +- " literal." +- ), +- "parens should be stripped for short string in list", ++ "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a list literal.", ++ ("parens should be stripped for short string in list"), + ] + + L2 = [ +- "This is a really long string that can't be expected to fit in one line and is the" +- " only child of a list literal." ++ "This is a really long string that can't be expected to fit in one line and is the only child of a list literal." + ] + + S1 = { + "The is a short string", +- ( +- "This is a really long string that can't possibly be expected to fit all" +- " together on one line. Also it is inside a set literal, so it's expected to be" +- " wrapped in parens when splitting to avoid implicit str concatenation." +- ), ++ "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a set literal, so it's expected to be wrapped in parens when splitting to avoid implicit str concatenation.", + short_call("arg", {"key": "value"}), +- ( +- "This is another really really (not really) long string that also can't be" +- " expected to fit on one line and is, like the other string, inside a set" +- " literal." +- ), +- "parens should be stripped for short string in set", ++ "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a set literal.", ++ ("parens should be stripped for short string in set"), + } + + S2 = { +- "This is a really long string that can't be expected to fit in one line and is the" +- " only child of a set literal." ++ "This is a really long string that can't be expected to fit in one line and is the only child of a set literal." + } + + T1 = ( + "The is a short string", +- ( +- "This is a really long string that can't possibly be expected to fit all" +- " together on one line. Also it is inside a tuple literal, so it's expected to" +- " be wrapped in parens when splitting to avoid implicit str concatenation." +- ), ++ "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a tuple literal, so it's expected to be wrapped in parens when splitting to avoid implicit str concatenation.", + short_call("arg", {"key": "value"}), +- ( +- "This is another really really (not really) long string that also can't be" +- " expected to fit on one line and is, like the other string, inside a tuple" +- " literal." +- ), +- "parens should be stripped for short string in list", ++ "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a tuple literal.", ++ ("parens should be stripped for short string in list"), + ) + + T2 = ( +- ( +- "This is a really long string that can't be expected to fit in one line and is" +- " the only child of a tuple literal." +- ), ++ "This is a really long string that can't be expected to fit in one line and is the only child of a tuple literal.", + ) + + func_with_keywords( + my_arg, +- my_kwarg=( +- "Long keyword strings also need to be wrapped, but they will probably need to" +- " be handled a little bit differently." +- ), ++ my_kwarg="Long keyword strings also need to be wrapped, but they will probably need to be handled a little bit differently.", + ) + + bad_split1 = ( +- "But what should happen when code has already been formatted but in the wrong way?" +- " Like with a space at the end instead of the beginning. Or what about when it is" +- " split too soon?" ++ "But what should happen when code has already been formatted but in the wrong way? Like" ++ " with a space at the end instead of the beginning. Or what about when it is split too soon?" + ) + + bad_split2 = ( +@@ -205,11 +138,9 @@ + xxx, + yyy, + zzz, +- long_string_kwarg=( +- "But what should happen when code has already been formatted but in the wrong" +- " way? Like with a space at the end instead of the beginning. Or what about" +- " when it is split too soon?" +- ), ++ long_string_kwarg="But what should happen when code has already been formatted but in the wrong way? Like " ++ "with a space at the end instead of the beginning. Or what about when it is split too " ++ "soon?", + ) + + bad_split_func3( +@@ -228,29 +159,28 @@ + ) + + inline_comments_func1( +- "if there are inline comments in the middle " ++ "if there are inline " ++ "comments in the middle " + # Here is the standard alone comment. +- "of the implicitly concatenated string, we should handle them correctly", ++ "of the implicitly concatenated " ++ "string, we should handle " ++ "them correctly", + xxx, + ) + + inline_comments_func2( +- "what if the string is very very very very very very very very very very long and" +- " this part does not fit into a single line? " ++ "what if the string is very very very very very very very very very very long and this part does " ++ "not fit into a single line? " + # Here is the standard alone comment. + "then the string should still be properly handled by merging and splitting " + "it into parts that fit in line length.", + xxx, + ) + +-raw_string = ( +- r"This is a long raw string. When re-formatting this string, black needs to make" +- r" sure it prepends the 'r' onto the new string." +-) ++raw_string = r"This is a long raw string. When re-formatting this string, black needs to make sure it prepends the 'r' onto the new string." + +-fmt_string1 = ( +- "We also need to be sure to preserve any and all {} which may or may not be" +- " attached to the string in question.".format("method calls") ++fmt_string1 = "We also need to be sure to preserve any and all {} which may or may not be attached to the string in question.".format( ++ "method calls" + ) + + fmt_string2 = "But what about when the string is {} but {}".format( +@@ -259,8 +189,8 @@ + ) + + old_fmt_string1 = ( +- "While we are on the topic of %s, we should also note that old-style formatting" +- " must also be preserved, since some %s still uses it." % ("formatting", "code") ++ "While we are on the topic of %s, we should also note that old-style formatting must also be preserved, since some %s still uses it." ++ % ("formatting", "code") + ) + + old_fmt_string2 = "This is a %s %s %s %s" % ( +@@ -271,8 +201,7 @@ + ) + + old_fmt_string3 = ( +- "Whereas only the strings after the percent sign were long in the last example," +- " this example uses a long initial string as well. This is another %s %s %s %s" ++ "Whereas only the strings after the percent sign were long in the last example, this example uses a long initial string as well. This is another %s %s %s %s" + % ( + "really really really really really", + "old", +@@ -281,26 +210,14 @@ + ) + ) + +-fstring = ( +- f"f-strings definitely make things more {difficult} than they need to be for" +- " {black}. But boy they sure are handy. The problem is that some lines will need" +- f" to have the 'f' whereas others do not. This {line}, for example, needs one." +-) ++fstring = f"f-strings definitely make things more {difficult} than they need to be for {{black}}. But boy they sure are handy. The problem is that some lines will need to have the 'f' whereas others do not. This {line}, for example, needs one." + +-fstring_with_no_fexprs = ( +- f"Some regular string that needs to get split certainly but is NOT an fstring by" +- f" any means whatsoever." +-) ++fstring_with_no_fexprs = f"Some regular string that needs to get split certainly but is NOT an fstring by any means whatsoever." + +-comment_string = ( # This comment gets thrown to the top. +- "Long lines with inline comments should have their comments appended to the" +- " reformatted string's enclosing right parentheses." +-) ++comment_string = "Long lines with inline comments should have their comments appended to the reformatted string's enclosing right parentheses." # This comment gets thrown to the top. + + arg_comment_string = print( +- "Long lines with inline comments which are apart of (and not the only member of) an" +- " argument list should have their comments appended to the reformatted string's" +- " enclosing left parentheses.", # This comment gets thrown to the top. ++ "Long lines with inline comments which are apart of (and not the only member of) an argument list should have their comments appended to the reformatted string's enclosing left parentheses.", # This comment gets thrown to the top. + "Arg #2", + "Arg #3", + "Arg #4", +@@ -315,80 +232,72 @@ + + triple_quote_string = """This is a really really really long triple quote string assignment and it should not be touched.""" + +-assert some_type_of_boolean_expression, ( +- "Followed by a really really really long string that is used to provide context to" +- " the AssertionError exception." +-) ++assert some_type_of_boolean_expression, "Followed by a really really really long string that is used to provide context to the AssertionError exception." + +-assert some_type_of_boolean_expression, ( +- "Followed by a really really really long string that is used to provide context to" +- " the AssertionError exception, which uses dynamic string {}.".format("formatting") ++assert some_type_of_boolean_expression, "Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic string {}.".format( ++ "formatting" + ) + + assert some_type_of_boolean_expression, ( +- "Followed by a really really really long string that is used to provide context to" +- " the AssertionError exception, which uses dynamic string %s." % "formatting" ++ "Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic string %s." ++ % "formatting" + ) + + assert some_type_of_boolean_expression, ( +- "Followed by a really really really long string that is used to provide context to" +- " the AssertionError exception, which uses dynamic %s %s." ++ "Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic %s %s." + % ("string", "formatting") + ) + + some_function_call( +- "With a reallly generic name and with a really really long string that is, at some" +- " point down the line, " ++ "With a reallly generic name and with a really really long string that is, at some point down the line, " + + added + + " to a variable and then added to another string." + ) + + some_function_call( +- "With a reallly generic name and with a really really long string that is, at some" +- " point down the line, " ++ "With a reallly generic name and with a really really long string that is, at some point down the line, " + + added +- + " to a variable and then added to another string. But then what happens when the" +- " final string is also supppppperrrrr long?! Well then that second (realllllllly" +- " long) string should be split too.", ++ + " to a variable and then added to another string. But then what happens when the final string is also supppppperrrrr long?! Well then that second (realllllllly long) string should be split too.", + "and a second argument", + and_a_third, + ) + +-return ( +- "A really really really really really really really really really really really" +- " really really long {} {}".format("return", "value") ++return "A really really really really really really really really really really really really really long {} {}".format( ++ "return", "value" + ) + + func_with_bad_comma( +- "This is a really long string argument to a function that has a trailing comma" +- " which should NOT be there.", ++ "This is a really long string argument to a function that has a trailing comma which should NOT be there.", + ) + + func_with_bad_comma( +- "This is a really long string argument to a function that has a trailing comma" +- " which should NOT be there.", # comment after comma ++ "This is a really long string argument to a function that has a trailing comma which should NOT be there.", # comment after comma + ) + + func_with_bad_comma( +- "This is a really long string argument to a function that has a trailing comma" +- " which should NOT be there.", ++ ( ++ "This is a really long string argument to a function that has a trailing comma" ++ " which should NOT be there." ++ ), + ) + + func_with_bad_comma( +- "This is a really long string argument to a function that has a trailing comma" +- " which should NOT be there.", # comment after comma ++ ( ++ "This is a really long string argument to a function that has a trailing comma" ++ " which should NOT be there." ++ ), # comment after comma + ) + + func_with_bad_parens_that_wont_fit_in_one_line( +- "short string that should have parens stripped", x, y, z ++ ("short string that should have parens stripped"), x, y, z + ) + + func_with_bad_parens_that_wont_fit_in_one_line( +- x, y, "short string that should have parens stripped", z ++ x, y, ("short string that should have parens stripped"), z + ) + + func_with_bad_parens( +- "short string that should have parens stripped", ++ ("short string that should have parens stripped"), + x, + y, + z, +@@ -397,7 +306,7 @@ + func_with_bad_parens( + x, + y, +- "short string that should have parens stripped", ++ ("short string that should have parens stripped"), + z, + ) + +@@ -408,50 +317,27 @@ + + CONCATENATED + + "using the '+' operator." + ) +-annotated_variable: Final = ( +- "This is a large string that has a type annotation attached to it. A type" +- " annotation should NOT stop a long string from being wrapped." +-) +-annotated_variable: Literal["fakse_literal"] = ( +- "This is a large string that has a type annotation attached to it. A type" +- " annotation should NOT stop a long string from being wrapped." +-) ++annotated_variable: Final = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped." ++annotated_variable: Literal[ ++ "fakse_literal" ++] = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped." + +-backslashes = ( +- "This is a really long string with \"embedded\" double quotes and 'single' quotes" +- " that also handles checking for an even number of backslashes \\" +-) +-backslashes = ( +- "This is a really long string with \"embedded\" double quotes and 'single' quotes" +- " that also handles checking for an even number of backslashes \\\\" +-) +-backslashes = ( +- "This is a really 'long' string with \"embedded double quotes\" and 'single' quotes" +- ' that also handles checking for an odd number of backslashes \\", like' +- " this...\\\\\\" +-) ++backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\" ++backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\\\" ++backslashes = "This is a really 'long' string with \"embedded double quotes\" and 'single' quotes that also handles checking for an odd number of backslashes \\\", like this...\\\\\\" + +-short_string = "Hi there." ++short_string = "Hi" " there." + +-func_call(short_string="Hi there.") ++func_call(short_string=("Hi" " there.")) + + raw_strings = r"Don't" " get" r" merged" " unless they are all raw." + + + def foo(): +- yield ( +- "This is a really long string that can't possibly be expected to fit all" +- " together on one line. In fact it may even take up three or more lines... like" +- " four or five... but probably just three." +- ) ++ yield "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three." + + +-x = ( +- "This is a {really} long string that needs to be split without a doubt (i.e." +- f" most definitely). In short, this {string} that can't possibly be {{expected}} to" +- f" fit all together on one line. In {fact} it may even take up three or more" +- " lines... like four or five... but probably just four." +-) ++x = f"This is a {{really}} long string that needs to be split without a doubt (i.e. most definitely). In short, this {string} that can't possibly be {{expected}} to fit all together on one line. In {fact} it may even take up three or more lines... like four or five... but probably just four." + + long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # type: ignore +@@ -468,51 +354,24 @@ + " of it." + ) + +-string_with_nameescape = ( +- "........................................................................" +- " \N{LAO KO LA}" +-) ++string_with_nameescape = "........................................................................ \N{LAO KO LA}" + +-string_with_nameescape = ( +- "..........................................................................." +- " \N{LAO KO LA}" +-) ++string_with_nameescape = "........................................................................... \N{LAO KO LA}" + +-string_with_nameescape = ( +- "............................................................................" +- " \N{LAO KO LA}" +-) ++string_with_nameescape = "............................................................................ \N{LAO KO LA}" + +-string_with_nameescape_and_escaped_backslash = ( +- "......................................................................" +- " \\\N{LAO KO LA}" +-) ++string_with_nameescape_and_escaped_backslash = "...................................................................... \\\N{LAO KO LA}" + +-string_with_nameescape_and_escaped_backslash = ( +- "........................................................................." +- " \\\N{LAO KO LA}" +-) ++string_with_nameescape_and_escaped_backslash = "......................................................................... \\\N{LAO KO LA}" + +-string_with_nameescape_and_escaped_backslash = ( +- ".........................................................................." +- " \\\N{LAO KO LA}" +-) ++string_with_nameescape_and_escaped_backslash = ".......................................................................... \\\N{LAO KO LA}" + +-string_with_escaped_nameescape = ( +- "........................................................................ \\N{LAO" +- " KO LA}" +-) ++string_with_escaped_nameescape = "........................................................................ \\N{LAO KO LA}" + +-string_with_escaped_nameescape = ( +- "..........................................................................." +- " \\N{LAO KO LA}" +-) ++string_with_escaped_nameescape = "........................................................................... \\N{LAO KO LA}" + + msg = ( +- lambda x: ( +- f"this is a very very very long lambda value {x} that doesn't fit on a single" +- " line" +- ) ++ lambda x: f"this is a very very very long lambda value {x} that doesn't fit on a single line" + ) + + dict_with_lambda_values = { +@@ -524,61 +383,54 @@ + + # Complex string concatenations with a method call in the middle. + code = ( +- " return [\n" +- + ", \n".join( +- " (%r, self.%s, visitor.%s)" % (attrname, attrname, visit_name) +- for attrname, visit_name in names ++ (" return [\n") ++ + ( ++ ", \n".join( ++ " (%r, self.%s, visitor.%s)" % (attrname, attrname, visit_name) ++ for attrname, visit_name in names ++ ) + ) +- + "\n ]\n" ++ + ("\n ]\n") + ) + + + # Test case of an outer string' parens enclose an inner string's parens. +-call(body="%s %s" % (",".join(items), suffix)) ++call(body=("%s %s" % ((",".join(items)), suffix))) + + log.info( +- "Skipping:" +- f' {desc["db_id"]=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]=} {desc["exposure_max"]=}' ++ f'Skipping: {desc["db_id"]=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]=} {desc["exposure_max"]=}' + ) + + log.info( +- "Skipping:" +- f" {desc['db_id']=} {desc['ms_name']} {money=} {dte=} {pos_share=} {desc['status']=} {desc['exposure_max']=}" ++ f"Skipping: {desc['db_id']=} {desc['ms_name']} {money=} {dte=} {pos_share=} {desc['status']=} {desc['exposure_max']=}" + ) + + log.info( +- "Skipping:" +- f" {desc['db_id']} {foo('bar',x=123)} {'foo' != 'bar'} {(x := 'abc=')} {pos_share=} {desc['status']} {desc['exposure_max']}" ++ f'Skipping: {desc["db_id"]} {foo("bar",x=123)} {"foo" != "bar"} {(x := "abc=")} {pos_share=} {desc["status"]} {desc["exposure_max"]}' + ) + + log.info( +- "Skipping:" +- f' {desc["db_id"]} {desc["ms_name"]} {money=} {(x := "abc=")=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' ++ f'Skipping: {desc["db_id"]} {desc["ms_name"]} {money=} {(x := "abc=")=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' + ) + + log.info( +- "Skipping:" +- f' {desc["db_id"]} {foo("bar",x=123)=} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' ++ f'Skipping: {desc["db_id"]} {foo("bar",x=123)=} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' + ) + + log.info( +- "Skipping:" +- f' {foo("asdf")=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' ++ f'Skipping: {foo("asdf")=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' + ) + + log.info( +- "Skipping:" +- f" {'a' == 'b' == 'c' == 'd'} {desc['ms_name']} {money=} {dte=} {pos_share=} {desc['status']} {desc['exposure_max']}" ++ f'Skipping: {"a" == "b" == "c" == "d"} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' + ) + + log.info( +- "Skipping:" +- f' {"a" == "b" == "c" == "d"=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' ++ f'Skipping: {"a" == "b" == "c" == "d"=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' + ) + + log.info( +- "Skipping:" +- f' { longer_longer_longer_longer_longer_longer_name [ "db_id" ] [ "another_key" ] = : .3f }' ++ f'Skipping: { longer_longer_longer_longer_longer_longer_name [ "db_id" ] [ "another_key" ] = : .3f }' + ) + + log.info( +``` + +## Ruff Output + +```python +x = "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three." + +x += "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three." + +y = "Short string" + +print( + "This is a really long string inside of a print statement with extra arguments attached at the end of it.", + x, + y, + z, +) + +print( + "This is a really long string inside of a print statement with no extra arguments attached at the end of it." +) + +D1 = { + "The First": "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.", + "The Second": "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary.", +} + +D2 = { + 1.0: "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.", + 2.0: "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary.", +} + +D3 = { + x: "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a dictionary, so formatting is more difficult.", + y: "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a dictionary.", +} + +D4 = { + "A long and ridiculous {}".format( + string_key + ): "This is a really really really long string that has to go i,side of a dictionary. It is soooo bad.", + some_func( + "calling", "some", "stuff" + ): "This is a really really really long string that has to go inside of a dictionary. It is {soooo} bad (#{x}).".format( + sooo="soooo", x=2 + ), + "A %s %s" + % ( + "formatted", + "string", + ): "This is a really really really long string that has to go inside of a dictionary. It is %s bad (#%d)." + % ("soooo", 2), +} + +D5 = { # Test for https://github.com/psf/black/issues/3261 + ( + "This is a really long string that can't be expected to fit in one line and is used as a nested dict's key" + ): {"inner": "value"}, +} + +D6 = { # Test for https://github.com/psf/black/issues/3261 + ( + "This is a really long string that can't be expected to fit in one line and is used as a dict's key" + ): ["value1", "value2"], +} + +L1 = [ + "The is a short string", + "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a list literal, so it's expected to be wrapped in parens when splitting to avoid implicit str concatenation.", + short_call("arg", {"key": "value"}), + "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a list literal.", + ("parens should be stripped for short string in list"), +] + +L2 = [ + "This is a really long string that can't be expected to fit in one line and is the only child of a list literal." +] + +S1 = { + "The is a short string", + "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a set literal, so it's expected to be wrapped in parens when splitting to avoid implicit str concatenation.", + short_call("arg", {"key": "value"}), + "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a set literal.", + ("parens should be stripped for short string in set"), +} + +S2 = { + "This is a really long string that can't be expected to fit in one line and is the only child of a set literal." +} + +T1 = ( + "The is a short string", + "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a tuple literal, so it's expected to be wrapped in parens when splitting to avoid implicit str concatenation.", + short_call("arg", {"key": "value"}), + "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a tuple literal.", + ("parens should be stripped for short string in list"), +) + +T2 = ( + "This is a really long string that can't be expected to fit in one line and is the only child of a tuple literal.", +) + +func_with_keywords( + my_arg, + my_kwarg="Long keyword strings also need to be wrapped, but they will probably need to be handled a little bit differently.", +) + +bad_split1 = ( + "But what should happen when code has already been formatted but in the wrong way? Like" + " with a space at the end instead of the beginning. Or what about when it is split too soon?" +) + +bad_split2 = ( + "But what should happen when code has already " + "been formatted but in the wrong way? Like " + "with a space at the end instead of the " + "beginning. Or what about when it is split too " + "soon? In the case of a split that is too " + "short, black will try to honer the custom " + "split." +) + +bad_split3 = ( + "What if we have inline comments on " # First Comment + "each line of a bad split? In that " # Second Comment + "case, we should just leave it alone." # Third Comment +) + +bad_split_func1( + "But what should happen when code has already " + "been formatted but in the wrong way? Like " + "with a space at the end instead of the " + "beginning. Or what about when it is split too " + "soon? In the case of a split that is too " + "short, black will try to honer the custom " + "split.", + xxx, + yyy, + zzz, +) + +bad_split_func2( + xxx, + yyy, + zzz, + long_string_kwarg="But what should happen when code has already been formatted but in the wrong way? Like " + "with a space at the end instead of the beginning. Or what about when it is split too " + "soon?", +) + +bad_split_func3( + ( + "But what should happen when code has already " + r"been formatted but in the wrong way? Like " + "with a space at the end instead of the " + r"beginning. Or what about when it is split too " + r"soon? In the case of a split that is too " + "short, black will try to honer the custom " + "split." + ), + xxx, + yyy, + zzz, +) + +inline_comments_func1( + "if there are inline " + "comments in the middle " + # Here is the standard alone comment. + "of the implicitly concatenated " + "string, we should handle " + "them correctly", + xxx, +) + +inline_comments_func2( + "what if the string is very very very very very very very very very very long and this part does " + "not fit into a single line? " + # Here is the standard alone comment. + "then the string should still be properly handled by merging and splitting " + "it into parts that fit in line length.", + xxx, +) + +raw_string = r"This is a long raw string. When re-formatting this string, black needs to make sure it prepends the 'r' onto the new string." + +fmt_string1 = "We also need to be sure to preserve any and all {} which may or may not be attached to the string in question.".format( + "method calls" +) + +fmt_string2 = "But what about when the string is {} but {}".format( + "short", + "the method call is really really really really really really really really long?", +) + +old_fmt_string1 = ( + "While we are on the topic of %s, we should also note that old-style formatting must also be preserved, since some %s still uses it." + % ("formatting", "code") +) + +old_fmt_string2 = "This is a %s %s %s %s" % ( + "really really really really really", + "old", + "way to format strings!", + "Use f-strings instead!", +) + +old_fmt_string3 = ( + "Whereas only the strings after the percent sign were long in the last example, this example uses a long initial string as well. This is another %s %s %s %s" + % ( + "really really really really really", + "old", + "way to format strings!", + "Use f-strings instead!", + ) +) + +fstring = f"f-strings definitely make things more {difficult} than they need to be for {{black}}. But boy they sure are handy. The problem is that some lines will need to have the 'f' whereas others do not. This {line}, for example, needs one." + +fstring_with_no_fexprs = f"Some regular string that needs to get split certainly but is NOT an fstring by any means whatsoever." + +comment_string = "Long lines with inline comments should have their comments appended to the reformatted string's enclosing right parentheses." # This comment gets thrown to the top. + +arg_comment_string = print( + "Long lines with inline comments which are apart of (and not the only member of) an argument list should have their comments appended to the reformatted string's enclosing left parentheses.", # This comment gets thrown to the top. + "Arg #2", + "Arg #3", + "Arg #4", + "Arg #5", +) + +pragma_comment_string1 = "Lines which end with an inline pragma comment of the form `# : <...>` should be left alone." # noqa: E501 + +pragma_comment_string2 = "Lines which end with an inline pragma comment of the form `# : <...>` should be left alone." # noqa + +"""This is a really really really long triple quote string and it should not be touched.""" + +triple_quote_string = """This is a really really really long triple quote string assignment and it should not be touched.""" + +assert some_type_of_boolean_expression, "Followed by a really really really long string that is used to provide context to the AssertionError exception." + +assert some_type_of_boolean_expression, "Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic string {}.".format( + "formatting" +) + +assert some_type_of_boolean_expression, ( + "Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic string %s." + % "formatting" +) + +assert some_type_of_boolean_expression, ( + "Followed by a really really really long string that is used to provide context to the AssertionError exception, which uses dynamic %s %s." + % ("string", "formatting") +) + +some_function_call( + "With a reallly generic name and with a really really long string that is, at some point down the line, " + + added + + " to a variable and then added to another string." +) + +some_function_call( + "With a reallly generic name and with a really really long string that is, at some point down the line, " + + added + + " to a variable and then added to another string. But then what happens when the final string is also supppppperrrrr long?! Well then that second (realllllllly long) string should be split too.", + "and a second argument", + and_a_third, +) + +return "A really really really really really really really really really really really really really long {} {}".format( + "return", "value" +) + +func_with_bad_comma( + "This is a really long string argument to a function that has a trailing comma which should NOT be there.", +) + +func_with_bad_comma( + "This is a really long string argument to a function that has a trailing comma which should NOT be there.", # comment after comma +) + +func_with_bad_comma( + ( + "This is a really long string argument to a function that has a trailing comma" + " which should NOT be there." + ), +) + +func_with_bad_comma( + ( + "This is a really long string argument to a function that has a trailing comma" + " which should NOT be there." + ), # comment after comma +) + +func_with_bad_parens_that_wont_fit_in_one_line( + ("short string that should have parens stripped"), x, y, z +) + +func_with_bad_parens_that_wont_fit_in_one_line( + x, y, ("short string that should have parens stripped"), z +) + +func_with_bad_parens( + ("short string that should have parens stripped"), + x, + y, + z, +) + +func_with_bad_parens( + x, + y, + ("short string that should have parens stripped"), + z, +) + +annotated_variable: Final = ( + "This is a large " + + STRING + + " that has been " + + CONCATENATED + + "using the '+' operator." +) +annotated_variable: Final = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped." +annotated_variable: Literal[ + "fakse_literal" +] = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped." + +backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\" +backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\\\" +backslashes = "This is a really 'long' string with \"embedded double quotes\" and 'single' quotes that also handles checking for an odd number of backslashes \\\", like this...\\\\\\" + +short_string = "Hi" " there." + +func_call(short_string=("Hi" " there.")) + +raw_strings = r"Don't" " get" r" merged" " unless they are all raw." + + +def foo(): + yield "This is a really long string that can't possibly be expected to fit all together on one line. In fact it may even take up three or more lines... like four or five... but probably just three." + + +x = f"This is a {{really}} long string that needs to be split without a doubt (i.e. most definitely). In short, this {string} that can't possibly be {{expected}} to fit all together on one line. In {fact} it may even take up three or more lines... like four or five... but probably just four." + +long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # type: ignore + " of it." +) + +long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # noqa + " of it." +) + +long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # pylint: disable=some-pylint-check + " of it." +) + +string_with_nameescape = "........................................................................ \N{LAO KO LA}" + +string_with_nameescape = "........................................................................... \N{LAO KO LA}" + +string_with_nameescape = "............................................................................ \N{LAO KO LA}" + +string_with_nameescape_and_escaped_backslash = "...................................................................... \\\N{LAO KO LA}" + +string_with_nameescape_and_escaped_backslash = "......................................................................... \\\N{LAO KO LA}" + +string_with_nameescape_and_escaped_backslash = ".......................................................................... \\\N{LAO KO LA}" + +string_with_escaped_nameescape = "........................................................................ \\N{LAO KO LA}" + +string_with_escaped_nameescape = "........................................................................... \\N{LAO KO LA}" + +msg = ( + lambda x: f"this is a very very very long lambda value {x} that doesn't fit on a single line" +) + +dict_with_lambda_values = { + "join": lambda j: ( + f"{j.__class__.__name__}({some_function_call(j.left)}, " + f"{some_function_call(j.right)})" + ), +} + +# Complex string concatenations with a method call in the middle. +code = ( + (" return [\n") + + ( + ", \n".join( + " (%r, self.%s, visitor.%s)" % (attrname, attrname, visit_name) + for attrname, visit_name in names + ) + ) + + ("\n ]\n") +) + + +# Test case of an outer string' parens enclose an inner string's parens. +call(body=("%s %s" % ((",".join(items)), suffix))) + +log.info( + f'Skipping: {desc["db_id"]=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]=} {desc["exposure_max"]=}' +) + +log.info( + f"Skipping: {desc['db_id']=} {desc['ms_name']} {money=} {dte=} {pos_share=} {desc['status']=} {desc['exposure_max']=}" +) + +log.info( + f'Skipping: {desc["db_id"]} {foo("bar",x=123)} {"foo" != "bar"} {(x := "abc=")} {pos_share=} {desc["status"]} {desc["exposure_max"]}' +) + +log.info( + f'Skipping: {desc["db_id"]} {desc["ms_name"]} {money=} {(x := "abc=")=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' +) + +log.info( + f'Skipping: {desc["db_id"]} {foo("bar",x=123)=} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' +) + +log.info( + f'Skipping: {foo("asdf")=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' +) + +log.info( + f'Skipping: {"a" == "b" == "c" == "d"} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' +) + +log.info( + f'Skipping: {"a" == "b" == "c" == "d"=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' +) + +log.info( + f'Skipping: { longer_longer_longer_longer_longer_longer_name [ "db_id" ] [ "another_key" ] = : .3f }' +) + +log.info( + f"""Skipping: {"a" == 'b'} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}""" +) + +log.info( + f"""Skipping: {'a' == "b"=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}""" +) + +log.info( + f"""Skipping: {'a' == 'b'} {desc['ms_name']} {money=} {dte=} {pos_share=} {desc['status']} {desc['exposure_max']}""" +) +``` + +## Black Output + +```python +x = ( + "This is a really long string that can't possibly be expected to fit all together" + " on one line. In fact it may even take up three or more lines... like four or" + " five... but probably just three." +) + +x += ( + "This is a really long string that can't possibly be expected to fit all together" + " on one line. In fact it may even take up three or more lines... like four or" + " five... but probably just three." +) + +y = "Short string" + +print( + "This is a really long string inside of a print statement with extra arguments" + " attached at the end of it.", + x, + y, + z, +) + +print( + "This is a really long string inside of a print statement with no extra arguments" + " attached at the end of it." +) + +D1 = { + "The First": ( + "This is a really long string that can't possibly be expected to fit all" + " together on one line. Also it is inside a dictionary, so formatting is more" + " difficult." + ), + "The Second": ( + "This is another really really (not really) long string that also can't be" + " expected to fit on one line and is, like the other string, inside a" + " dictionary." + ), +} + +D2 = { + 1.0: ( + "This is a really long string that can't possibly be expected to fit all" + " together on one line. Also it is inside a dictionary, so formatting is more" + " difficult." + ), + 2.0: ( + "This is another really really (not really) long string that also can't be" + " expected to fit on one line and is, like the other string, inside a" + " dictionary." + ), +} + +D3 = { + x: ( + "This is a really long string that can't possibly be expected to fit all" + " together on one line. Also it is inside a dictionary, so formatting is more" + " difficult." + ), + y: ( + "This is another really really (not really) long string that also can't be" + " expected to fit on one line and is, like the other string, inside a" + " dictionary." + ), +} + +D4 = { + "A long and ridiculous {}".format(string_key): ( + "This is a really really really long string that has to go i,side of a" + " dictionary. It is soooo bad." + ), + some_func("calling", "some", "stuff"): ( + "This is a really really really long string that has to go inside of a" + " dictionary. It is {soooo} bad (#{x}).".format(sooo="soooo", x=2) + ), + "A %s %s" + % ("formatted", "string"): ( + "This is a really really really long string that has to go inside of a" + " dictionary. It is %s bad (#%d)." % ("soooo", 2) + ), +} + +D5 = { # Test for https://github.com/psf/black/issues/3261 + "This is a really long string that can't be expected to fit in one line and is used as a nested dict's key": { + "inner": "value" + }, +} + +D6 = { # Test for https://github.com/psf/black/issues/3261 + "This is a really long string that can't be expected to fit in one line and is used as a dict's key": [ + "value1", + "value2", + ], +} + +L1 = [ + "The is a short string", + ( + "This is a really long string that can't possibly be expected to fit all" + " together on one line. Also it is inside a list literal, so it's expected to" + " be wrapped in parens when splitting to avoid implicit str concatenation." + ), + short_call("arg", {"key": "value"}), + ( + "This is another really really (not really) long string that also can't be" + " expected to fit on one line and is, like the other string, inside a list" + " literal." + ), + "parens should be stripped for short string in list", +] + +L2 = [ + "This is a really long string that can't be expected to fit in one line and is the" + " only child of a list literal." +] + +S1 = { + "The is a short string", + ( + "This is a really long string that can't possibly be expected to fit all" + " together on one line. Also it is inside a set literal, so it's expected to be" + " wrapped in parens when splitting to avoid implicit str concatenation." + ), + short_call("arg", {"key": "value"}), + ( + "This is another really really (not really) long string that also can't be" + " expected to fit on one line and is, like the other string, inside a set" + " literal." + ), + "parens should be stripped for short string in set", +} + +S2 = { + "This is a really long string that can't be expected to fit in one line and is the" + " only child of a set literal." +} + +T1 = ( + "The is a short string", + ( + "This is a really long string that can't possibly be expected to fit all" + " together on one line. Also it is inside a tuple literal, so it's expected to" + " be wrapped in parens when splitting to avoid implicit str concatenation." + ), + short_call("arg", {"key": "value"}), + ( + "This is another really really (not really) long string that also can't be" + " expected to fit on one line and is, like the other string, inside a tuple" + " literal." + ), + "parens should be stripped for short string in list", +) + +T2 = ( + ( + "This is a really long string that can't be expected to fit in one line and is" + " the only child of a tuple literal." + ), +) + +func_with_keywords( + my_arg, + my_kwarg=( + "Long keyword strings also need to be wrapped, but they will probably need to" + " be handled a little bit differently." + ), +) + +bad_split1 = ( + "But what should happen when code has already been formatted but in the wrong way?" + " Like with a space at the end instead of the beginning. Or what about when it is" + " split too soon?" +) + +bad_split2 = ( + "But what should happen when code has already " + "been formatted but in the wrong way? Like " + "with a space at the end instead of the " + "beginning. Or what about when it is split too " + "soon? In the case of a split that is too " + "short, black will try to honer the custom " + "split." +) + +bad_split3 = ( + "What if we have inline comments on " # First Comment + "each line of a bad split? In that " # Second Comment + "case, we should just leave it alone." # Third Comment +) + +bad_split_func1( + "But what should happen when code has already " + "been formatted but in the wrong way? Like " + "with a space at the end instead of the " + "beginning. Or what about when it is split too " + "soon? In the case of a split that is too " + "short, black will try to honer the custom " + "split.", + xxx, + yyy, + zzz, +) + +bad_split_func2( + xxx, + yyy, + zzz, + long_string_kwarg=( + "But what should happen when code has already been formatted but in the wrong" + " way? Like with a space at the end instead of the beginning. Or what about" + " when it is split too soon?" + ), +) + +bad_split_func3( + ( + "But what should happen when code has already " + r"been formatted but in the wrong way? Like " + "with a space at the end instead of the " + r"beginning. Or what about when it is split too " + r"soon? In the case of a split that is too " + "short, black will try to honer the custom " + "split." + ), + xxx, + yyy, + zzz, +) + +inline_comments_func1( + "if there are inline comments in the middle " + # Here is the standard alone comment. + "of the implicitly concatenated string, we should handle them correctly", + xxx, +) + +inline_comments_func2( + "what if the string is very very very very very very very very very very long and" + " this part does not fit into a single line? " + # Here is the standard alone comment. + "then the string should still be properly handled by merging and splitting " + "it into parts that fit in line length.", + xxx, +) + +raw_string = ( + r"This is a long raw string. When re-formatting this string, black needs to make" + r" sure it prepends the 'r' onto the new string." +) + +fmt_string1 = ( + "We also need to be sure to preserve any and all {} which may or may not be" + " attached to the string in question.".format("method calls") +) + +fmt_string2 = "But what about when the string is {} but {}".format( + "short", + "the method call is really really really really really really really really long?", +) + +old_fmt_string1 = ( + "While we are on the topic of %s, we should also note that old-style formatting" + " must also be preserved, since some %s still uses it." % ("formatting", "code") +) + +old_fmt_string2 = "This is a %s %s %s %s" % ( + "really really really really really", + "old", + "way to format strings!", + "Use f-strings instead!", +) + +old_fmt_string3 = ( + "Whereas only the strings after the percent sign were long in the last example," + " this example uses a long initial string as well. This is another %s %s %s %s" + % ( + "really really really really really", + "old", + "way to format strings!", + "Use f-strings instead!", + ) +) + +fstring = ( + f"f-strings definitely make things more {difficult} than they need to be for" + " {black}. But boy they sure are handy. The problem is that some lines will need" + f" to have the 'f' whereas others do not. This {line}, for example, needs one." +) + +fstring_with_no_fexprs = ( + f"Some regular string that needs to get split certainly but is NOT an fstring by" + f" any means whatsoever." +) + +comment_string = ( # This comment gets thrown to the top. + "Long lines with inline comments should have their comments appended to the" + " reformatted string's enclosing right parentheses." +) + +arg_comment_string = print( + "Long lines with inline comments which are apart of (and not the only member of) an" + " argument list should have their comments appended to the reformatted string's" + " enclosing left parentheses.", # This comment gets thrown to the top. + "Arg #2", + "Arg #3", + "Arg #4", + "Arg #5", +) + +pragma_comment_string1 = "Lines which end with an inline pragma comment of the form `# : <...>` should be left alone." # noqa: E501 + +pragma_comment_string2 = "Lines which end with an inline pragma comment of the form `# : <...>` should be left alone." # noqa + +"""This is a really really really long triple quote string and it should not be touched.""" + +triple_quote_string = """This is a really really really long triple quote string assignment and it should not be touched.""" + +assert some_type_of_boolean_expression, ( + "Followed by a really really really long string that is used to provide context to" + " the AssertionError exception." +) + +assert some_type_of_boolean_expression, ( + "Followed by a really really really long string that is used to provide context to" + " the AssertionError exception, which uses dynamic string {}.".format("formatting") +) + +assert some_type_of_boolean_expression, ( + "Followed by a really really really long string that is used to provide context to" + " the AssertionError exception, which uses dynamic string %s." % "formatting" +) + +assert some_type_of_boolean_expression, ( + "Followed by a really really really long string that is used to provide context to" + " the AssertionError exception, which uses dynamic %s %s." + % ("string", "formatting") +) + +some_function_call( + "With a reallly generic name and with a really really long string that is, at some" + " point down the line, " + + added + + " to a variable and then added to another string." +) + +some_function_call( + "With a reallly generic name and with a really really long string that is, at some" + " point down the line, " + + added + + " to a variable and then added to another string. But then what happens when the" + " final string is also supppppperrrrr long?! Well then that second (realllllllly" + " long) string should be split too.", + "and a second argument", + and_a_third, +) + +return ( + "A really really really really really really really really really really really" + " really really long {} {}".format("return", "value") +) + +func_with_bad_comma( + "This is a really long string argument to a function that has a trailing comma" + " which should NOT be there.", +) + +func_with_bad_comma( + "This is a really long string argument to a function that has a trailing comma" + " which should NOT be there.", # comment after comma +) + +func_with_bad_comma( + "This is a really long string argument to a function that has a trailing comma" + " which should NOT be there.", +) + +func_with_bad_comma( + "This is a really long string argument to a function that has a trailing comma" + " which should NOT be there.", # comment after comma +) + +func_with_bad_parens_that_wont_fit_in_one_line( + "short string that should have parens stripped", x, y, z +) + +func_with_bad_parens_that_wont_fit_in_one_line( + x, y, "short string that should have parens stripped", z +) + +func_with_bad_parens( + "short string that should have parens stripped", + x, + y, + z, +) + +func_with_bad_parens( + x, + y, + "short string that should have parens stripped", + z, +) + +annotated_variable: Final = ( + "This is a large " + + STRING + + " that has been " + + CONCATENATED + + "using the '+' operator." +) +annotated_variable: Final = ( + "This is a large string that has a type annotation attached to it. A type" + " annotation should NOT stop a long string from being wrapped." +) +annotated_variable: Literal["fakse_literal"] = ( + "This is a large string that has a type annotation attached to it. A type" + " annotation should NOT stop a long string from being wrapped." +) + +backslashes = ( + "This is a really long string with \"embedded\" double quotes and 'single' quotes" + " that also handles checking for an even number of backslashes \\" +) +backslashes = ( + "This is a really long string with \"embedded\" double quotes and 'single' quotes" + " that also handles checking for an even number of backslashes \\\\" +) +backslashes = ( + "This is a really 'long' string with \"embedded double quotes\" and 'single' quotes" + ' that also handles checking for an odd number of backslashes \\", like' + " this...\\\\\\" +) + +short_string = "Hi there." + +func_call(short_string="Hi there.") + +raw_strings = r"Don't" " get" r" merged" " unless they are all raw." + + +def foo(): + yield ( + "This is a really long string that can't possibly be expected to fit all" + " together on one line. In fact it may even take up three or more lines... like" + " four or five... but probably just three." + ) + + +x = ( + "This is a {really} long string that needs to be split without a doubt (i.e." + f" most definitely). In short, this {string} that can't possibly be {{expected}} to" + f" fit all together on one line. In {fact} it may even take up three or more" + " lines... like four or five... but probably just four." +) + +long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # type: ignore + " of it." +) + +long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # noqa + " of it." +) + +long_unmergable_string_with_pragma = ( + "This is a really long string that can't be merged because it has a likely pragma at the end" # pylint: disable=some-pylint-check + " of it." +) + +string_with_nameescape = ( + "........................................................................" + " \N{LAO KO LA}" +) + +string_with_nameescape = ( + "..........................................................................." + " \N{LAO KO LA}" +) + +string_with_nameescape = ( + "............................................................................" + " \N{LAO KO LA}" +) + +string_with_nameescape_and_escaped_backslash = ( + "......................................................................" + " \\\N{LAO KO LA}" +) + +string_with_nameescape_and_escaped_backslash = ( + "........................................................................." + " \\\N{LAO KO LA}" +) + +string_with_nameescape_and_escaped_backslash = ( + ".........................................................................." + " \\\N{LAO KO LA}" +) + +string_with_escaped_nameescape = ( + "........................................................................ \\N{LAO" + " KO LA}" +) + +string_with_escaped_nameescape = ( + "..........................................................................." + " \\N{LAO KO LA}" +) + +msg = ( + lambda x: ( + f"this is a very very very long lambda value {x} that doesn't fit on a single" + " line" + ) +) + +dict_with_lambda_values = { + "join": lambda j: ( + f"{j.__class__.__name__}({some_function_call(j.left)}, " + f"{some_function_call(j.right)})" + ), +} + +# Complex string concatenations with a method call in the middle. +code = ( + " return [\n" + + ", \n".join( + " (%r, self.%s, visitor.%s)" % (attrname, attrname, visit_name) + for attrname, visit_name in names + ) + + "\n ]\n" +) + + +# Test case of an outer string' parens enclose an inner string's parens. +call(body="%s %s" % (",".join(items), suffix)) + +log.info( + "Skipping:" + f' {desc["db_id"]=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]=} {desc["exposure_max"]=}' +) + +log.info( + "Skipping:" + f" {desc['db_id']=} {desc['ms_name']} {money=} {dte=} {pos_share=} {desc['status']=} {desc['exposure_max']=}" +) + +log.info( + "Skipping:" + f" {desc['db_id']} {foo('bar',x=123)} {'foo' != 'bar'} {(x := 'abc=')} {pos_share=} {desc['status']} {desc['exposure_max']}" +) + +log.info( + "Skipping:" + f' {desc["db_id"]} {desc["ms_name"]} {money=} {(x := "abc=")=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' +) + +log.info( + "Skipping:" + f' {desc["db_id"]} {foo("bar",x=123)=} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' +) + +log.info( + "Skipping:" + f' {foo("asdf")=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' +) + +log.info( + "Skipping:" + f" {'a' == 'b' == 'c' == 'd'} {desc['ms_name']} {money=} {dte=} {pos_share=} {desc['status']} {desc['exposure_max']}" +) + +log.info( + "Skipping:" + f' {"a" == "b" == "c" == "d"=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}' +) + +log.info( + "Skipping:" + f' { longer_longer_longer_longer_longer_longer_name [ "db_id" ] [ "another_key" ] = : .3f }' +) + +log.info( + f"""Skipping: {"a" == 'b'} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}""" +) + +log.info( + f"""Skipping: {'a' == "b"=} {desc["ms_name"]} {money=} {dte=} {pos_share=} {desc["status"]} {desc["exposure_max"]}""" +) + +log.info( + f"""Skipping: {'a' == 'b'} {desc['ms_name']} {money=} {dte=} {pos_share=} {desc['status']} {desc['exposure_max']}""" +) +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__east_asian_width.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__east_asian_width.py.snap new file mode 100644 index 0000000000000..7ba67786746f8 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__east_asian_width.py.snap @@ -0,0 +1,75 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__east_asian_width.py +--- +## Input + +```python +# The following strings do not have not-so-many chars, but are long enough +# when these are rendered in a monospace font (if the renderer respects +# Unicode East Asian Width properties). +hangul = '코드포인트 수는 적으나 실제 터미널이나 에디터에서 렌더링될 땐 너무 길어서 줄바꿈이 필요한 문자열' +hanzi = '中文測試:代碼點數量少,但在真正的終端模擬器或編輯器中呈現時太長,因此需要換行的字符串。' +japanese = 'コードポイントの数は少ないが、実際の端末エミュレータやエディタでレンダリングされる時は長すぎる為、改行が要る文字列' +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,16 +1,6 @@ + # The following strings do not have not-so-many chars, but are long enough + # when these are rendered in a monospace font (if the renderer respects + # Unicode East Asian Width properties). +-hangul = ( +- "코드포인트 수는 적으나 실제 터미널이나 에디터에서 렌더링될 땐 너무 길어서 줄바꿈이" +- " 필요한 문자열" +-) +-hanzi = ( +- "中文測試:代碼點數量少,但在真正的終端模擬器或編輯器中呈現時太長," +- "因此需要換行的字符串。" +-) +-japanese = ( +- "コードポイントの数は少ないが、" +- "実際の端末エミュレータやエディタでレンダリングされる時は長すぎる為、" +- "改行が要る文字列" +-) ++hangul = "코드포인트 수는 적으나 실제 터미널이나 에디터에서 렌더링될 땐 너무 길어서 줄바꿈이 필요한 문자열" ++hanzi = "中文測試:代碼點數量少,但在真正的終端模擬器或編輯器中呈現時太長,因此需要換行的字符串。" ++japanese = "コードポイントの数は少ないが、実際の端末エミュレータやエディタでレンダリングされる時は長すぎる為、改行が要る文字列" +``` + +## Ruff Output + +```python +# The following strings do not have not-so-many chars, but are long enough +# when these are rendered in a monospace font (if the renderer respects +# Unicode East Asian Width properties). +hangul = "코드포인트 수는 적으나 실제 터미널이나 에디터에서 렌더링될 땐 너무 길어서 줄바꿈이 필요한 문자열" +hanzi = "中文測試:代碼點數量少,但在真正的終端模擬器或編輯器中呈現時太長,因此需要換行的字符串。" +japanese = "コードポイントの数は少ないが、実際の端末エミュレータやエディタでレンダリングされる時は長すぎる為、改行が要る文字列" +``` + +## Black Output + +```python +# The following strings do not have not-so-many chars, but are long enough +# when these are rendered in a monospace font (if the renderer respects +# Unicode East Asian Width properties). +hangul = ( + "코드포인트 수는 적으나 실제 터미널이나 에디터에서 렌더링될 땐 너무 길어서 줄바꿈이" + " 필요한 문자열" +) +hanzi = ( + "中文測試:代碼點數量少,但在真正的終端模擬器或編輯器中呈現時太長," + "因此需要換行的字符串。" +) +japanese = ( + "コードポイントの数は少ないが、" + "実際の端末エミュレータやエディタでレンダリングされる時は長すぎる為、" + "改行が要る文字列" +) +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__edge_case.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__edge_case.py.snap new file mode 100644 index 0000000000000..4db3fa039c2a8 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__edge_case.py.snap @@ -0,0 +1,340 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__edge_case.py +--- +## Input + +```python +some_variable = "This string is long but not so long that it needs to be split just yet" +some_variable = 'This string is long but not so long that it needs to be split just yet' +some_variable = "This string is long, just long enough that it needs to be split, u get?" +some_variable = 'This string is long, just long enough that it needs to be split, u get?' +some_variable = "This string is long, just long enough that it needs to be split, u get? So we stay" +some_variable = 'This string is long, just long enough that it needs to be split, u get? So we stay' +some_variable = "This string is long, just long enough that it needs to be split, u get? So we split" +some_variable = 'This string is long, just long enough that it needs to be split, u get? So we split' +some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at alll".format("ha") +some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at allll".format("ha") +some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at alllllllllll".format("ha") +some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at allllllllllll".format("ha") +some_variable = "This is a long string that will end with a method that is not calleddd".format +addition_inside_tuple = ( + some_string_inside_a_variable + + "Some string that is just long enough to cause a split to take place.............", + xyz, + "Some really long string that needs to get split eventually but I'm running out of things to say" + some_string_inside_a_variable +) +addition_inside_tuple = ( + some_string_inside_a_variable + + "Some string that is just long enough to cause a split to take place.............." +) +return "Hi there. This is areally really reallllly long string that needs to be split!!!" +ternary_expression = ( + "Short String" + if some_condition + else "This is a really long string that will eventually need to be split right here." +) +return f'{x}/b/c/d/d/d/dadfjsadjsaidoaisjdsfjaofjdfijaidfjaodfjaoifjodjafojdoajaaaaaaaaaaa' +return f'{x}/b/c/d/d/d/dadfjsadjsaidoaisjdsfjaofjdfijaidfjaodfjaoifjodjafojdoajaaaaaaaaaaaa' +assert str(result) == "This long string should be split at some point right close to or around hereeeeeee" +assert str(result) < "This long string should be split at some point right close to or around hereeeeee" +assert "A format string: %s" % "This long string should be split at some point right close to or around hereeeeeee" != result +msg += "This long string should be wrapped in parens at some point right around hereeeee" +msg += "This long string should be split at some point right close to or around hereeeeeeee" +msg += "This long string should not be split at any point ever since it is just righttt" +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -12,51 +12,33 @@ + some_variable = ( + "This string is long, just long enough that it needs to be split, u get? So we stay" + ) +-some_variable = ( +- "This string is long, just long enough that it needs to be split, u get? So we" +- " split" +-) +-some_variable = ( +- "This string is long, just long enough that it needs to be split, u get? So we" +- " split" +-) +-some_variable = ( +- "This string is long but not so long that it needs hahahah toooooo be so greatttt" +- " {} that I just can't think of any more good words to say about it at alll".format( +- "ha" +- ) ++some_variable = "This string is long, just long enough that it needs to be split, u get? So we split" ++some_variable = "This string is long, just long enough that it needs to be split, u get? So we split" ++some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at alll".format( ++ "ha" + ) +-some_variable = ( +- "This string is long but not so long that it needs hahahah toooooo be so greatttt" +- " {} that I just can't think of any more good words to say about it at allll" +- .format("ha") ++some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at allll".format( ++ "ha" + ) +-some_variable = ( +- "This string is long but not so long that it needs hahahah toooooo be so greatttt" +- " {} that I just can't think of any more good words to say about it at alllllllllll" +- .format("ha") ++some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at alllllllllll".format( ++ "ha" + ) +-some_variable = ( +- "This string is long but not so long that it needs hahahah toooooo be so greatttt" +- " {} that I just can't think of any more good words to say about it at" +- " allllllllllll".format("ha") ++some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at allllllllllll".format( ++ "ha" + ) + some_variable = ( + "This is a long string that will end with a method that is not calleddd".format + ) + addition_inside_tuple = ( + some_string_inside_a_variable +- + "Some string that is just long enough to cause a split to take" +- " place.............", ++ + "Some string that is just long enough to cause a split to take place.............", + xyz, +- "Some really long string that needs to get split eventually but I'm running out of" +- " things to say" ++ "Some really long string that needs to get split eventually but I'm running out of things to say" + + some_string_inside_a_variable, + ) + addition_inside_tuple = ( + some_string_inside_a_variable +- + "Some string that is just long enough to cause a split to take" +- " place.............." ++ + "Some string that is just long enough to cause a split to take place.............." + ) + return ( + "Hi there. This is areally really reallllly long string that needs to be split!!!" +@@ -64,9 +46,7 @@ + ternary_expression = ( + "Short String" + if some_condition +- else ( +- "This is a really long string that will eventually need to be split right here." +- ) ++ else "This is a really long string that will eventually need to be split right here." + ) + return ( + f"{x}/b/c/d/d/d/dadfjsadjsaidoaisjdsfjaofjdfijaidfjaodfjaoifjodjafojdoajaaaaaaaaaaa" +@@ -74,25 +54,19 @@ + return f"{x}/b/c/d/d/d/dadfjsadjsaidoaisjdsfjaofjdfijaidfjaodfjaoifjodjafojdoajaaaaaaaaaaaa" + assert ( + str(result) +- == "This long string should be split at some point right close to or around" +- " hereeeeeee" ++ == "This long string should be split at some point right close to or around hereeeeeee" + ) + assert ( + str(result) +- < "This long string should be split at some point right close to or around" +- " hereeeeee" ++ < "This long string should be split at some point right close to or around hereeeeee" + ) + assert ( + "A format string: %s" +- % "This long string should be split at some point right close to or around" +- " hereeeeeee" ++ % "This long string should be split at some point right close to or around hereeeeeee" + != result + ) + msg += ( + "This long string should be wrapped in parens at some point right around hereeeee" + ) +-msg += ( +- "This long string should be split at some point right close to or around" +- " hereeeeeeee" +-) ++msg += "This long string should be split at some point right close to or around hereeeeeeee" + msg += "This long string should not be split at any point ever since it is just righttt" +``` + +## Ruff Output + +```python +some_variable = "This string is long but not so long that it needs to be split just yet" +some_variable = "This string is long but not so long that it needs to be split just yet" +some_variable = ( + "This string is long, just long enough that it needs to be split, u get?" +) +some_variable = ( + "This string is long, just long enough that it needs to be split, u get?" +) +some_variable = ( + "This string is long, just long enough that it needs to be split, u get? So we stay" +) +some_variable = ( + "This string is long, just long enough that it needs to be split, u get? So we stay" +) +some_variable = "This string is long, just long enough that it needs to be split, u get? So we split" +some_variable = "This string is long, just long enough that it needs to be split, u get? So we split" +some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at alll".format( + "ha" +) +some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at allll".format( + "ha" +) +some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at alllllllllll".format( + "ha" +) +some_variable = "This string is long but not so long that it needs hahahah toooooo be so greatttt {} that I just can't think of any more good words to say about it at allllllllllll".format( + "ha" +) +some_variable = ( + "This is a long string that will end with a method that is not calleddd".format +) +addition_inside_tuple = ( + some_string_inside_a_variable + + "Some string that is just long enough to cause a split to take place.............", + xyz, + "Some really long string that needs to get split eventually but I'm running out of things to say" + + some_string_inside_a_variable, +) +addition_inside_tuple = ( + some_string_inside_a_variable + + "Some string that is just long enough to cause a split to take place.............." +) +return ( + "Hi there. This is areally really reallllly long string that needs to be split!!!" +) +ternary_expression = ( + "Short String" + if some_condition + else "This is a really long string that will eventually need to be split right here." +) +return ( + f"{x}/b/c/d/d/d/dadfjsadjsaidoaisjdsfjaofjdfijaidfjaodfjaoifjodjafojdoajaaaaaaaaaaa" +) +return f"{x}/b/c/d/d/d/dadfjsadjsaidoaisjdsfjaofjdfijaidfjaodfjaoifjodjafojdoajaaaaaaaaaaaa" +assert ( + str(result) + == "This long string should be split at some point right close to or around hereeeeeee" +) +assert ( + str(result) + < "This long string should be split at some point right close to or around hereeeeee" +) +assert ( + "A format string: %s" + % "This long string should be split at some point right close to or around hereeeeeee" + != result +) +msg += ( + "This long string should be wrapped in parens at some point right around hereeeee" +) +msg += "This long string should be split at some point right close to or around hereeeeeeee" +msg += "This long string should not be split at any point ever since it is just righttt" +``` + +## Black Output + +```python +some_variable = "This string is long but not so long that it needs to be split just yet" +some_variable = "This string is long but not so long that it needs to be split just yet" +some_variable = ( + "This string is long, just long enough that it needs to be split, u get?" +) +some_variable = ( + "This string is long, just long enough that it needs to be split, u get?" +) +some_variable = ( + "This string is long, just long enough that it needs to be split, u get? So we stay" +) +some_variable = ( + "This string is long, just long enough that it needs to be split, u get? So we stay" +) +some_variable = ( + "This string is long, just long enough that it needs to be split, u get? So we" + " split" +) +some_variable = ( + "This string is long, just long enough that it needs to be split, u get? So we" + " split" +) +some_variable = ( + "This string is long but not so long that it needs hahahah toooooo be so greatttt" + " {} that I just can't think of any more good words to say about it at alll".format( + "ha" + ) +) +some_variable = ( + "This string is long but not so long that it needs hahahah toooooo be so greatttt" + " {} that I just can't think of any more good words to say about it at allll" + .format("ha") +) +some_variable = ( + "This string is long but not so long that it needs hahahah toooooo be so greatttt" + " {} that I just can't think of any more good words to say about it at alllllllllll" + .format("ha") +) +some_variable = ( + "This string is long but not so long that it needs hahahah toooooo be so greatttt" + " {} that I just can't think of any more good words to say about it at" + " allllllllllll".format("ha") +) +some_variable = ( + "This is a long string that will end with a method that is not calleddd".format +) +addition_inside_tuple = ( + some_string_inside_a_variable + + "Some string that is just long enough to cause a split to take" + " place.............", + xyz, + "Some really long string that needs to get split eventually but I'm running out of" + " things to say" + + some_string_inside_a_variable, +) +addition_inside_tuple = ( + some_string_inside_a_variable + + "Some string that is just long enough to cause a split to take" + " place.............." +) +return ( + "Hi there. This is areally really reallllly long string that needs to be split!!!" +) +ternary_expression = ( + "Short String" + if some_condition + else ( + "This is a really long string that will eventually need to be split right here." + ) +) +return ( + f"{x}/b/c/d/d/d/dadfjsadjsaidoaisjdsfjaofjdfijaidfjaodfjaoifjodjafojdoajaaaaaaaaaaa" +) +return f"{x}/b/c/d/d/d/dadfjsadjsaidoaisjdsfjaofjdfijaidfjaodfjaoifjodjafojdoajaaaaaaaaaaaa" +assert ( + str(result) + == "This long string should be split at some point right close to or around" + " hereeeeeee" +) +assert ( + str(result) + < "This long string should be split at some point right close to or around" + " hereeeeee" +) +assert ( + "A format string: %s" + % "This long string should be split at some point right close to or around" + " hereeeeeee" + != result +) +msg += ( + "This long string should be wrapped in parens at some point right around hereeeee" +) +msg += ( + "This long string should be split at some point right close to or around" + " hereeeeeeee" +) +msg += "This long string should not be split at any point ever since it is just righttt" +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__regression.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__regression.py.snap new file mode 100644 index 0000000000000..e05940e360ce9 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__regression.py.snap @@ -0,0 +1,2565 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__regression.py +--- +## Input + +```python +class A: + def foo(): + result = type(message)("") + + +# Don't merge multiline (e.g. triple-quoted) strings. +def foo(): + query = ( + """SELECT xxxxxxxxxxxxxxxxxxxx(xxx)""" + """ FROM xxxxxxxxxxxxxxxx WHERE xxxxxxxxxx AND xxx <> xxxxxxxxxxxxxx()""") + +# There was a bug where tuples were being identified as long strings. +long_tuple = ('Apple', 'Berry', 'Cherry', 'Dill', 'Evergreen', 'Fig', + 'Grape', 'Harry', 'Iglu', 'Jaguar') + +stupid_format_method_bug = "Some really long string that just so happens to be the {} {} to force the 'format' method to hang over the line length boundary. This is pretty annoying.".format("perfect", "length") + +class A: + def foo(): + os.system("This is a regression test. xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxxx.".format("xxxxxxxxxx", "xxxxxx", "xxxxxxxxxx")) + + +class A: + def foo(): + XXXXXXXXXXXX.append( + ( + "xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx, xxxx_xxxx_xxxxxxxxxx={})".format( + xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx + ), + my_var, + my_other_var, + ) + ) + +class A: + class B: + def foo(): + bar( + ( + "[{}]: xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx={}" + " xxxx_xxxx_xxxxxxxxxx={}, xxxx={})" + .format(xxxx._xxxxxxxxxxxxxx, xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx, xxxxxxx) + ), + varX, + varY, + varZ, + ) + +def foo(xxxx): + for (xxx_xxxx, _xxx_xxx, _xxx_xxxxx, xxx_xxxx) in xxxx: + for xxx in xxx_xxxx: + assert ("x" in xxx) or ( + xxx in xxx_xxx_xxxxx + ), "{0} xxxxxxx xx {1}, xxx {1} xx xxx xx xxxx xx xxx xxxx: xxx xxxx {2}".format( + xxx_xxxx, xxx, xxxxxx.xxxxxxx(xxx_xxx_xxxxx) + ) + +class A: + def disappearing_comment(): + return ( + ( # xx -x xxxxxxx xx xxx xxxxxxx. + '{{xxx_xxxxxxxxxx_xxxxxxxx}} xxx xxxx' + ' {} {{xxxx}} >&2' + .format( + "{xxxx} {xxxxxx}" + if xxxxx.xx_xxxxxxxxxx + else ( # Disappearing Comment + "--xxxxxxx --xxxxxx=x --xxxxxx-xxxxx=xxxxxx" + " --xxxxxx-xxxx=xxxxxxxxxxx.xxx" + ) + ) + ), + (x, y, z), + ) + +class A: + class B: + def foo(): + xxxxx_xxxx( + xx, "\t" + "@xxxxxx '{xxxx_xxx}\t' > {xxxxxx_xxxx}.xxxxxxx;" + "{xxxx_xxx} >> {xxxxxx_xxxx}.xxxxxxx 2>&1; xx=$$?;" + "xxxx $$xx" + .format(xxxx_xxx=xxxx_xxxxxxx, xxxxxx_xxxx=xxxxxxx + "/" + xxxx_xxx_xxxx, x=xxx_xxxxx_xxxxx_xxx), + x, + y, + z, + ) + +func_call_where_string_arg_has_method_call_and_bad_parens( + ( + "A long string with {}. This string is so long that it is ridiculous. It can't fit on one line at alllll.".format("formatting") + ), +) + +func_call_where_string_arg_has_old_fmt_and_bad_parens( + ( + "A long string with {}. This string is so long that it is ridiculous. It can't fit on one line at alllll." % "formatting" + ), +) + +func_call_where_string_arg_has_old_fmt_and_bad_parens( + ( + "A long string with {}. This {} is so long that it is ridiculous. It can't fit on one line at alllll." % ("formatting", "string") + ), +) + +class A: + def append(self): + if True: + xxxx.xxxxxxx.xxxxx( ('xxxxxxxxxx xxxx xx xxxxxx(%x) xx %x xxxx xx xxx %x.xx' + % (len(self) + 1, + xxxx.xxxxxxxxxx, + xxxx.xxxxxxxxxx)) + + (' %.3f (%s) to %.3f (%s).\n' + % (xxxx.xxxxxxxxx, + xxxx.xxxxxxxxxxxxxx(xxxx.xxxxxxxxx), + x, + xxxx.xxxxxxxxxxxxxx( xx) + ))) + +class A: + def foo(): + some_func_call( + 'xxxxxxxxxx', + ( + "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " + "\"xxxx xxxxxxx xxxxxx xxxx; xxxx xxxxxx_xxxxx xxxxxx xxxx; " + "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" " + ), + None, + ('xxxxxxxxxxx',), + ), + +class A: + def foo(): + some_func_call( + ( + "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " + "xxxx, ('xxxxxxx xxxxxx xxxx, xxxx') xxxxxx_xxxxx xxxxxx xxxx; " + "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" " + ), + None, + ('xxxxxxxxxxx',), + ), + +xxxxxxx = { 'xx' : 'xxxx xxxxxxx xxxxxxxxx -x xxx -x /xxx/{0} -x xxx,xxx -xx {1} \ +-xx {1} -xx xxx=xxx_xxxx,xxx_xx,xxx_xxx,xxx_xxxx,xxx_xx,xxx_xxx |\ + xxxxxx -x xxxxxxxx -x xxxxxxxx -x', + 'xx' : 'xxxx xxxxxxx xxxxxxxxx -x xxx -x /xxx/{0} -x xxx,xxx -xx {1} \ +-xx {1} -xx xxx=xxx_xxxx_xxx_xxxx,xxx_xx_xxx_xxxx,xxx_xxxx_xxx_xxxx,\ +xxx_xx_xxxx_xxxx,xxx_xxx_xxxx,xxx_xxx_xxxx xxxx=xxx | xxxxxx -x xxxxxxxx -x xxxxxxxx -x' +} + +class A: + def foo(self): + if True: + xxxxx_xxxxxxxxxxxx('xxx xxxxxx xxx xxxxxxxxx.xx xx xxxxxxxx. xxx xxxxxxxxxxxxx.xx xxxxxxx ' + + 'xx xxxxxx xxxxxx xxxxxx xx xxxxxxx xxx xxx ${0} xx x xxxxxxxx xxxxx'.xxxxxx(xxxxxx_xxxxxx_xxx)) + +class A: + class B: + def foo(): + row = { + 'xxxxxxxxxxxxxxx' : xxxxxx_xxxxx_xxxx, + # 'xxxxxxxxxxxxxxxxxxxxxxx' + # 'xxxxxxxxxxxxxxxxxxxxxx' + # 'xxxxxxxxxxxxxxxxxx' + # 'xxxxxxxxxxxxxxxxx' + 'xxxxxxxxxx' : xxxxx_xxxxx, + } + +class A: + def xxxx_xxx_xx_xxxxxxxxxx_xxxx_xxxxxxxxx(xxxx): + xxxxxxxx = [ + xxxxxxxxxxxxxxxx( + 'xxxx', + xxxxxxxxxxx={ + 'xxxx' : 1.0, + }, + xxxxxx={'xxxxxx 1' : xxxxxx(xxxx='xxxxxx 1', xxxxxx=600.0)}, + xxxxxxxx_xxxxxxx=0.0, + ), + xxxxxxxxxxxxxxxx( + 'xxxxxxx', + xxxxxxxxxxx={ + 'xxxx' : 1.0, + }, + xxxxxx={'xxxxxx 1' : xxxxxx(xxxx='xxxxxx 1', xxxxxx=200.0)}, + xxxxxxxx_xxxxxxx=0.0, + ), + xxxxxxxxxxxxxxxx( + 'xxxx', + ), + ] + +some_dictionary = { + 'xxxxx006': ['xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx0xx6xxxxxxxxxx2xxxxxx9xxxxxxxxxx0xxxxx1xxx2x/xx9xx6+x+xxxxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxxxx43xxx2xx2x4x++xxx6xxxxxxxxx+xxxxx/xx9x+xxxxxxxxxxxxxx8x15xxxxxxxxxxxxxxxxx82xx/xxxxxxxxxxxxxx/x5xxxxxxxxxxxxxx6xxxxxx74x4/xxx4x+xxxxxxxxx2xxxxxxxx87xxxxx4xxxxxxxx3xx0xxxxx4xxx1xx9xx5xxxxxxx/xxxxx5xx6xx4xxxx1x/x2xxxxxxxxxxxx64xxxxxxx1x0xx5xxxxxxxxxxxxxx== xxxxx000 xxxxxxxxxx\n', + 'xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx6xxxxxxxxxxxxxx9xxxxxxxxxxxxx3xxx9xxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxxxx2xxxx2xxx6xxxxx/xx54xxxxxxxxx4xxx3xxxxxx9xx3xxxxx39xxxxxxxxx5xx91xxxx7xxxxxx8xxxxxxxxxxxxxxxx9xxx93xxxxxxxxxxxxxxxxx7xxx8xx8xx4/x1xxxxx1x3xxxxxxxxxxxxx3xxxxxx9xx4xx4x7xxxxxxxxxxxxx1xxxxxxxxx7xxxxxxxxxxxxxx4xx6xxxxxxxxx9xxx7xxxx2xxxxxxxxxxxxxxxxxxxxxx8xxxxxxxxxxxxxxxxxxxx6xx== xxxxx010 xxxxxxxxxx\n'], + 'xxxxx016': ['xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx0xx6xxxxxxxxxx2xxxxxx9xxxxxxxxxx0xxxxx1xxx2x/xx9xx6+x+xxxxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxxxx43xxx2xx2x4x++xxx6xxxxxxxxx+xxxxx/xx9x+xxxxxxxxxxxxxx8x15xxxxxxxxxxxxxxxxx82xx/xxxxxxxxxxxxxx/x5xxxxxxxxxxxxxx6xxxxxx74x4/xxx4x+xxxxxxxxx2xxxxxxxx87xxxxx4xxxxxxxx3xx0xxxxx4xxx1xx9xx5xxxxxxx/xxxxx5xx6xx4xxxx1x/x2xxxxxxxxxxxx64xxxxxxx1x0xx5xxxxxxxxxxxxxx== xxxxx000 xxxxxxxxxx\n', + 'xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx6xxxxxxxxxxxxxx9xxxxxxxxxxxxx3xxx9xxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxxxx2xxxx2xxx6xxxxx/xx54xxxxxxxxx4xxx3xxxxxx9xx3xxxxx39xxxxxxxxx5xx91xxxx7xxxxxx8xxxxxxxxxxxxxxxx9xxx93xxxxxxxxxxxxxxxxx7xxx8xx8xx4/x1xxxxx1x3xxxxxxxxxxxxx3xxxxxx9xx4xx4x7xxxxxxxxxxxxx1xxxxxxxxx7xxxxxxxxxxxxxx4xx6xxxxxxxxx9xxx7xxxx2xxxxxxxxxxxxxxxxxxxxxx8xxxxxxxxxxxxxxxxxxxx6xx== xxxxx010 xxxxxxxxxx\n'] +} + +def foo(): + xxx_xxx = ( + 'xxxx xxx xxxxxxxx_xxxx xx "xxxxxxxxxx".' + '\n xxx: xxxxxx xxxxxxxx_xxxx=xxxxxxxxxx' + ) # xxxx xxxxxxxxxx xxxx xx xxxx xx xxx xxxxxxxx xxxxxx xxxxx. + +some_tuple = ("some string", "some string" " which should be joined") + +some_commented_string = ( # This comment stays at the top. + "This string is long but not so long that it needs hahahah toooooo be so greatttt" + " {} that I just can't think of any more good words to say about it at" + " allllllllllll".format("ha") # comments here are fine +) + +some_commented_string = ( + "This string is long but not so long that it needs hahahah toooooo be so greatttt" # But these + " {} that I just can't think of any more good words to say about it at" # comments will stay + " allllllllllll".format("ha") # comments here are fine +) + +lpar_and_rpar_have_comments = func_call( # LPAR Comment + "Long really ridiculous type of string that shouldn't really even exist at all. I mean commmme onnn!!!", # Comma Comment +) # RPAR Comment + +cmd_fstring = ( + f"sudo -E deluge-console info --detailed --sort-reverse=time_added " + f"{'' if ID is None else ID} | perl -nE 'print if /^{field}:/'" +) + +cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {'' if ID is None else ID} | perl -nE 'print if /^{field}:/'" + +cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {'{{}}' if ID is None else ID} | perl -nE 'print if /^{field}:/'" + +cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {{'' if ID is None else ID}} | perl -nE 'print if /^{field}:/'" + +fstring = f"This string really doesn't need to be an {{{{fstring}}}}, but this one most certainly, absolutely {does}." + +fstring = ( + f"We have to remember to escape {braces}." + " Like {these}." + f" But not {this}." +) + +class A: + class B: + def foo(): + st_error = STError( + f"This string ({string_leaf.value}) appears to be pointless (i.e. has" + " no parent)." + ) + +def foo(): + user_regex = _lazy_re_compile( + r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*\Z" # dot-atom + r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"\Z)', # quoted-string + re.IGNORECASE) + +def foo(): + user_regex = _lazy_re_compile( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # dot-atom + 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', # quoted-string + xyz + ) + +def foo(): + user_regex = _lazy_re_compile( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # dot-atom + 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', # quoted-string + xyz + ) + +class A: + class B: + def foo(): + if not hasattr(module, name): + raise ValueError( + "Could not find object %s in %s.\n" + "Please note that you cannot serialize things like inner " + "classes. Please move the object into the main module " + "body to use migrations.\n" + "For more information, see " + "https://docs.djangoproject.com/en/%s/topics/migrations/#serializing-values" + % (name, module_name, get_docs_version())) + +class A: + class B: + def foo(): + if not hasattr(module, name): + raise ValueError( + "Could not find object %s in %s.\nPlease note that you cannot serialize things like inner classes. Please move the object into the main module body to use migrations.\nFor more information, see https://docs.djangoproject.com/en/%s/topics/migrations/#serializing-values" + % (name, module_name, get_docs_version())) + +x = ( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +) + +class Step(StepBase): + def who(self): + self.cmd = 'SR AAAA-CORRECT NAME IS {last_name} {first_name}{middle_name} {title}/P{passenger_association}'.format( + last_name=last_name, + first_name=first_name, + middle_name=middle_name, + title=title, + passenger_association=passenger_association, + ) + +xxxxxxx_xxxxxx_xxxxxxx = xxx( + [ + xxxxxxxxxxxx( + xxxxxx_xxxxxxx=( + '((x.aaaaaaaaa = "xxxxxx.xxxxxxxxxxxxxxxxxxxxx") || (x.xxxxxxxxx = "xxxxxxxxxxxx")) && ' + # xxxxx xxxxxxxxxxxx xxxx xxx (xxxxxxxxxxxxxxxx) xx x xxxxxxxxx xx xxxxxx. + "(x.bbbbbbbbbbbb.xxx != " + '"xxx:xxx:xxx::cccccccccccc:xxxxxxx-xxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxxxx") && ' + ) + ) + ] +) + +if __name__ == "__main__": + for i in range(4, 8): + cmd = ( + r"for pid in $(ps aux | grep paster | grep -v grep | grep '\-%d' | awk '{print $2}'); do kill $pid; done" + % (i) + ) + +def A(): + def B(): + def C(): + def D(): + def E(): + def F(): + def G(): + assert ( + c_float(val[0][0] / val[0][1]).value + == c_float(value[0][0] / value[0][1]).value + ), "%s didn't roundtrip" % tag + +class xxxxxxxxxxxxxxxxxxxxx(xxxx.xxxxxxxxxxxxx): + def xxxxxxx_xxxxxx(xxxx): + assert xxxxxxx_xxxx in [ + x.xxxxx.xxxxxx.xxxxx.xxxxxx, + x.xxxxx.xxxxxx.xxxxx.xxxx, + ], ("xxxxxxxxxxx xxxxxxx xxxx (xxxxxx xxxx) %x xxx xxxxx" % xxxxxxx_xxxx) + +value.__dict__[ + key +] = "test" # set some Thrift field to non-None in the struct aa bb cc dd ee + +RE_ONE_BACKSLASH = { + "asdf_hjkl_jkl": re.compile( + r"(?>\n" +) + +assert str(suffix_arr) == ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) != ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) <= ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) >= ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) < ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) > ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) in "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', 'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', 'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +assert str(suffix_arr) not in "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', 'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', 'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +message = ( + f"1. Go to Google Developers Console and log in with your Google account." + "(https://console.developers.google.com/)" + "2. You should be prompted to create a new project (name does not matter)." + "3. Click on Enable APIs and Services at the top." + "4. In the list of APIs choose or search for YouTube Data API v3 and " + "click on it. Choose Enable." + "5. Click on Credentials on the left navigation bar." + "6. Click on Create Credential at the top." + '7. At the top click the link for "API key".' + "8. No application restrictions are needed. Click Create at the bottom." + "9. You now have a key to add to `{prefix}set api youtube api_key`" +) +message = ( + f"1. Go to Google Developers Console and log in with your Google account." + "(https://console.developers.google.com/)" + "2. You should be prompted to create a new project (name does not matter)." + f"3. Click on Enable APIs and Services at the top." + "4. In the list of APIs choose or search for YouTube Data API v3 and " + "click on it. Choose Enable." + f"5. Click on Credentials on the left navigation bar." + "6. Click on Create Credential at the top." + '7. At the top click the link for "API key".' + "8. No application restrictions are needed. Click Create at the bottom." + "9. You now have a key to add to `{prefix}set api youtube api_key`" +) +message = ( + f"1. Go to Google Developers Console and log in with your Google account." + "(https://console.developers.google.com/)" + "2. You should be prompted to create a new project (name does not matter)." + f"3. Click on Enable APIs and Services at the top." + "4. In the list of APIs choose or search for YouTube Data API v3 and " + "click on it. Choose Enable." + f"5. Click on Credentials on the left navigation bar." + "6. Click on Create Credential at the top." + '7. At the top click the link for "API key".' + "8. No application restrictions are needed. Click Create at the bottom." + f"9. You now have a key to add to `{prefix}set api youtube api_key`" +) + +# It shouldn't matter if the string prefixes are capitalized. +temp_msg = ( + F"{F'{humanize_number(pos)}.': <{pound_len+2}} " + F"{balance: <{bal_len + 5}} " + F"<<{author.display_name}>>\n" +) + +fstring = ( + F"We have to remember to escape {braces}." + " Like {these}." + F" But not {this}." +) + +welcome_to_programming = R"hello," R" world!" + +fstring = F"f-strings definitely make things more {difficult} than they need to be for {{black}}. But boy they sure are handy. The problem is that some lines will need to have the 'f' whereas others do not. This {line}, for example, needs one." + +x = F"This is a long string which contains an f-expr that should not split {{{[i for i in range(5)]}}}." + +x = ( + "\N{BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR}\N{VARIATION SELECTOR-16}" +) + +xxxxxx_xxx_xxxx_xx_xxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxx_xxxx_xxxx_xxxxx = xxxx.xxxxxx.xxxxxxxxx.xxxxxxxxxxxxxxxxxxxx( + xx_xxxxxx={ + "x3_xxxxxxxx": "xxx3_xxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxx_xxxxxxxx_xxxxxx_xxxxxxx", + }, +) + +# Regression test for https://github.com/psf/black/issues/3117. +some_dict = { + "something_something": + r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t" + r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t", +} + +# Regression test for https://github.com/psf/black/issues/3459. +xxxx( + empty_str_as_first_split='' + f'xxxxxxx {xxxxxxxxxx} xxx xxxxxxxxxx xxxxx xxx xxx xx ' + 'xxxxx xxxxxxxxx xxxxxxx, xxx xxxxxxxxxxx xxx xxxxx. ' + f'xxxxxxxxxxxxx xxxx xx xxxxxxxxxx. xxxxx: {x.xxx}', + empty_u_str_as_first_split=u'' + f'xxxxxxx {xxxxxxxxxx} xxx xxxxxxxxxx xxxxx xxx xxx xx ' + 'xxxxx xxxxxxxxx xxxxxxx, xxx xxxxxxxxxxx xxx xxxxx. ' + f'xxxxxxxxxxxxx xxxx xx xxxxxxxxxx. xxxxx: {x.xxx}', +) + +# Regression test for https://github.com/psf/black/issues/3455. +a_dict = { + "/this/is/a/very/very/very/very/very/very/very/very/very/very/long/key/without/spaces": + # And there is a comment before the value + ("item1", "item2", "item3"), +} + +# Regression test for https://github.com/psf/black/issues/3506. +s = ( + "With single quote: ' " + f" {my_dict['foo']}" + ' With double quote: " ' + f' {my_dict["bar"]}' +) + +s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry:\'{my_dict["foo"]}\'' +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -25,41 +25,42 @@ + "Jaguar", + ) + +-stupid_format_method_bug = ( +- "Some really long string that just so happens to be the {} {} to force the 'format'" +- " method to hang over the line length boundary. This is pretty annoying.".format( +- "perfect", "length" +- ) ++stupid_format_method_bug = "Some really long string that just so happens to be the {} {} to force the 'format' method to hang over the line length boundary. This is pretty annoying.".format( ++ "perfect", "length" + ) + + + class A: + def foo(): + os.system( +- "This is a regression test. xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx" +- " xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx" +- " xxxx.".format("xxxxxxxxxx", "xxxxxx", "xxxxxxxxxx") ++ "This is a regression test. xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxxx.".format( ++ "xxxxxxxxxx", "xxxxxx", "xxxxxxxxxx" ++ ) + ) + + + class A: + def foo(): +- XXXXXXXXXXXX.append(( +- "xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx, xxxx_xxxx_xxxxxxxxxx={})".format( +- xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx +- ), +- my_var, +- my_other_var, +- )) ++ XXXXXXXXXXXX.append( ++ ( ++ "xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx, xxxx_xxxx_xxxxxxxxxx={})".format( ++ xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx ++ ), ++ my_var, ++ my_other_var, ++ ) ++ ) + + + class A: + class B: + def foo(): + bar( +- "[{}]: xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx={}" +- " xxxx_xxxx_xxxxxxxxxx={}, xxxx={})".format( +- xxxx._xxxxxxxxxxxxxx, xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx, xxxxxxx ++ ( ++ "[{}]: xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx={}" ++ " xxxx_xxxx_xxxxxxxxxx={}, xxxx={})".format( ++ xxxx._xxxxxxxxxxxxxx, xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx, xxxxxxx ++ ) + ), + varX, + varY, +@@ -70,9 +71,10 @@ + def foo(xxxx): + for xxx_xxxx, _xxx_xxx, _xxx_xxxxx, xxx_xxxx in xxxx: + for xxx in xxx_xxxx: +- assert ("x" in xxx) or (xxx in xxx_xxx_xxxxx), ( +- "{0} xxxxxxx xx {1}, xxx {1} xx xxx xx xxxx xx xxx xxxx: xxx xxxx {2}" +- .format(xxx_xxxx, xxx, xxxxxx.xxxxxxx(xxx_xxx_xxxxx)) ++ assert ( ++ ("x" in xxx) or (xxx in xxx_xxx_xxxxx) ++ ), "{0} xxxxxxx xx {1}, xxx {1} xx xxx xx xxxx xx xxx xxxx: xxx xxxx {2}".format( ++ xxx_xxxx, xxx, xxxxxx.xxxxxxx(xxx_xxx_xxxxx) + ) + + +@@ -80,10 +82,11 @@ + def disappearing_comment(): + return ( + ( # xx -x xxxxxxx xx xxx xxxxxxx. +- "{{xxx_xxxxxxxxxx_xxxxxxxx}} xxx xxxx {} {{xxxx}} >&2".format( ++ "{{xxx_xxxxxxxxxx_xxxxxxxx}} xxx xxxx" " {} {{xxxx}} >&2".format( + "{xxxx} {xxxxxx}" + if xxxxx.xx_xxxxxxxxxx +- else ( # Disappearing Comment ++ # Disappearing Comment ++ else ( + "--xxxxxxx --xxxxxx=x --xxxxxx-xxxxx=xxxxxx" + " --xxxxxx-xxxx=xxxxxxxxxxx.xxx" + ) +@@ -113,18 +116,25 @@ + + + func_call_where_string_arg_has_method_call_and_bad_parens( +- "A long string with {}. This string is so long that it is ridiculous. It can't fit" +- " on one line at alllll.".format("formatting"), ++ ( ++ "A long string with {}. This string is so long that it is ridiculous. It can't fit on one line at alllll.".format( ++ "formatting" ++ ) ++ ), + ) + + func_call_where_string_arg_has_old_fmt_and_bad_parens( +- "A long string with {}. This string is so long that it is ridiculous. It can't fit" +- " on one line at alllll." % "formatting", ++ ( ++ "A long string with {}. This string is so long that it is ridiculous. It can't fit on one line at alllll." ++ % "formatting" ++ ), + ) + + func_call_where_string_arg_has_old_fmt_and_bad_parens( +- "A long string with {}. This {} is so long that it is ridiculous. It can't fit on" +- " one line at alllll." % ("formatting", "string"), ++ ( ++ "A long string with {}. This {} is so long that it is ridiculous. It can't fit on one line at alllll." ++ % ("formatting", "string") ++ ), + ) + + +@@ -132,52 +142,60 @@ + def append(self): + if True: + xxxx.xxxxxxx.xxxxx( +- "xxxxxxxxxx xxxx xx xxxxxx(%x) xx %x xxxx xx xxx %x.xx" +- % (len(self) + 1, xxxx.xxxxxxxxxx, xxxx.xxxxxxxxxx) +- + " %.3f (%s) to %.3f (%s).\n" +- % ( +- xxxx.xxxxxxxxx, +- xxxx.xxxxxxxxxxxxxx(xxxx.xxxxxxxxx), +- x, +- xxxx.xxxxxxxxxxxxxx(xx), ++ ( ++ "xxxxxxxxxx xxxx xx xxxxxx(%x) xx %x xxxx xx xxx %x.xx" ++ % (len(self) + 1, xxxx.xxxxxxxxxx, xxxx.xxxxxxxxxx) ++ ) ++ + ( ++ " %.3f (%s) to %.3f (%s).\n" ++ % ( ++ xxxx.xxxxxxxxx, ++ xxxx.xxxxxxxxxxxxxx(xxxx.xxxxxxxxx), ++ x, ++ xxxx.xxxxxxxxxxxxxx(xx), ++ ) + ) + ) + + + class A: + def foo(): +- some_func_call( +- "xxxxxxxxxx", +- "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " +- '"xxxx xxxxxxx xxxxxx xxxx; xxxx xxxxxx_xxxxx xxxxxx xxxx; ' +- "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" ", +- None, +- ("xxxxxxxxxxx",), +- ), ++ ( ++ some_func_call( ++ "xxxxxxxxxx", ++ ( ++ "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " ++ '"xxxx xxxxxxx xxxxxx xxxx; xxxx xxxxxx_xxxxx xxxxxx xxxx; ' ++ "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" " ++ ), ++ None, ++ ("xxxxxxxxxxx",), ++ ), ++ ) + + + class A: + def foo(): +- some_func_call( +- "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " +- "xxxx, ('xxxxxxx xxxxxx xxxx, xxxx') xxxxxx_xxxxx xxxxxx xxxx; " +- "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" ", +- None, +- ("xxxxxxxxxxx",), +- ), ++ ( ++ some_func_call( ++ ( ++ "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " ++ "xxxx, ('xxxxxxx xxxxxx xxxx, xxxx') xxxxxx_xxxxx xxxxxx xxxx; " ++ "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" " ++ ), ++ None, ++ ("xxxxxxxxxxx",), ++ ), ++ ) + + + xxxxxxx = { +- "xx": ( +- "xxxx xxxxxxx xxxxxxxxx -x xxx -x /xxx/{0} -x xxx,xxx -xx {1} -xx {1} -xx" +- " xxx=xxx_xxxx,xxx_xx,xxx_xxx,xxx_xxxx,xxx_xx,xxx_xxx | xxxxxx -x xxxxxxxx -x" +- " xxxxxxxx -x" +- ), +- "xx": ( +- "xxxx xxxxxxx xxxxxxxxx -x xxx -x /xxx/{0} -x xxx,xxx -xx {1} -xx {1} -xx" +- " xxx=xxx_xxxx_xxx_xxxx,xxx_xx_xxx_xxxx,xxx_xxxx_xxx_xxxx,xxx_xx_xxxx_xxxx,xxx_xxx_xxxx,xxx_xxx_xxxx" +- " xxxx=xxx | xxxxxx -x xxxxxxxx -x xxxxxxxx -x" +- ), ++ "xx": "xxxx xxxxxxx xxxxxxxxx -x xxx -x /xxx/{0} -x xxx,xxx -xx {1} \ ++-xx {1} -xx xxx=xxx_xxxx,xxx_xx,xxx_xxx,xxx_xxxx,xxx_xx,xxx_xxx |\ ++ xxxxxx -x xxxxxxxx -x xxxxxxxx -x", ++ "xx": "xxxx xxxxxxx xxxxxxxxx -x xxx -x /xxx/{0} -x xxx,xxx -xx {1} \ ++-xx {1} -xx xxx=xxx_xxxx_xxx_xxxx,xxx_xx_xxx_xxxx,xxx_xxxx_xxx_xxxx,\ ++xxx_xx_xxxx_xxxx,xxx_xxx_xxxx,xxx_xxx_xxxx xxxx=xxx | xxxxxx -x xxxxxxxx -x xxxxxxxx -x", + } + + +@@ -185,10 +203,10 @@ + def foo(self): + if True: + xxxxx_xxxxxxxxxxxx( +- "xxx xxxxxx xxx xxxxxxxxx.xx xx xxxxxxxx. xxx xxxxxxxxxxxxx.xx" +- " xxxxxxx " +- + "xx xxxxxx xxxxxx xxxxxx xx xxxxxxx xxx xxx ${0} xx x xxxxxxxx xxxxx" +- .xxxxxx(xxxxxx_xxxxxx_xxx) ++ "xxx xxxxxx xxx xxxxxxxxx.xx xx xxxxxxxx. xxx xxxxxxxxxxxxx.xx xxxxxxx " ++ + "xx xxxxxx xxxxxx xxxxxx xx xxxxxxx xxx xxx ${0} xx x xxxxxxxx xxxxx".xxxxxx( ++ xxxxxx_xxxxxx_xxx ++ ) + ) + + +@@ -232,39 +250,24 @@ + + some_dictionary = { + "xxxxx006": [ +- ( +- "xxx-xxx" +- " xxxxx3xxxx1xx2xxxxxxxxxxxxxx0xx6xxxxxxxxxx2xxxxxx9xxxxxxxxxx0xxxxx1xxx2x/xx9xx6+x+xxxxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxxxx43xxx2xx2x4x++xxx6xxxxxxxxx+xxxxx/xx9x+xxxxxxxxxxxxxx8x15xxxxxxxxxxxxxxxxx82xx/xxxxxxxxxxxxxx/x5xxxxxxxxxxxxxx6xxxxxx74x4/xxx4x+xxxxxxxxx2xxxxxxxx87xxxxx4xxxxxxxx3xx0xxxxx4xxx1xx9xx5xxxxxxx/xxxxx5xx6xx4xxxx1x/x2xxxxxxxxxxxx64xxxxxxx1x0xx5xxxxxxxxxxxxxx==" +- " xxxxx000 xxxxxxxxxx\n" +- ), +- ( +- "xxx-xxx" +- " xxxxx3xxxx1xx2xxxxxxxxxxxxxx6xxxxxxxxxxxxxx9xxxxxxxxxxxxx3xxx9xxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxxxx2xxxx2xxx6xxxxx/xx54xxxxxxxxx4xxx3xxxxxx9xx3xxxxx39xxxxxxxxx5xx91xxxx7xxxxxx8xxxxxxxxxxxxxxxx9xxx93xxxxxxxxxxxxxxxxx7xxx8xx8xx4/x1xxxxx1x3xxxxxxxxxxxxx3xxxxxx9xx4xx4x7xxxxxxxxxxxxx1xxxxxxxxx7xxxxxxxxxxxxxx4xx6xxxxxxxxx9xxx7xxxx2xxxxxxxxxxxxxxxxxxxxxx8xxxxxxxxxxxxxxxxxxxx6xx==" +- " xxxxx010 xxxxxxxxxx\n" +- ), ++ "xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx0xx6xxxxxxxxxx2xxxxxx9xxxxxxxxxx0xxxxx1xxx2x/xx9xx6+x+xxxxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxxxx43xxx2xx2x4x++xxx6xxxxxxxxx+xxxxx/xx9x+xxxxxxxxxxxxxx8x15xxxxxxxxxxxxxxxxx82xx/xxxxxxxxxxxxxx/x5xxxxxxxxxxxxxx6xxxxxx74x4/xxx4x+xxxxxxxxx2xxxxxxxx87xxxxx4xxxxxxxx3xx0xxxxx4xxx1xx9xx5xxxxxxx/xxxxx5xx6xx4xxxx1x/x2xxxxxxxxxxxx64xxxxxxx1x0xx5xxxxxxxxxxxxxx== xxxxx000 xxxxxxxxxx\n", ++ "xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx6xxxxxxxxxxxxxx9xxxxxxxxxxxxx3xxx9xxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxxxx2xxxx2xxx6xxxxx/xx54xxxxxxxxx4xxx3xxxxxx9xx3xxxxx39xxxxxxxxx5xx91xxxx7xxxxxx8xxxxxxxxxxxxxxxx9xxx93xxxxxxxxxxxxxxxxx7xxx8xx8xx4/x1xxxxx1x3xxxxxxxxxxxxx3xxxxxx9xx4xx4x7xxxxxxxxxxxxx1xxxxxxxxx7xxxxxxxxxxxxxx4xx6xxxxxxxxx9xxx7xxxx2xxxxxxxxxxxxxxxxxxxxxx8xxxxxxxxxxxxxxxxxxxx6xx== xxxxx010 xxxxxxxxxx\n", + ], + "xxxxx016": [ +- ( +- "xxx-xxx" +- " xxxxx3xxxx1xx2xxxxxxxxxxxxxx0xx6xxxxxxxxxx2xxxxxx9xxxxxxxxxx0xxxxx1xxx2x/xx9xx6+x+xxxxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxxxx43xxx2xx2x4x++xxx6xxxxxxxxx+xxxxx/xx9x+xxxxxxxxxxxxxx8x15xxxxxxxxxxxxxxxxx82xx/xxxxxxxxxxxxxx/x5xxxxxxxxxxxxxx6xxxxxx74x4/xxx4x+xxxxxxxxx2xxxxxxxx87xxxxx4xxxxxxxx3xx0xxxxx4xxx1xx9xx5xxxxxxx/xxxxx5xx6xx4xxxx1x/x2xxxxxxxxxxxx64xxxxxxx1x0xx5xxxxxxxxxxxxxx==" +- " xxxxx000 xxxxxxxxxx\n" +- ), +- ( +- "xxx-xxx" +- " xxxxx3xxxx1xx2xxxxxxxxxxxxxx6xxxxxxxxxxxxxx9xxxxxxxxxxxxx3xxx9xxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxxxx2xxxx2xxx6xxxxx/xx54xxxxxxxxx4xxx3xxxxxx9xx3xxxxx39xxxxxxxxx5xx91xxxx7xxxxxx8xxxxxxxxxxxxxxxx9xxx93xxxxxxxxxxxxxxxxx7xxx8xx8xx4/x1xxxxx1x3xxxxxxxxxxxxx3xxxxxx9xx4xx4x7xxxxxxxxxxxxx1xxxxxxxxx7xxxxxxxxxxxxxx4xx6xxxxxxxxx9xxx7xxxx2xxxxxxxxxxxxxxxxxxxxxx8xxxxxxxxxxxxxxxxxxxx6xx==" +- " xxxxx010 xxxxxxxxxx\n" +- ), ++ "xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx0xx6xxxxxxxxxx2xxxxxx9xxxxxxxxxx0xxxxx1xxx2x/xx9xx6+x+xxxxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxxxx43xxx2xx2x4x++xxx6xxxxxxxxx+xxxxx/xx9x+xxxxxxxxxxxxxx8x15xxxxxxxxxxxxxxxxx82xx/xxxxxxxxxxxxxx/x5xxxxxxxxxxxxxx6xxxxxx74x4/xxx4x+xxxxxxxxx2xxxxxxxx87xxxxx4xxxxxxxx3xx0xxxxx4xxx1xx9xx5xxxxxxx/xxxxx5xx6xx4xxxx1x/x2xxxxxxxxxxxx64xxxxxxx1x0xx5xxxxxxxxxxxxxx== xxxxx000 xxxxxxxxxx\n", ++ "xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx6xxxxxxxxxxxxxx9xxxxxxxxxxxxx3xxx9xxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxxxx2xxxx2xxx6xxxxx/xx54xxxxxxxxx4xxx3xxxxxx9xx3xxxxx39xxxxxxxxx5xx91xxxx7xxxxxx8xxxxxxxxxxxxxxxx9xxx93xxxxxxxxxxxxxxxxx7xxx8xx8xx4/x1xxxxx1x3xxxxxxxxxxxxx3xxxxxx9xx4xx4x7xxxxxxxxxxxxx1xxxxxxxxx7xxxxxxxxxxxxxx4xx6xxxxxxxxx9xxx7xxxx2xxxxxxxxxxxxxxxxxxxxxx8xxxxxxxxxxxxxxxxxxxx6xx== xxxxx010 xxxxxxxxxx\n", + ], + } + + + def foo(): +- xxx_xxx = ( # xxxx xxxxxxxxxx xxxx xx xxxx xx xxx xxxxxxxx xxxxxx xxxxx. +- 'xxxx xxx xxxxxxxx_xxxx xx "xxxxxxxxxx".\n xxx: xxxxxx xxxxxxxx_xxxx=xxxxxxxxxx' +- ) ++ xxx_xxx = ( ++ 'xxxx xxx xxxxxxxx_xxxx xx "xxxxxxxxxx".' ++ "\n xxx: xxxxxx xxxxxxxx_xxxx=xxxxxxxxxx" ++ ) # xxxx xxxxxxxxxx xxxx xx xxxx xx xxx xxxxxxxx xxxxxx xxxxx. + + +-some_tuple = ("some string", "some string which should be joined") ++some_tuple = ("some string", "some string" " which should be joined") + + some_commented_string = ( # This comment stays at the top. + "This string is long but not so long that it needs hahahah toooooo be so greatttt" +@@ -279,36 +282,25 @@ + ) + + lpar_and_rpar_have_comments = func_call( # LPAR Comment +- "Long really ridiculous type of string that shouldn't really even exist at all. I" +- " mean commmme onnn!!!", # Comma Comment ++ "Long really ridiculous type of string that shouldn't really even exist at all. I mean commmme onnn!!!", # Comma Comment + ) # RPAR Comment + + cmd_fstring = ( +- "sudo -E deluge-console info --detailed --sort-reverse=time_added " ++ f"sudo -E deluge-console info --detailed --sort-reverse=time_added " + f"{'' if ID is None else ID} | perl -nE 'print if /^{field}:/'" + ) + +-cmd_fstring = ( +- "sudo -E deluge-console info --detailed --sort-reverse=time_added" +- f" {'' if ID is None else ID} | perl -nE 'print if /^{field}:/'" +-) ++cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {'' if ID is None else ID} | perl -nE 'print if /^{field}:/'" ++ ++cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {'{{}}' if ID is None else ID} | perl -nE 'print if /^{field}:/'" + +-cmd_fstring = ( +- "sudo -E deluge-console info --detailed --sort-reverse=time_added" +- f" {'{{}}' if ID is None else ID} | perl -nE 'print if /^{field}:/'" +-) ++cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {{'' if ID is None else ID}} | perl -nE 'print if /^{field}:/'" + +-cmd_fstring = ( +- "sudo -E deluge-console info --detailed --sort-reverse=time_added {'' if ID is" +- f" None else ID}} | perl -nE 'print if /^{field}:/'" +-) ++fstring = f"This string really doesn't need to be an {{{{fstring}}}}, but this one most certainly, absolutely {does}." + + fstring = ( +- "This string really doesn't need to be an {{fstring}}, but this one most" +- f" certainly, absolutely {does}." ++ f"We have to remember to escape {braces}." " Like {these}." f" But not {this}." + ) +- +-fstring = f"We have to remember to escape {braces}. Like {{these}}. But not {this}." + + + class A: +@@ -364,10 +356,7 @@ + def foo(): + if not hasattr(module, name): + raise ValueError( +- "Could not find object %s in %s.\nPlease note that you cannot" +- " serialize things like inner classes. Please move the object into" +- " the main module body to use migrations.\nFor more information," +- " see https://docs.djangoproject.com/en/%s/topics/migrations/#serializing-values" ++ "Could not find object %s in %s.\nPlease note that you cannot serialize things like inner classes. Please move the object into the main module body to use migrations.\nFor more information, see https://docs.djangoproject.com/en/%s/topics/migrations/#serializing-values" + % (name, module_name, get_docs_version()) + ) + +@@ -382,35 +371,33 @@ + + class Step(StepBase): + def who(self): +- self.cmd = ( +- "SR AAAA-CORRECT NAME IS {last_name} {first_name}{middle_name}" +- " {title}/P{passenger_association}".format( +- last_name=last_name, +- first_name=first_name, +- middle_name=middle_name, +- title=title, +- passenger_association=passenger_association, +- ) ++ self.cmd = "SR AAAA-CORRECT NAME IS {last_name} {first_name}{middle_name} {title}/P{passenger_association}".format( ++ last_name=last_name, ++ first_name=first_name, ++ middle_name=middle_name, ++ title=title, ++ passenger_association=passenger_association, + ) + + +-xxxxxxx_xxxxxx_xxxxxxx = xxx([ +- xxxxxxxxxxxx( +- xxxxxx_xxxxxxx=( +- '((x.aaaaaaaaa = "xxxxxx.xxxxxxxxxxxxxxxxxxxxx") || (x.xxxxxxxxx =' +- ' "xxxxxxxxxxxx")) && ' +- # xxxxx xxxxxxxxxxxx xxxx xxx (xxxxxxxxxxxxxxxx) xx x xxxxxxxxx xx xxxxxx. +- "(x.bbbbbbbbbbbb.xxx != " +- '"xxx:xxx:xxx::cccccccccccc:xxxxxxx-xxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxxxx") && ' ++xxxxxxx_xxxxxx_xxxxxxx = xxx( ++ [ ++ xxxxxxxxxxxx( ++ xxxxxx_xxxxxxx=( ++ '((x.aaaaaaaaa = "xxxxxx.xxxxxxxxxxxxxxxxxxxxx") || (x.xxxxxxxxx = "xxxxxxxxxxxx")) && ' ++ # xxxxx xxxxxxxxxxxx xxxx xxx (xxxxxxxxxxxxxxxx) xx x xxxxxxxxx xx xxxxxx. ++ "(x.bbbbbbbbbbbb.xxx != " ++ '"xxx:xxx:xxx::cccccccccccc:xxxxxxx-xxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxxxx") && ' ++ ) + ) +- ) +-]) ++ ] ++) + + if __name__ == "__main__": + for i in range(4, 8): + cmd = ( +- r"for pid in $(ps aux | grep paster | grep -v grep | grep '\-%d' | awk" +- r" '{print $2}'); do kill $pid; done" % (i) ++ r"for pid in $(ps aux | grep paster | grep -v grep | grep '\-%d' | awk '{print $2}'); do kill $pid; done" ++ % (i) + ) + + +@@ -432,14 +419,12 @@ + assert xxxxxxx_xxxx in [ + x.xxxxx.xxxxxx.xxxxx.xxxxxx, + x.xxxxx.xxxxxx.xxxxx.xxxx, +- ], ( +- "xxxxxxxxxxx xxxxxxx xxxx (xxxxxx xxxx) %x xxx xxxxx" % xxxxxxx_xxxx +- ) ++ ], "xxxxxxxxxxx xxxxxxx xxxx (xxxxxx xxxx) %x xxx xxxxx" % xxxxxxx_xxxx + + +-value.__dict__[key] = ( +- "test" # set some Thrift field to non-None in the struct aa bb cc dd ee +-) ++value.__dict__[ ++ key ++] = "test" # set some Thrift field to non-None in the struct aa bb cc dd ee + + RE_ONE_BACKSLASH = { + "asdf_hjkl_jkl": re.compile( +@@ -449,8 +434,7 @@ + + RE_TWO_BACKSLASHES = { + "asdf_hjkl_jkl": re.compile( +- r"(?>\n" + ) + +-assert ( +- str(suffix_arr) +- == "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " ++assert str(suffix_arr) == ( ++ "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" + ) +-assert ( +- str(suffix_arr) +- != "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " ++assert str(suffix_arr) != ( ++ "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" + ) +-assert ( +- str(suffix_arr) +- <= "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " ++assert str(suffix_arr) <= ( ++ "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" + ) +-assert ( +- str(suffix_arr) +- >= "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " ++assert str(suffix_arr) >= ( ++ "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" + ) +-assert ( +- str(suffix_arr) +- < "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " ++assert str(suffix_arr) < ( ++ "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" + ) +-assert ( +- str(suffix_arr) +- > "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " ++assert str(suffix_arr) > ( ++ "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" + ) + assert ( + str(suffix_arr) +- in "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', 'grykangaroo$'," +- " 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', 'o$', 'oo$', 'roo$', 'rykangaroo$'," +- " 'ykangaroo$']" ++ in "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', 'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', 'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" + ) + assert ( + str(suffix_arr) +- not in "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', 'grykangaroo$'," +- " 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', 'o$', 'oo$', 'roo$'," +- " 'rykangaroo$', 'ykangaroo$']" ++ not in "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', 'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', 'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" + ) + message = ( + f"1. Go to Google Developers Console and log in with your Google account." +- f"(https://console.developers.google.com/)" +- f"2. You should be prompted to create a new project (name does not matter)." +- f"3. Click on Enable APIs and Services at the top." +- f"4. In the list of APIs choose or search for YouTube Data API v3 and " +- f"click on it. Choose Enable." +- f"5. Click on Credentials on the left navigation bar." +- f"6. Click on Create Credential at the top." +- f'7. At the top click the link for "API key".' +- f"8. No application restrictions are needed. Click Create at the bottom." +- f"9. You now have a key to add to `{{prefix}}set api youtube api_key`" ++ "(https://console.developers.google.com/)" ++ "2. You should be prompted to create a new project (name does not matter)." ++ "3. Click on Enable APIs and Services at the top." ++ "4. In the list of APIs choose or search for YouTube Data API v3 and " ++ "click on it. Choose Enable." ++ "5. Click on Credentials on the left navigation bar." ++ "6. Click on Create Credential at the top." ++ '7. At the top click the link for "API key".' ++ "8. No application restrictions are needed. Click Create at the bottom." ++ "9. You now have a key to add to `{prefix}set api youtube api_key`" + ) + message = ( + f"1. Go to Google Developers Console and log in with your Google account." +- f"(https://console.developers.google.com/)" +- f"2. You should be prompted to create a new project (name does not matter)." ++ "(https://console.developers.google.com/)" ++ "2. You should be prompted to create a new project (name does not matter)." + f"3. Click on Enable APIs and Services at the top." +- f"4. In the list of APIs choose or search for YouTube Data API v3 and " +- f"click on it. Choose Enable." ++ "4. In the list of APIs choose or search for YouTube Data API v3 and " ++ "click on it. Choose Enable." + f"5. Click on Credentials on the left navigation bar." +- f"6. Click on Create Credential at the top." +- f'7. At the top click the link for "API key".' +- f"8. No application restrictions are needed. Click Create at the bottom." +- f"9. You now have a key to add to `{{prefix}}set api youtube api_key`" ++ "6. Click on Create Credential at the top." ++ '7. At the top click the link for "API key".' ++ "8. No application restrictions are needed. Click Create at the bottom." ++ "9. You now have a key to add to `{prefix}set api youtube api_key`" + ) + message = ( +- "1. Go to Google Developers Console and log in with your Google account." ++ f"1. Go to Google Developers Console and log in with your Google account." + "(https://console.developers.google.com/)" + "2. You should be prompted to create a new project (name does not matter)." +- "3. Click on Enable APIs and Services at the top." ++ f"3. Click on Enable APIs and Services at the top." + "4. In the list of APIs choose or search for YouTube Data API v3 and " + "click on it. Choose Enable." +- "5. Click on Credentials on the left navigation bar." ++ f"5. Click on Credentials on the left navigation bar." + "6. Click on Create Credential at the top." + '7. At the top click the link for "API key".' + "8. No application restrictions are needed. Click Create at the bottom." +@@ -613,55 +583,40 @@ + f"<<{author.display_name}>>\n" + ) + +-fstring = f"We have to remember to escape {braces}. Like {{these}}. But not {this}." ++fstring = ( ++ f"We have to remember to escape {braces}." " Like {these}." f" But not {this}." ++) + + welcome_to_programming = R"hello," R" world!" + +-fstring = ( +- f"f-strings definitely make things more {difficult} than they need to be for" +- " {black}. But boy they sure are handy. The problem is that some lines will need" +- f" to have the 'f' whereas others do not. This {line}, for example, needs one." +-) ++fstring = f"f-strings definitely make things more {difficult} than they need to be for {{black}}. But boy they sure are handy. The problem is that some lines will need to have the 'f' whereas others do not. This {line}, for example, needs one." + +-x = ( +- "This is a long string which contains an f-expr that should not split" +- f" {{{[i for i in range(5)]}}}." +-) ++x = f"This is a long string which contains an f-expr that should not split {{{[i for i in range(5)]}}}." + +-x = ( +- "\N{BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR}\N{VARIATION SELECTOR-16}" +-) ++x = "\N{BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR}\N{VARIATION SELECTOR-16}" + + xxxxxx_xxx_xxxx_xx_xxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxx_xxxx_xxxx_xxxxx = xxxx.xxxxxx.xxxxxxxxx.xxxxxxxxxxxxxxxxxxxx( + xx_xxxxxx={ +- "x3_xxxxxxxx": ( +- "xxx3_xxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxx_xxxxxxxx_xxxxxx_xxxxxxx" +- ), ++ "x3_xxxxxxxx": "xxx3_xxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxx_xxxxxxxx_xxxxxx_xxxxxxx", + }, + ) + + # Regression test for https://github.com/psf/black/issues/3117. + some_dict = { +- "something_something": ( +- r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t" +- r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t" +- ), ++ "something_something": r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t" ++ r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t", + } + + # Regression test for https://github.com/psf/black/issues/3459. + xxxx( +- empty_str_as_first_split=( +- "" +- f"xxxxxxx {xxxxxxxxxx} xxx xxxxxxxxxx xxxxx xxx xxx xx " +- "xxxxx xxxxxxxxx xxxxxxx, xxx xxxxxxxxxxx xxx xxxxx. " +- f"xxxxxxxxxxxxx xxxx xx xxxxxxxxxx. xxxxx: {x.xxx}" +- ), +- empty_u_str_as_first_split=( +- "" +- f"xxxxxxx {xxxxxxxxxx} xxx xxxxxxxxxx xxxxx xxx xxx xx " +- "xxxxx xxxxxxxxx xxxxxxx, xxx xxxxxxxxxxx xxx xxxxx. " +- f"xxxxxxxxxxxxx xxxx xx xxxxxxxxxx. xxxxx: {x.xxx}" +- ), ++ empty_str_as_first_split="" ++ f"xxxxxxx {xxxxxxxxxx} xxx xxxxxxxxxx xxxxx xxx xxx xx " ++ "xxxxx xxxxxxxxx xxxxxxx, xxx xxxxxxxxxxx xxx xxxxx. " ++ f"xxxxxxxxxxxxx xxxx xx xxxxxxxxxx. xxxxx: {x.xxx}", ++ empty_u_str_as_first_split="" ++ f"xxxxxxx {xxxxxxxxxx} xxx xxxxxxxxxx xxxxx xxx xxx xx " ++ "xxxxx xxxxxxxxx xxxxxxx, xxx xxxxxxxxxxx xxx xxxxx. " ++ f"xxxxxxxxxxxxx xxxx xx xxxxxxxxxx. xxxxx: {x.xxx}", + ) + + # Regression test for https://github.com/psf/black/issues/3455. +@@ -672,9 +627,11 @@ + } + + # Regression test for https://github.com/psf/black/issues/3506. +-s = f"With single quote: ' {my_dict['foo']} With double quote: \" {my_dict['bar']}" +- + s = ( +- "Lorem Ipsum is simply dummy text of the printing and typesetting" +- f" industry:'{my_dict['foo']}'" ++ "With single quote: ' " ++ f" {my_dict['foo']}" ++ ' With double quote: " ' ++ f' {my_dict["bar"]}' + ) ++ ++s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry:\'{my_dict["foo"]}\'' +``` + +## Ruff Output + +```python +class A: + def foo(): + result = type(message)("") + + +# Don't merge multiline (e.g. triple-quoted) strings. +def foo(): + query = ( + """SELECT xxxxxxxxxxxxxxxxxxxx(xxx)""" + """ FROM xxxxxxxxxxxxxxxx WHERE xxxxxxxxxx AND xxx <> xxxxxxxxxxxxxx()""" + ) + + +# There was a bug where tuples were being identified as long strings. +long_tuple = ( + "Apple", + "Berry", + "Cherry", + "Dill", + "Evergreen", + "Fig", + "Grape", + "Harry", + "Iglu", + "Jaguar", +) + +stupid_format_method_bug = "Some really long string that just so happens to be the {} {} to force the 'format' method to hang over the line length boundary. This is pretty annoying.".format( + "perfect", "length" +) + + +class A: + def foo(): + os.system( + "This is a regression test. xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxxx.".format( + "xxxxxxxxxx", "xxxxxx", "xxxxxxxxxx" + ) + ) + + +class A: + def foo(): + XXXXXXXXXXXX.append( + ( + "xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx, xxxx_xxxx_xxxxxxxxxx={})".format( + xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx + ), + my_var, + my_other_var, + ) + ) + + +class A: + class B: + def foo(): + bar( + ( + "[{}]: xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx={}" + " xxxx_xxxx_xxxxxxxxxx={}, xxxx={})".format( + xxxx._xxxxxxxxxxxxxx, xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx, xxxxxxx + ) + ), + varX, + varY, + varZ, + ) + + +def foo(xxxx): + for xxx_xxxx, _xxx_xxx, _xxx_xxxxx, xxx_xxxx in xxxx: + for xxx in xxx_xxxx: + assert ( + ("x" in xxx) or (xxx in xxx_xxx_xxxxx) + ), "{0} xxxxxxx xx {1}, xxx {1} xx xxx xx xxxx xx xxx xxxx: xxx xxxx {2}".format( + xxx_xxxx, xxx, xxxxxx.xxxxxxx(xxx_xxx_xxxxx) + ) + + +class A: + def disappearing_comment(): + return ( + ( # xx -x xxxxxxx xx xxx xxxxxxx. + "{{xxx_xxxxxxxxxx_xxxxxxxx}} xxx xxxx" " {} {{xxxx}} >&2".format( + "{xxxx} {xxxxxx}" + if xxxxx.xx_xxxxxxxxxx + # Disappearing Comment + else ( + "--xxxxxxx --xxxxxx=x --xxxxxx-xxxxx=xxxxxx" + " --xxxxxx-xxxx=xxxxxxxxxxx.xxx" + ) + ) + ), + (x, y, z), + ) + + +class A: + class B: + def foo(): + xxxxx_xxxx( + xx, + "\t" + "@xxxxxx '{xxxx_xxx}\t' > {xxxxxx_xxxx}.xxxxxxx;" + "{xxxx_xxx} >> {xxxxxx_xxxx}.xxxxxxx 2>&1; xx=$$?;" + "xxxx $$xx".format( + xxxx_xxx=xxxx_xxxxxxx, + xxxxxx_xxxx=xxxxxxx + "/" + xxxx_xxx_xxxx, + x=xxx_xxxxx_xxxxx_xxx, + ), + x, + y, + z, + ) + + +func_call_where_string_arg_has_method_call_and_bad_parens( + ( + "A long string with {}. This string is so long that it is ridiculous. It can't fit on one line at alllll.".format( + "formatting" + ) + ), +) + +func_call_where_string_arg_has_old_fmt_and_bad_parens( + ( + "A long string with {}. This string is so long that it is ridiculous. It can't fit on one line at alllll." + % "formatting" + ), +) + +func_call_where_string_arg_has_old_fmt_and_bad_parens( + ( + "A long string with {}. This {} is so long that it is ridiculous. It can't fit on one line at alllll." + % ("formatting", "string") + ), +) + + +class A: + def append(self): + if True: + xxxx.xxxxxxx.xxxxx( + ( + "xxxxxxxxxx xxxx xx xxxxxx(%x) xx %x xxxx xx xxx %x.xx" + % (len(self) + 1, xxxx.xxxxxxxxxx, xxxx.xxxxxxxxxx) + ) + + ( + " %.3f (%s) to %.3f (%s).\n" + % ( + xxxx.xxxxxxxxx, + xxxx.xxxxxxxxxxxxxx(xxxx.xxxxxxxxx), + x, + xxxx.xxxxxxxxxxxxxx(xx), + ) + ) + ) + + +class A: + def foo(): + ( + some_func_call( + "xxxxxxxxxx", + ( + "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " + '"xxxx xxxxxxx xxxxxx xxxx; xxxx xxxxxx_xxxxx xxxxxx xxxx; ' + "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" " + ), + None, + ("xxxxxxxxxxx",), + ), + ) + + +class A: + def foo(): + ( + some_func_call( + ( + "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " + "xxxx, ('xxxxxxx xxxxxx xxxx, xxxx') xxxxxx_xxxxx xxxxxx xxxx; " + "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" " + ), + None, + ("xxxxxxxxxxx",), + ), + ) + + +xxxxxxx = { + "xx": "xxxx xxxxxxx xxxxxxxxx -x xxx -x /xxx/{0} -x xxx,xxx -xx {1} \ +-xx {1} -xx xxx=xxx_xxxx,xxx_xx,xxx_xxx,xxx_xxxx,xxx_xx,xxx_xxx |\ + xxxxxx -x xxxxxxxx -x xxxxxxxx -x", + "xx": "xxxx xxxxxxx xxxxxxxxx -x xxx -x /xxx/{0} -x xxx,xxx -xx {1} \ +-xx {1} -xx xxx=xxx_xxxx_xxx_xxxx,xxx_xx_xxx_xxxx,xxx_xxxx_xxx_xxxx,\ +xxx_xx_xxxx_xxxx,xxx_xxx_xxxx,xxx_xxx_xxxx xxxx=xxx | xxxxxx -x xxxxxxxx -x xxxxxxxx -x", +} + + +class A: + def foo(self): + if True: + xxxxx_xxxxxxxxxxxx( + "xxx xxxxxx xxx xxxxxxxxx.xx xx xxxxxxxx. xxx xxxxxxxxxxxxx.xx xxxxxxx " + + "xx xxxxxx xxxxxx xxxxxx xx xxxxxxx xxx xxx ${0} xx x xxxxxxxx xxxxx".xxxxxx( + xxxxxx_xxxxxx_xxx + ) + ) + + +class A: + class B: + def foo(): + row = { + "xxxxxxxxxxxxxxx": xxxxxx_xxxxx_xxxx, + # 'xxxxxxxxxxxxxxxxxxxxxxx' + # 'xxxxxxxxxxxxxxxxxxxxxx' + # 'xxxxxxxxxxxxxxxxxx' + # 'xxxxxxxxxxxxxxxxx' + "xxxxxxxxxx": xxxxx_xxxxx, + } + + +class A: + def xxxx_xxx_xx_xxxxxxxxxx_xxxx_xxxxxxxxx(xxxx): + xxxxxxxx = [ + xxxxxxxxxxxxxxxx( + "xxxx", + xxxxxxxxxxx={ + "xxxx": 1.0, + }, + xxxxxx={"xxxxxx 1": xxxxxx(xxxx="xxxxxx 1", xxxxxx=600.0)}, + xxxxxxxx_xxxxxxx=0.0, + ), + xxxxxxxxxxxxxxxx( + "xxxxxxx", + xxxxxxxxxxx={ + "xxxx": 1.0, + }, + xxxxxx={"xxxxxx 1": xxxxxx(xxxx="xxxxxx 1", xxxxxx=200.0)}, + xxxxxxxx_xxxxxxx=0.0, + ), + xxxxxxxxxxxxxxxx( + "xxxx", + ), + ] + + +some_dictionary = { + "xxxxx006": [ + "xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx0xx6xxxxxxxxxx2xxxxxx9xxxxxxxxxx0xxxxx1xxx2x/xx9xx6+x+xxxxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxxxx43xxx2xx2x4x++xxx6xxxxxxxxx+xxxxx/xx9x+xxxxxxxxxxxxxx8x15xxxxxxxxxxxxxxxxx82xx/xxxxxxxxxxxxxx/x5xxxxxxxxxxxxxx6xxxxxx74x4/xxx4x+xxxxxxxxx2xxxxxxxx87xxxxx4xxxxxxxx3xx0xxxxx4xxx1xx9xx5xxxxxxx/xxxxx5xx6xx4xxxx1x/x2xxxxxxxxxxxx64xxxxxxx1x0xx5xxxxxxxxxxxxxx== xxxxx000 xxxxxxxxxx\n", + "xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx6xxxxxxxxxxxxxx9xxxxxxxxxxxxx3xxx9xxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxxxx2xxxx2xxx6xxxxx/xx54xxxxxxxxx4xxx3xxxxxx9xx3xxxxx39xxxxxxxxx5xx91xxxx7xxxxxx8xxxxxxxxxxxxxxxx9xxx93xxxxxxxxxxxxxxxxx7xxx8xx8xx4/x1xxxxx1x3xxxxxxxxxxxxx3xxxxxx9xx4xx4x7xxxxxxxxxxxxx1xxxxxxxxx7xxxxxxxxxxxxxx4xx6xxxxxxxxx9xxx7xxxx2xxxxxxxxxxxxxxxxxxxxxx8xxxxxxxxxxxxxxxxxxxx6xx== xxxxx010 xxxxxxxxxx\n", + ], + "xxxxx016": [ + "xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx0xx6xxxxxxxxxx2xxxxxx9xxxxxxxxxx0xxxxx1xxx2x/xx9xx6+x+xxxxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxxxx43xxx2xx2x4x++xxx6xxxxxxxxx+xxxxx/xx9x+xxxxxxxxxxxxxx8x15xxxxxxxxxxxxxxxxx82xx/xxxxxxxxxxxxxx/x5xxxxxxxxxxxxxx6xxxxxx74x4/xxx4x+xxxxxxxxx2xxxxxxxx87xxxxx4xxxxxxxx3xx0xxxxx4xxx1xx9xx5xxxxxxx/xxxxx5xx6xx4xxxx1x/x2xxxxxxxxxxxx64xxxxxxx1x0xx5xxxxxxxxxxxxxx== xxxxx000 xxxxxxxxxx\n", + "xxx-xxx xxxxx3xxxx1xx2xxxxxxxxxxxxxx6xxxxxxxxxxxxxx9xxxxxxxxxxxxx3xxx9xxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxxxx2xxxx2xxx6xxxxx/xx54xxxxxxxxx4xxx3xxxxxx9xx3xxxxx39xxxxxxxxx5xx91xxxx7xxxxxx8xxxxxxxxxxxxxxxx9xxx93xxxxxxxxxxxxxxxxx7xxx8xx8xx4/x1xxxxx1x3xxxxxxxxxxxxx3xxxxxx9xx4xx4x7xxxxxxxxxxxxx1xxxxxxxxx7xxxxxxxxxxxxxx4xx6xxxxxxxxx9xxx7xxxx2xxxxxxxxxxxxxxxxxxxxxx8xxxxxxxxxxxxxxxxxxxx6xx== xxxxx010 xxxxxxxxxx\n", + ], +} + + +def foo(): + xxx_xxx = ( + 'xxxx xxx xxxxxxxx_xxxx xx "xxxxxxxxxx".' + "\n xxx: xxxxxx xxxxxxxx_xxxx=xxxxxxxxxx" + ) # xxxx xxxxxxxxxx xxxx xx xxxx xx xxx xxxxxxxx xxxxxx xxxxx. + + +some_tuple = ("some string", "some string" " which should be joined") + +some_commented_string = ( # This comment stays at the top. + "This string is long but not so long that it needs hahahah toooooo be so greatttt" + " {} that I just can't think of any more good words to say about it at" + " allllllllllll".format("ha") # comments here are fine +) + +some_commented_string = ( + "This string is long but not so long that it needs hahahah toooooo be so greatttt" # But these + " {} that I just can't think of any more good words to say about it at" # comments will stay + " allllllllllll".format("ha") # comments here are fine +) + +lpar_and_rpar_have_comments = func_call( # LPAR Comment + "Long really ridiculous type of string that shouldn't really even exist at all. I mean commmme onnn!!!", # Comma Comment +) # RPAR Comment + +cmd_fstring = ( + f"sudo -E deluge-console info --detailed --sort-reverse=time_added " + f"{'' if ID is None else ID} | perl -nE 'print if /^{field}:/'" +) + +cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {'' if ID is None else ID} | perl -nE 'print if /^{field}:/'" + +cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {'{{}}' if ID is None else ID} | perl -nE 'print if /^{field}:/'" + +cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {{'' if ID is None else ID}} | perl -nE 'print if /^{field}:/'" + +fstring = f"This string really doesn't need to be an {{{{fstring}}}}, but this one most certainly, absolutely {does}." + +fstring = ( + f"We have to remember to escape {braces}." " Like {these}." f" But not {this}." +) + + +class A: + class B: + def foo(): + st_error = STError( + f"This string ({string_leaf.value}) appears to be pointless (i.e. has" + " no parent)." + ) + + +def foo(): + user_regex = _lazy_re_compile( + r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*\Z" # dot-atom + r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"\Z)', # quoted-string + re.IGNORECASE, + ) + + +def foo(): + user_regex = _lazy_re_compile( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # dot-atom + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", # quoted-string + xyz, + ) + + +def foo(): + user_regex = _lazy_re_compile( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # dot-atom + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", # quoted-string + xyz, + ) + + +class A: + class B: + def foo(): + if not hasattr(module, name): + raise ValueError( + "Could not find object %s in %s.\n" + "Please note that you cannot serialize things like inner " + "classes. Please move the object into the main module " + "body to use migrations.\n" + "For more information, see " + "https://docs.djangoproject.com/en/%s/topics/migrations/#serializing-values" + % (name, module_name, get_docs_version()) + ) + + +class A: + class B: + def foo(): + if not hasattr(module, name): + raise ValueError( + "Could not find object %s in %s.\nPlease note that you cannot serialize things like inner classes. Please move the object into the main module body to use migrations.\nFor more information, see https://docs.djangoproject.com/en/%s/topics/migrations/#serializing-values" + % (name, module_name, get_docs_version()) + ) + + +x = ( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +) + + +class Step(StepBase): + def who(self): + self.cmd = "SR AAAA-CORRECT NAME IS {last_name} {first_name}{middle_name} {title}/P{passenger_association}".format( + last_name=last_name, + first_name=first_name, + middle_name=middle_name, + title=title, + passenger_association=passenger_association, + ) + + +xxxxxxx_xxxxxx_xxxxxxx = xxx( + [ + xxxxxxxxxxxx( + xxxxxx_xxxxxxx=( + '((x.aaaaaaaaa = "xxxxxx.xxxxxxxxxxxxxxxxxxxxx") || (x.xxxxxxxxx = "xxxxxxxxxxxx")) && ' + # xxxxx xxxxxxxxxxxx xxxx xxx (xxxxxxxxxxxxxxxx) xx x xxxxxxxxx xx xxxxxx. + "(x.bbbbbbbbbbbb.xxx != " + '"xxx:xxx:xxx::cccccccccccc:xxxxxxx-xxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxxxx") && ' + ) + ) + ] +) + +if __name__ == "__main__": + for i in range(4, 8): + cmd = ( + r"for pid in $(ps aux | grep paster | grep -v grep | grep '\-%d' | awk '{print $2}'); do kill $pid; done" + % (i) + ) + + +def A(): + def B(): + def C(): + def D(): + def E(): + def F(): + def G(): + assert ( + c_float(val[0][0] / val[0][1]).value + == c_float(value[0][0] / value[0][1]).value + ), "%s didn't roundtrip" % tag + + +class xxxxxxxxxxxxxxxxxxxxx(xxxx.xxxxxxxxxxxxx): + def xxxxxxx_xxxxxx(xxxx): + assert xxxxxxx_xxxx in [ + x.xxxxx.xxxxxx.xxxxx.xxxxxx, + x.xxxxx.xxxxxx.xxxxx.xxxx, + ], "xxxxxxxxxxx xxxxxxx xxxx (xxxxxx xxxx) %x xxx xxxxx" % xxxxxxx_xxxx + + +value.__dict__[ + key +] = "test" # set some Thrift field to non-None in the struct aa bb cc dd ee + +RE_ONE_BACKSLASH = { + "asdf_hjkl_jkl": re.compile( + r"(?>\n" +) + +assert str(suffix_arr) == ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) != ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) <= ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) >= ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) < ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert str(suffix_arr) > ( + "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert ( + str(suffix_arr) + in "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', 'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', 'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert ( + str(suffix_arr) + not in "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', 'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', 'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +message = ( + f"1. Go to Google Developers Console and log in with your Google account." + "(https://console.developers.google.com/)" + "2. You should be prompted to create a new project (name does not matter)." + "3. Click on Enable APIs and Services at the top." + "4. In the list of APIs choose or search for YouTube Data API v3 and " + "click on it. Choose Enable." + "5. Click on Credentials on the left navigation bar." + "6. Click on Create Credential at the top." + '7. At the top click the link for "API key".' + "8. No application restrictions are needed. Click Create at the bottom." + "9. You now have a key to add to `{prefix}set api youtube api_key`" +) +message = ( + f"1. Go to Google Developers Console and log in with your Google account." + "(https://console.developers.google.com/)" + "2. You should be prompted to create a new project (name does not matter)." + f"3. Click on Enable APIs and Services at the top." + "4. In the list of APIs choose or search for YouTube Data API v3 and " + "click on it. Choose Enable." + f"5. Click on Credentials on the left navigation bar." + "6. Click on Create Credential at the top." + '7. At the top click the link for "API key".' + "8. No application restrictions are needed. Click Create at the bottom." + "9. You now have a key to add to `{prefix}set api youtube api_key`" +) +message = ( + f"1. Go to Google Developers Console and log in with your Google account." + "(https://console.developers.google.com/)" + "2. You should be prompted to create a new project (name does not matter)." + f"3. Click on Enable APIs and Services at the top." + "4. In the list of APIs choose or search for YouTube Data API v3 and " + "click on it. Choose Enable." + f"5. Click on Credentials on the left navigation bar." + "6. Click on Create Credential at the top." + '7. At the top click the link for "API key".' + "8. No application restrictions are needed. Click Create at the bottom." + f"9. You now have a key to add to `{prefix}set api youtube api_key`" +) + +# It shouldn't matter if the string prefixes are capitalized. +temp_msg = ( + f"{F'{humanize_number(pos)}.': <{pound_len+2}} " + f"{balance: <{bal_len + 5}} " + f"<<{author.display_name}>>\n" +) + +fstring = ( + f"We have to remember to escape {braces}." " Like {these}." f" But not {this}." +) + +welcome_to_programming = R"hello," R" world!" + +fstring = f"f-strings definitely make things more {difficult} than they need to be for {{black}}. But boy they sure are handy. The problem is that some lines will need to have the 'f' whereas others do not. This {line}, for example, needs one." + +x = f"This is a long string which contains an f-expr that should not split {{{[i for i in range(5)]}}}." + +x = "\N{BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR}\N{VARIATION SELECTOR-16}" + +xxxxxx_xxx_xxxx_xx_xxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxx_xxxx_xxxx_xxxxx = xxxx.xxxxxx.xxxxxxxxx.xxxxxxxxxxxxxxxxxxxx( + xx_xxxxxx={ + "x3_xxxxxxxx": "xxx3_xxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxx_xxxxxxxx_xxxxxx_xxxxxxx", + }, +) + +# Regression test for https://github.com/psf/black/issues/3117. +some_dict = { + "something_something": r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t" + r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t", +} + +# Regression test for https://github.com/psf/black/issues/3459. +xxxx( + empty_str_as_first_split="" + f"xxxxxxx {xxxxxxxxxx} xxx xxxxxxxxxx xxxxx xxx xxx xx " + "xxxxx xxxxxxxxx xxxxxxx, xxx xxxxxxxxxxx xxx xxxxx. " + f"xxxxxxxxxxxxx xxxx xx xxxxxxxxxx. xxxxx: {x.xxx}", + empty_u_str_as_first_split="" + f"xxxxxxx {xxxxxxxxxx} xxx xxxxxxxxxx xxxxx xxx xxx xx " + "xxxxx xxxxxxxxx xxxxxxx, xxx xxxxxxxxxxx xxx xxxxx. " + f"xxxxxxxxxxxxx xxxx xx xxxxxxxxxx. xxxxx: {x.xxx}", +) + +# Regression test for https://github.com/psf/black/issues/3455. +a_dict = { + "/this/is/a/very/very/very/very/very/very/very/very/very/very/long/key/without/spaces": + # And there is a comment before the value + ("item1", "item2", "item3"), +} + +# Regression test for https://github.com/psf/black/issues/3506. +s = ( + "With single quote: ' " + f" {my_dict['foo']}" + ' With double quote: " ' + f' {my_dict["bar"]}' +) + +s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry:\'{my_dict["foo"]}\'' +``` + +## Black Output + +```python +class A: + def foo(): + result = type(message)("") + + +# Don't merge multiline (e.g. triple-quoted) strings. +def foo(): + query = ( + """SELECT xxxxxxxxxxxxxxxxxxxx(xxx)""" + """ FROM xxxxxxxxxxxxxxxx WHERE xxxxxxxxxx AND xxx <> xxxxxxxxxxxxxx()""" + ) + + +# There was a bug where tuples were being identified as long strings. +long_tuple = ( + "Apple", + "Berry", + "Cherry", + "Dill", + "Evergreen", + "Fig", + "Grape", + "Harry", + "Iglu", + "Jaguar", +) + +stupid_format_method_bug = ( + "Some really long string that just so happens to be the {} {} to force the 'format'" + " method to hang over the line length boundary. This is pretty annoying.".format( + "perfect", "length" + ) +) + + +class A: + def foo(): + os.system( + "This is a regression test. xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx" + " xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx" + " xxxx.".format("xxxxxxxxxx", "xxxxxx", "xxxxxxxxxx") + ) + + +class A: + def foo(): + XXXXXXXXXXXX.append(( + "xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx, xxxx_xxxx_xxxxxxxxxx={})".format( + xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx + ), + my_var, + my_other_var, + )) + + +class A: + class B: + def foo(): + bar( + "[{}]: xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx={}" + " xxxx_xxxx_xxxxxxxxxx={}, xxxx={})".format( + xxxx._xxxxxxxxxxxxxx, xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx, xxxxxxx + ), + varX, + varY, + varZ, + ) + + +def foo(xxxx): + for xxx_xxxx, _xxx_xxx, _xxx_xxxxx, xxx_xxxx in xxxx: + for xxx in xxx_xxxx: + assert ("x" in xxx) or (xxx in xxx_xxx_xxxxx), ( + "{0} xxxxxxx xx {1}, xxx {1} xx xxx xx xxxx xx xxx xxxx: xxx xxxx {2}" + .format(xxx_xxxx, xxx, xxxxxx.xxxxxxx(xxx_xxx_xxxxx)) + ) + + +class A: + def disappearing_comment(): + return ( + ( # xx -x xxxxxxx xx xxx xxxxxxx. + "{{xxx_xxxxxxxxxx_xxxxxxxx}} xxx xxxx {} {{xxxx}} >&2".format( + "{xxxx} {xxxxxx}" + if xxxxx.xx_xxxxxxxxxx + else ( # Disappearing Comment + "--xxxxxxx --xxxxxx=x --xxxxxx-xxxxx=xxxxxx" + " --xxxxxx-xxxx=xxxxxxxxxxx.xxx" + ) + ) + ), + (x, y, z), + ) + + +class A: + class B: + def foo(): + xxxxx_xxxx( + xx, + "\t" + "@xxxxxx '{xxxx_xxx}\t' > {xxxxxx_xxxx}.xxxxxxx;" + "{xxxx_xxx} >> {xxxxxx_xxxx}.xxxxxxx 2>&1; xx=$$?;" + "xxxx $$xx".format( + xxxx_xxx=xxxx_xxxxxxx, + xxxxxx_xxxx=xxxxxxx + "/" + xxxx_xxx_xxxx, + x=xxx_xxxxx_xxxxx_xxx, + ), + x, + y, + z, + ) + + +func_call_where_string_arg_has_method_call_and_bad_parens( + "A long string with {}. This string is so long that it is ridiculous. It can't fit" + " on one line at alllll.".format("formatting"), +) + +func_call_where_string_arg_has_old_fmt_and_bad_parens( + "A long string with {}. This string is so long that it is ridiculous. It can't fit" + " on one line at alllll." % "formatting", +) + +func_call_where_string_arg_has_old_fmt_and_bad_parens( + "A long string with {}. This {} is so long that it is ridiculous. It can't fit on" + " one line at alllll." % ("formatting", "string"), +) + + +class A: + def append(self): + if True: + xxxx.xxxxxxx.xxxxx( + "xxxxxxxxxx xxxx xx xxxxxx(%x) xx %x xxxx xx xxx %x.xx" + % (len(self) + 1, xxxx.xxxxxxxxxx, xxxx.xxxxxxxxxx) + + " %.3f (%s) to %.3f (%s).\n" + % ( + xxxx.xxxxxxxxx, + xxxx.xxxxxxxxxxxxxx(xxxx.xxxxxxxxx), + x, + xxxx.xxxxxxxxxxxxxx(xx), + ) + ) + + +class A: + def foo(): + some_func_call( + "xxxxxxxxxx", + "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " + '"xxxx xxxxxxx xxxxxx xxxx; xxxx xxxxxx_xxxxx xxxxxx xxxx; ' + "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" ", + None, + ("xxxxxxxxxxx",), + ), + + +class A: + def foo(): + some_func_call( + "xx {xxxxxxxxxxx}/xxxxxxxxxxx.xxx xxxx.xxx && xxxxxx -x " + "xxxx, ('xxxxxxx xxxxxx xxxx, xxxx') xxxxxx_xxxxx xxxxxx xxxx; " + "xxxx.xxxx_xxxxxx(['xxxx.xxx'], xxxx.xxxxxxx().xxxxxxxxxx)\" ", + None, + ("xxxxxxxxxxx",), + ), + + +xxxxxxx = { + "xx": ( + "xxxx xxxxxxx xxxxxxxxx -x xxx -x /xxx/{0} -x xxx,xxx -xx {1} -xx {1} -xx" + " xxx=xxx_xxxx,xxx_xx,xxx_xxx,xxx_xxxx,xxx_xx,xxx_xxx | xxxxxx -x xxxxxxxx -x" + " xxxxxxxx -x" + ), + "xx": ( + "xxxx xxxxxxx xxxxxxxxx -x xxx -x /xxx/{0} -x xxx,xxx -xx {1} -xx {1} -xx" + " xxx=xxx_xxxx_xxx_xxxx,xxx_xx_xxx_xxxx,xxx_xxxx_xxx_xxxx,xxx_xx_xxxx_xxxx,xxx_xxx_xxxx,xxx_xxx_xxxx" + " xxxx=xxx | xxxxxx -x xxxxxxxx -x xxxxxxxx -x" + ), +} + + +class A: + def foo(self): + if True: + xxxxx_xxxxxxxxxxxx( + "xxx xxxxxx xxx xxxxxxxxx.xx xx xxxxxxxx. xxx xxxxxxxxxxxxx.xx" + " xxxxxxx " + + "xx xxxxxx xxxxxx xxxxxx xx xxxxxxx xxx xxx ${0} xx x xxxxxxxx xxxxx" + .xxxxxx(xxxxxx_xxxxxx_xxx) + ) + + +class A: + class B: + def foo(): + row = { + "xxxxxxxxxxxxxxx": xxxxxx_xxxxx_xxxx, + # 'xxxxxxxxxxxxxxxxxxxxxxx' + # 'xxxxxxxxxxxxxxxxxxxxxx' + # 'xxxxxxxxxxxxxxxxxx' + # 'xxxxxxxxxxxxxxxxx' + "xxxxxxxxxx": xxxxx_xxxxx, + } + + +class A: + def xxxx_xxx_xx_xxxxxxxxxx_xxxx_xxxxxxxxx(xxxx): + xxxxxxxx = [ + xxxxxxxxxxxxxxxx( + "xxxx", + xxxxxxxxxxx={ + "xxxx": 1.0, + }, + xxxxxx={"xxxxxx 1": xxxxxx(xxxx="xxxxxx 1", xxxxxx=600.0)}, + xxxxxxxx_xxxxxxx=0.0, + ), + xxxxxxxxxxxxxxxx( + "xxxxxxx", + xxxxxxxxxxx={ + "xxxx": 1.0, + }, + xxxxxx={"xxxxxx 1": xxxxxx(xxxx="xxxxxx 1", xxxxxx=200.0)}, + xxxxxxxx_xxxxxxx=0.0, + ), + xxxxxxxxxxxxxxxx( + "xxxx", + ), + ] + + +some_dictionary = { + "xxxxx006": [ + ( + "xxx-xxx" + " xxxxx3xxxx1xx2xxxxxxxxxxxxxx0xx6xxxxxxxxxx2xxxxxx9xxxxxxxxxx0xxxxx1xxx2x/xx9xx6+x+xxxxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxxxx43xxx2xx2x4x++xxx6xxxxxxxxx+xxxxx/xx9x+xxxxxxxxxxxxxx8x15xxxxxxxxxxxxxxxxx82xx/xxxxxxxxxxxxxx/x5xxxxxxxxxxxxxx6xxxxxx74x4/xxx4x+xxxxxxxxx2xxxxxxxx87xxxxx4xxxxxxxx3xx0xxxxx4xxx1xx9xx5xxxxxxx/xxxxx5xx6xx4xxxx1x/x2xxxxxxxxxxxx64xxxxxxx1x0xx5xxxxxxxxxxxxxx==" + " xxxxx000 xxxxxxxxxx\n" + ), + ( + "xxx-xxx" + " xxxxx3xxxx1xx2xxxxxxxxxxxxxx6xxxxxxxxxxxxxx9xxxxxxxxxxxxx3xxx9xxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxxxx2xxxx2xxx6xxxxx/xx54xxxxxxxxx4xxx3xxxxxx9xx3xxxxx39xxxxxxxxx5xx91xxxx7xxxxxx8xxxxxxxxxxxxxxxx9xxx93xxxxxxxxxxxxxxxxx7xxx8xx8xx4/x1xxxxx1x3xxxxxxxxxxxxx3xxxxxx9xx4xx4x7xxxxxxxxxxxxx1xxxxxxxxx7xxxxxxxxxxxxxx4xx6xxxxxxxxx9xxx7xxxx2xxxxxxxxxxxxxxxxxxxxxx8xxxxxxxxxxxxxxxxxxxx6xx==" + " xxxxx010 xxxxxxxxxx\n" + ), + ], + "xxxxx016": [ + ( + "xxx-xxx" + " xxxxx3xxxx1xx2xxxxxxxxxxxxxx0xx6xxxxxxxxxx2xxxxxx9xxxxxxxxxx0xxxxx1xxx2x/xx9xx6+x+xxxxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxxxx43xxx2xx2x4x++xxx6xxxxxxxxx+xxxxx/xx9x+xxxxxxxxxxxxxx8x15xxxxxxxxxxxxxxxxx82xx/xxxxxxxxxxxxxx/x5xxxxxxxxxxxxxx6xxxxxx74x4/xxx4x+xxxxxxxxx2xxxxxxxx87xxxxx4xxxxxxxx3xx0xxxxx4xxx1xx9xx5xxxxxxx/xxxxx5xx6xx4xxxx1x/x2xxxxxxxxxxxx64xxxxxxx1x0xx5xxxxxxxxxxxxxx==" + " xxxxx000 xxxxxxxxxx\n" + ), + ( + "xxx-xxx" + " xxxxx3xxxx1xx2xxxxxxxxxxxxxx6xxxxxxxxxxxxxx9xxxxxxxxxxxxx3xxx9xxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxxxx2xxxx2xxx6xxxxx/xx54xxxxxxxxx4xxx3xxxxxx9xx3xxxxx39xxxxxxxxx5xx91xxxx7xxxxxx8xxxxxxxxxxxxxxxx9xxx93xxxxxxxxxxxxxxxxx7xxx8xx8xx4/x1xxxxx1x3xxxxxxxxxxxxx3xxxxxx9xx4xx4x7xxxxxxxxxxxxx1xxxxxxxxx7xxxxxxxxxxxxxx4xx6xxxxxxxxx9xxx7xxxx2xxxxxxxxxxxxxxxxxxxxxx8xxxxxxxxxxxxxxxxxxxx6xx==" + " xxxxx010 xxxxxxxxxx\n" + ), + ], +} + + +def foo(): + xxx_xxx = ( # xxxx xxxxxxxxxx xxxx xx xxxx xx xxx xxxxxxxx xxxxxx xxxxx. + 'xxxx xxx xxxxxxxx_xxxx xx "xxxxxxxxxx".\n xxx: xxxxxx xxxxxxxx_xxxx=xxxxxxxxxx' + ) + + +some_tuple = ("some string", "some string which should be joined") + +some_commented_string = ( # This comment stays at the top. + "This string is long but not so long that it needs hahahah toooooo be so greatttt" + " {} that I just can't think of any more good words to say about it at" + " allllllllllll".format("ha") # comments here are fine +) + +some_commented_string = ( + "This string is long but not so long that it needs hahahah toooooo be so greatttt" # But these + " {} that I just can't think of any more good words to say about it at" # comments will stay + " allllllllllll".format("ha") # comments here are fine +) + +lpar_and_rpar_have_comments = func_call( # LPAR Comment + "Long really ridiculous type of string that shouldn't really even exist at all. I" + " mean commmme onnn!!!", # Comma Comment +) # RPAR Comment + +cmd_fstring = ( + "sudo -E deluge-console info --detailed --sort-reverse=time_added " + f"{'' if ID is None else ID} | perl -nE 'print if /^{field}:/'" +) + +cmd_fstring = ( + "sudo -E deluge-console info --detailed --sort-reverse=time_added" + f" {'' if ID is None else ID} | perl -nE 'print if /^{field}:/'" +) + +cmd_fstring = ( + "sudo -E deluge-console info --detailed --sort-reverse=time_added" + f" {'{{}}' if ID is None else ID} | perl -nE 'print if /^{field}:/'" +) + +cmd_fstring = ( + "sudo -E deluge-console info --detailed --sort-reverse=time_added {'' if ID is" + f" None else ID}} | perl -nE 'print if /^{field}:/'" +) + +fstring = ( + "This string really doesn't need to be an {{fstring}}, but this one most" + f" certainly, absolutely {does}." +) + +fstring = f"We have to remember to escape {braces}. Like {{these}}. But not {this}." + + +class A: + class B: + def foo(): + st_error = STError( + f"This string ({string_leaf.value}) appears to be pointless (i.e. has" + " no parent)." + ) + + +def foo(): + user_regex = _lazy_re_compile( + r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*\Z" # dot-atom + r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"\Z)', # quoted-string + re.IGNORECASE, + ) + + +def foo(): + user_regex = _lazy_re_compile( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # dot-atom + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", # quoted-string + xyz, + ) + + +def foo(): + user_regex = _lazy_re_compile( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # dot-atom + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", # quoted-string + xyz, + ) + + +class A: + class B: + def foo(): + if not hasattr(module, name): + raise ValueError( + "Could not find object %s in %s.\n" + "Please note that you cannot serialize things like inner " + "classes. Please move the object into the main module " + "body to use migrations.\n" + "For more information, see " + "https://docs.djangoproject.com/en/%s/topics/migrations/#serializing-values" + % (name, module_name, get_docs_version()) + ) + + +class A: + class B: + def foo(): + if not hasattr(module, name): + raise ValueError( + "Could not find object %s in %s.\nPlease note that you cannot" + " serialize things like inner classes. Please move the object into" + " the main module body to use migrations.\nFor more information," + " see https://docs.djangoproject.com/en/%s/topics/migrations/#serializing-values" + % (name, module_name, get_docs_version()) + ) + + +x = ( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +) + + +class Step(StepBase): + def who(self): + self.cmd = ( + "SR AAAA-CORRECT NAME IS {last_name} {first_name}{middle_name}" + " {title}/P{passenger_association}".format( + last_name=last_name, + first_name=first_name, + middle_name=middle_name, + title=title, + passenger_association=passenger_association, + ) + ) + + +xxxxxxx_xxxxxx_xxxxxxx = xxx([ + xxxxxxxxxxxx( + xxxxxx_xxxxxxx=( + '((x.aaaaaaaaa = "xxxxxx.xxxxxxxxxxxxxxxxxxxxx") || (x.xxxxxxxxx =' + ' "xxxxxxxxxxxx")) && ' + # xxxxx xxxxxxxxxxxx xxxx xxx (xxxxxxxxxxxxxxxx) xx x xxxxxxxxx xx xxxxxx. + "(x.bbbbbbbbbbbb.xxx != " + '"xxx:xxx:xxx::cccccccccccc:xxxxxxx-xxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxxxx") && ' + ) + ) +]) + +if __name__ == "__main__": + for i in range(4, 8): + cmd = ( + r"for pid in $(ps aux | grep paster | grep -v grep | grep '\-%d' | awk" + r" '{print $2}'); do kill $pid; done" % (i) + ) + + +def A(): + def B(): + def C(): + def D(): + def E(): + def F(): + def G(): + assert ( + c_float(val[0][0] / val[0][1]).value + == c_float(value[0][0] / value[0][1]).value + ), "%s didn't roundtrip" % tag + + +class xxxxxxxxxxxxxxxxxxxxx(xxxx.xxxxxxxxxxxxx): + def xxxxxxx_xxxxxx(xxxx): + assert xxxxxxx_xxxx in [ + x.xxxxx.xxxxxx.xxxxx.xxxxxx, + x.xxxxx.xxxxxx.xxxxx.xxxx, + ], ( + "xxxxxxxxxxx xxxxxxx xxxx (xxxxxx xxxx) %x xxx xxxxx" % xxxxxxx_xxxx + ) + + +value.__dict__[key] = ( + "test" # set some Thrift field to non-None in the struct aa bb cc dd ee +) + +RE_ONE_BACKSLASH = { + "asdf_hjkl_jkl": re.compile( + r"(?>\n" +) + +assert ( + str(suffix_arr) + == "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert ( + str(suffix_arr) + != "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert ( + str(suffix_arr) + <= "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert ( + str(suffix_arr) + >= "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert ( + str(suffix_arr) + < "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert ( + str(suffix_arr) + > "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', " + "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', " + "'o$', 'oo$', 'roo$', 'rykangaroo$', 'ykangaroo$']" +) +assert ( + str(suffix_arr) + in "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', 'grykangaroo$'," + " 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', 'o$', 'oo$', 'roo$', 'rykangaroo$'," + " 'ykangaroo$']" +) +assert ( + str(suffix_arr) + not in "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', 'grykangaroo$'," + " 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', 'o$', 'oo$', 'roo$'," + " 'rykangaroo$', 'ykangaroo$']" +) +message = ( + f"1. Go to Google Developers Console and log in with your Google account." + f"(https://console.developers.google.com/)" + f"2. You should be prompted to create a new project (name does not matter)." + f"3. Click on Enable APIs and Services at the top." + f"4. In the list of APIs choose or search for YouTube Data API v3 and " + f"click on it. Choose Enable." + f"5. Click on Credentials on the left navigation bar." + f"6. Click on Create Credential at the top." + f'7. At the top click the link for "API key".' + f"8. No application restrictions are needed. Click Create at the bottom." + f"9. You now have a key to add to `{{prefix}}set api youtube api_key`" +) +message = ( + f"1. Go to Google Developers Console and log in with your Google account." + f"(https://console.developers.google.com/)" + f"2. You should be prompted to create a new project (name does not matter)." + f"3. Click on Enable APIs and Services at the top." + f"4. In the list of APIs choose or search for YouTube Data API v3 and " + f"click on it. Choose Enable." + f"5. Click on Credentials on the left navigation bar." + f"6. Click on Create Credential at the top." + f'7. At the top click the link for "API key".' + f"8. No application restrictions are needed. Click Create at the bottom." + f"9. You now have a key to add to `{{prefix}}set api youtube api_key`" +) +message = ( + "1. Go to Google Developers Console and log in with your Google account." + "(https://console.developers.google.com/)" + "2. You should be prompted to create a new project (name does not matter)." + "3. Click on Enable APIs and Services at the top." + "4. In the list of APIs choose or search for YouTube Data API v3 and " + "click on it. Choose Enable." + "5. Click on Credentials on the left navigation bar." + "6. Click on Create Credential at the top." + '7. At the top click the link for "API key".' + "8. No application restrictions are needed. Click Create at the bottom." + f"9. You now have a key to add to `{prefix}set api youtube api_key`" +) + +# It shouldn't matter if the string prefixes are capitalized. +temp_msg = ( + f"{F'{humanize_number(pos)}.': <{pound_len+2}} " + f"{balance: <{bal_len + 5}} " + f"<<{author.display_name}>>\n" +) + +fstring = f"We have to remember to escape {braces}. Like {{these}}. But not {this}." + +welcome_to_programming = R"hello," R" world!" + +fstring = ( + f"f-strings definitely make things more {difficult} than they need to be for" + " {black}. But boy they sure are handy. The problem is that some lines will need" + f" to have the 'f' whereas others do not. This {line}, for example, needs one." +) + +x = ( + "This is a long string which contains an f-expr that should not split" + f" {{{[i for i in range(5)]}}}." +) + +x = ( + "\N{BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR}\N{VARIATION SELECTOR-16}" +) + +xxxxxx_xxx_xxxx_xx_xxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxx_xxxx_xxxx_xxxxx = xxxx.xxxxxx.xxxxxxxxx.xxxxxxxxxxxxxxxxxxxx( + xx_xxxxxx={ + "x3_xxxxxxxx": ( + "xxx3_xxxxx_xxxxxxxx_xxxxxxxx_xxxxxxxxxx_xxxxxxxx_xxxxxx_xxxxxxx" + ), + }, +) + +# Regression test for https://github.com/psf/black/issues/3117. +some_dict = { + "something_something": ( + r"Lorem ipsum dolor sit amet, an sed convenire eloquentiam \t" + r"signiferumque, duo ea vocibus consetetur scriptorem. Facer \t" + ), +} + +# Regression test for https://github.com/psf/black/issues/3459. +xxxx( + empty_str_as_first_split=( + "" + f"xxxxxxx {xxxxxxxxxx} xxx xxxxxxxxxx xxxxx xxx xxx xx " + "xxxxx xxxxxxxxx xxxxxxx, xxx xxxxxxxxxxx xxx xxxxx. " + f"xxxxxxxxxxxxx xxxx xx xxxxxxxxxx. xxxxx: {x.xxx}" + ), + empty_u_str_as_first_split=( + "" + f"xxxxxxx {xxxxxxxxxx} xxx xxxxxxxxxx xxxxx xxx xxx xx " + "xxxxx xxxxxxxxx xxxxxxx, xxx xxxxxxxxxxx xxx xxxxx. " + f"xxxxxxxxxxxxx xxxx xx xxxxxxxxxx. xxxxx: {x.xxx}" + ), +) + +# Regression test for https://github.com/psf/black/issues/3455. +a_dict = { + "/this/is/a/very/very/very/very/very/very/very/very/very/very/long/key/without/spaces": + # And there is a comment before the value + ("item1", "item2", "item3"), +} + +# Regression test for https://github.com/psf/black/issues/3506. +s = f"With single quote: ' {my_dict['foo']} With double quote: \" {my_dict['bar']}" + +s = ( + "Lorem Ipsum is simply dummy text of the printing and typesetting" + f" industry:'{my_dict['foo']}'" +) +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__type_annotations.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__type_annotations.py.snap new file mode 100644 index 0000000000000..8b8220f9c47cb --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__type_annotations.py.snap @@ -0,0 +1,115 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_long_strings__type_annotations.py +--- +## Input + +```python +def func( + arg1, + arg2, +) -> Set["this_is_a_very_long_module_name.AndAVeryLongClasName" + ".WithAVeryVeryVeryVeryVeryLongSubClassName"]: + pass + + +def func( + argument: ( + "VeryLongClassNameWithAwkwardGenericSubtype[int] |" + "VeryLongClassNameWithAwkwardGenericSubtype[str]" + ), +) -> ( + "VeryLongClassNameWithAwkwardGenericSubtype[int] |" + "VeryLongClassNameWithAwkwardGenericSubtype[str]" +): + pass + + +def func( + argument: ( + "int |" + "str" + ), +) -> Set["int |" + " str"]: + pass +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -21,6 +21,6 @@ + + + def func( +- argument: "int |" "str", ++ argument: ("int |" "str"), + ) -> Set["int |" " str"]: + pass +``` + +## Ruff Output + +```python +def func( + arg1, + arg2, +) -> Set[ + "this_is_a_very_long_module_name.AndAVeryLongClasName" + ".WithAVeryVeryVeryVeryVeryLongSubClassName" +]: + pass + + +def func( + argument: ( + "VeryLongClassNameWithAwkwardGenericSubtype[int] |" + "VeryLongClassNameWithAwkwardGenericSubtype[str]" + ), +) -> ( + "VeryLongClassNameWithAwkwardGenericSubtype[int] |" + "VeryLongClassNameWithAwkwardGenericSubtype[str]" +): + pass + + +def func( + argument: ("int |" "str"), +) -> Set["int |" " str"]: + pass +``` + +## Black Output + +```python +def func( + arg1, + arg2, +) -> Set[ + "this_is_a_very_long_module_name.AndAVeryLongClasName" + ".WithAVeryVeryVeryVeryVeryLongSubClassName" +]: + pass + + +def func( + argument: ( + "VeryLongClassNameWithAwkwardGenericSubtype[int] |" + "VeryLongClassNameWithAwkwardGenericSubtype[str]" + ), +) -> ( + "VeryLongClassNameWithAwkwardGenericSubtype[int] |" + "VeryLongClassNameWithAwkwardGenericSubtype[str]" +): + pass + + +def func( + argument: "int |" "str", +) -> Set["int |" " str"]: + pass +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_multiline_strings.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_multiline_strings.py.snap new file mode 100644 index 0000000000000..9e841c8b21eee --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_multiline_strings.py.snap @@ -0,0 +1,923 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_multiline_strings.py +--- +## Input + +```python +"""cow +say""", +call(3, "dogsay", textwrap.dedent("""dove + coo""" % "cowabunga")) +call(3, "dogsay", textwrap.dedent("""dove +coo""" % "cowabunga")) +call(3, textwrap.dedent("""cow + moo""" % "cowabunga"), "dogsay") +call(3, "dogsay", textwrap.dedent("""crow + caw""" % "cowabunga"),) +call(3, textwrap.dedent("""cat + meow""" % "cowabunga"), {"dog", "say"}) +call(3, {"dog", "say"}, textwrap.dedent("""horse + neigh""" % "cowabunga")) +call(3, {"dog", "say"}, textwrap.dedent("""pig + oink""" % "cowabunga"),) +textwrap.dedent("""A one-line triple-quoted string.""") +textwrap.dedent("""A two-line triple-quoted string +since it goes to the next line.""") +textwrap.dedent("""A three-line triple-quoted string +that not only goes to the next line +but also goes one line beyond.""") +textwrap.dedent("""\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. file contents. +""") +path.write_text(textwrap.dedent("""\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. file contents. +""")) +path.write_text(textwrap.dedent("""\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. {config_filename} file contents. +""".format("config_filename", config_filename))) +# Another use case +data = yaml.load("""\ +a: 1 +b: 2 +""") +data = yaml.load("""\ +a: 1 +b: 2 +""",) +data = yaml.load( + """\ + a: 1 + b: 2 +""" +) + +MULTILINE = """ +foo +""".replace("\n", "") +generated_readme = lambda project_name: """ +{} + + +""".strip().format(project_name) +parser.usage += """ +Custom extra help summary. + +Extra test: +- with +- bullets +""" + + +def get_stuff(cr, value): + # original + cr.execute(""" + SELECT whatever + FROM some_table t + WHERE id = %s + """, [value]) + return cr.fetchone() + + +def get_stuff(cr, value): + # preferred + cr.execute( + """ + SELECT whatever + FROM some_table t + WHERE id = %s + """, + [value], + ) + return cr.fetchone() + + +call(arg1, arg2, """ +short +""", arg3=True) +test_vectors = [ + "one-liner\n", + "two\nliner\n", + """expressed +as a three line +mulitline string""", +] + +_wat = re.compile( + r""" + regex + """, + re.MULTILINE | re.VERBOSE, +) +dis_c_instance_method = """\ +%3d 0 LOAD_FAST 1 (x) + 2 LOAD_CONST 1 (1) + 4 COMPARE_OP 2 (==) + 6 LOAD_FAST 0 (self) + 8 STORE_ATTR 0 (x) + 10 LOAD_CONST 0 (None) + 12 RETURN_VALUE +""" % (_C.__init__.__code__.co_firstlineno + 1,) +path.write_text(textwrap.dedent("""\ + A triple-quoted string + actually {verb} the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. {file_type} file contents. +""".format(verb="using", file_type="test"))) +{"""cow +moos"""} +["""cow +moos"""] +["""cow +moos""", """dog +woofs +and +barks"""] +def dastardly_default_value( + cow: String = json.loads("""this +is +quite +the +dastadardly +value!"""), + **kwargs, +): + pass + +print(f""" + This {animal} + moos and barks +{animal} say +""") +msg = f"""The arguments {bad_arguments} were passed in. +Please use `--build-option` instead, +`--global-option` is reserved to flags like `--verbose` or `--quiet`. +""" + +this_will_become_one_line = ( + "a" + "b" + "c" +) + +this_will_stay_on_three_lines = ( + "a" # comment + "b" + "c" +) + +this_will_also_become_one_line = ( # comment + "a" + "b" + "c" +) +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,95 +1,138 @@ +-"""cow ++( ++ """cow + say""", ++) + call( + 3, + "dogsay", +- textwrap.dedent("""dove +- coo""" % "cowabunga"), ++ textwrap.dedent( ++ """dove ++ coo""" ++ % "cowabunga" ++ ), + ) + call( + 3, + "dogsay", +- textwrap.dedent("""dove +-coo""" % "cowabunga"), ++ textwrap.dedent( ++ """dove ++coo""" ++ % "cowabunga" ++ ), + ) + call( + 3, +- textwrap.dedent("""cow +- moo""" % "cowabunga"), ++ textwrap.dedent( ++ """cow ++ moo""" ++ % "cowabunga" ++ ), + "dogsay", + ) + call( + 3, + "dogsay", +- textwrap.dedent("""crow +- caw""" % "cowabunga"), ++ textwrap.dedent( ++ """crow ++ caw""" ++ % "cowabunga" ++ ), + ) + call( + 3, +- textwrap.dedent("""cat +- meow""" % "cowabunga"), ++ textwrap.dedent( ++ """cat ++ meow""" ++ % "cowabunga" ++ ), + {"dog", "say"}, + ) + call( + 3, + {"dog", "say"}, +- textwrap.dedent("""horse +- neigh""" % "cowabunga"), ++ textwrap.dedent( ++ """horse ++ neigh""" ++ % "cowabunga" ++ ), + ) + call( + 3, + {"dog", "say"}, +- textwrap.dedent("""pig +- oink""" % "cowabunga"), ++ textwrap.dedent( ++ """pig ++ oink""" ++ % "cowabunga" ++ ), + ) + textwrap.dedent("""A one-line triple-quoted string.""") +-textwrap.dedent("""A two-line triple-quoted string +-since it goes to the next line.""") +-textwrap.dedent("""A three-line triple-quoted string ++textwrap.dedent( ++ """A two-line triple-quoted string ++since it goes to the next line.""" ++) ++textwrap.dedent( ++ """A three-line triple-quoted string + that not only goes to the next line +-but also goes one line beyond.""") +-textwrap.dedent("""\ ++but also goes one line beyond.""" ++) ++textwrap.dedent( ++ """\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. file contents. +-""") +-path.write_text(textwrap.dedent("""\ ++""" ++) ++path.write_text( ++ textwrap.dedent( ++ """\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. file contents. +-""")) +-path.write_text(textwrap.dedent("""\ ++""" ++ ) ++) ++path.write_text( ++ textwrap.dedent( ++ """\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. {config_filename} file contents. +-""".format("config_filename", config_filename))) ++""".format("config_filename", config_filename) ++ ) ++) + # Another use case +-data = yaml.load("""\ ++data = yaml.load( ++ """\ + a: 1 + b: 2 +-""") ++""" ++) + data = yaml.load( + """\ + a: 1 + b: 2 + """, + ) +-data = yaml.load("""\ ++data = yaml.load( ++ """\ + a: 1 + b: 2 +-""") ++""" ++) + + MULTILINE = """ + foo + """.replace("\n", "") +-generated_readme = lambda project_name: """ ++generated_readme = ( ++ lambda project_name: """ + {} + + + """.strip().format(project_name) ++) + parser.usage += """ + Custom extra help summary. + +@@ -156,16 +199,24 @@ + 10 LOAD_CONST 0 (None) + 12 RETURN_VALUE + """ % (_C.__init__.__code__.co_firstlineno + 1,) +-path.write_text(textwrap.dedent("""\ ++path.write_text( ++ textwrap.dedent( ++ """\ + A triple-quoted string + actually {verb} the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. {file_type} file contents. +-""".format(verb="using", file_type="test"))) +-{"""cow +-moos"""} +-["""cow +-moos"""] ++""".format(verb="using", file_type="test") ++ ) ++) ++{ ++ """cow ++moos""" ++} ++[ ++ """cow ++moos""" ++] + [ + """cow + moos""", +@@ -177,28 +228,32 @@ + + + def dastardly_default_value( +- cow: String = json.loads("""this ++ cow: String = json.loads( ++ """this + is + quite + the + dastadardly +-value!"""), ++value!""" ++ ), + **kwargs, + ): + pass + + +-print(f""" ++print( ++ f""" + This {animal} + moos and barks + {animal} say +-""") ++""" ++) + msg = f"""The arguments {bad_arguments} were passed in. + Please use `--build-option` instead, + `--global-option` is reserved to flags like `--verbose` or `--quiet`. + """ + +-this_will_become_one_line = "abc" ++this_will_become_one_line = "a" "b" "c" + + this_will_stay_on_three_lines = ( + "a" # comment +@@ -206,4 +261,6 @@ + "c" + ) + +-this_will_also_become_one_line = "abc" # comment ++this_will_also_become_one_line = ( # comment ++ "a" "b" "c" ++) +``` + +## Ruff Output + +```python +( + """cow +say""", +) +call( + 3, + "dogsay", + textwrap.dedent( + """dove + coo""" + % "cowabunga" + ), +) +call( + 3, + "dogsay", + textwrap.dedent( + """dove +coo""" + % "cowabunga" + ), +) +call( + 3, + textwrap.dedent( + """cow + moo""" + % "cowabunga" + ), + "dogsay", +) +call( + 3, + "dogsay", + textwrap.dedent( + """crow + caw""" + % "cowabunga" + ), +) +call( + 3, + textwrap.dedent( + """cat + meow""" + % "cowabunga" + ), + {"dog", "say"}, +) +call( + 3, + {"dog", "say"}, + textwrap.dedent( + """horse + neigh""" + % "cowabunga" + ), +) +call( + 3, + {"dog", "say"}, + textwrap.dedent( + """pig + oink""" + % "cowabunga" + ), +) +textwrap.dedent("""A one-line triple-quoted string.""") +textwrap.dedent( + """A two-line triple-quoted string +since it goes to the next line.""" +) +textwrap.dedent( + """A three-line triple-quoted string +that not only goes to the next line +but also goes one line beyond.""" +) +textwrap.dedent( + """\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. file contents. +""" +) +path.write_text( + textwrap.dedent( + """\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. file contents. +""" + ) +) +path.write_text( + textwrap.dedent( + """\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. {config_filename} file contents. +""".format("config_filename", config_filename) + ) +) +# Another use case +data = yaml.load( + """\ +a: 1 +b: 2 +""" +) +data = yaml.load( + """\ +a: 1 +b: 2 +""", +) +data = yaml.load( + """\ + a: 1 + b: 2 +""" +) + +MULTILINE = """ +foo +""".replace("\n", "") +generated_readme = ( + lambda project_name: """ +{} + + +""".strip().format(project_name) +) +parser.usage += """ +Custom extra help summary. + +Extra test: +- with +- bullets +""" + + +def get_stuff(cr, value): + # original + cr.execute( + """ + SELECT whatever + FROM some_table t + WHERE id = %s + """, + [value], + ) + return cr.fetchone() + + +def get_stuff(cr, value): + # preferred + cr.execute( + """ + SELECT whatever + FROM some_table t + WHERE id = %s + """, + [value], + ) + return cr.fetchone() + + +call( + arg1, + arg2, + """ +short +""", + arg3=True, +) +test_vectors = [ + "one-liner\n", + "two\nliner\n", + """expressed +as a three line +mulitline string""", +] + +_wat = re.compile( + r""" + regex + """, + re.MULTILINE | re.VERBOSE, +) +dis_c_instance_method = """\ +%3d 0 LOAD_FAST 1 (x) + 2 LOAD_CONST 1 (1) + 4 COMPARE_OP 2 (==) + 6 LOAD_FAST 0 (self) + 8 STORE_ATTR 0 (x) + 10 LOAD_CONST 0 (None) + 12 RETURN_VALUE +""" % (_C.__init__.__code__.co_firstlineno + 1,) +path.write_text( + textwrap.dedent( + """\ + A triple-quoted string + actually {verb} the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. {file_type} file contents. +""".format(verb="using", file_type="test") + ) +) +{ + """cow +moos""" +} +[ + """cow +moos""" +] +[ + """cow +moos""", + """dog +woofs +and +barks""", +] + + +def dastardly_default_value( + cow: String = json.loads( + """this +is +quite +the +dastadardly +value!""" + ), + **kwargs, +): + pass + + +print( + f""" + This {animal} + moos and barks +{animal} say +""" +) +msg = f"""The arguments {bad_arguments} were passed in. +Please use `--build-option` instead, +`--global-option` is reserved to flags like `--verbose` or `--quiet`. +""" + +this_will_become_one_line = "a" "b" "c" + +this_will_stay_on_three_lines = ( + "a" # comment + "b" + "c" +) + +this_will_also_become_one_line = ( # comment + "a" "b" "c" +) +``` + +## Black Output + +```python +"""cow +say""", +call( + 3, + "dogsay", + textwrap.dedent("""dove + coo""" % "cowabunga"), +) +call( + 3, + "dogsay", + textwrap.dedent("""dove +coo""" % "cowabunga"), +) +call( + 3, + textwrap.dedent("""cow + moo""" % "cowabunga"), + "dogsay", +) +call( + 3, + "dogsay", + textwrap.dedent("""crow + caw""" % "cowabunga"), +) +call( + 3, + textwrap.dedent("""cat + meow""" % "cowabunga"), + {"dog", "say"}, +) +call( + 3, + {"dog", "say"}, + textwrap.dedent("""horse + neigh""" % "cowabunga"), +) +call( + 3, + {"dog", "say"}, + textwrap.dedent("""pig + oink""" % "cowabunga"), +) +textwrap.dedent("""A one-line triple-quoted string.""") +textwrap.dedent("""A two-line triple-quoted string +since it goes to the next line.""") +textwrap.dedent("""A three-line triple-quoted string +that not only goes to the next line +but also goes one line beyond.""") +textwrap.dedent("""\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. file contents. +""") +path.write_text(textwrap.dedent("""\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. file contents. +""")) +path.write_text(textwrap.dedent("""\ + A triple-quoted string + actually leveraging the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. {config_filename} file contents. +""".format("config_filename", config_filename))) +# Another use case +data = yaml.load("""\ +a: 1 +b: 2 +""") +data = yaml.load( + """\ +a: 1 +b: 2 +""", +) +data = yaml.load("""\ + a: 1 + b: 2 +""") + +MULTILINE = """ +foo +""".replace("\n", "") +generated_readme = lambda project_name: """ +{} + + +""".strip().format(project_name) +parser.usage += """ +Custom extra help summary. + +Extra test: +- with +- bullets +""" + + +def get_stuff(cr, value): + # original + cr.execute( + """ + SELECT whatever + FROM some_table t + WHERE id = %s + """, + [value], + ) + return cr.fetchone() + + +def get_stuff(cr, value): + # preferred + cr.execute( + """ + SELECT whatever + FROM some_table t + WHERE id = %s + """, + [value], + ) + return cr.fetchone() + + +call( + arg1, + arg2, + """ +short +""", + arg3=True, +) +test_vectors = [ + "one-liner\n", + "two\nliner\n", + """expressed +as a three line +mulitline string""", +] + +_wat = re.compile( + r""" + regex + """, + re.MULTILINE | re.VERBOSE, +) +dis_c_instance_method = """\ +%3d 0 LOAD_FAST 1 (x) + 2 LOAD_CONST 1 (1) + 4 COMPARE_OP 2 (==) + 6 LOAD_FAST 0 (self) + 8 STORE_ATTR 0 (x) + 10 LOAD_CONST 0 (None) + 12 RETURN_VALUE +""" % (_C.__init__.__code__.co_firstlineno + 1,) +path.write_text(textwrap.dedent("""\ + A triple-quoted string + actually {verb} the textwrap.dedent functionality + that ends in a trailing newline, + representing e.g. {file_type} file contents. +""".format(verb="using", file_type="test"))) +{"""cow +moos"""} +["""cow +moos"""] +[ + """cow +moos""", + """dog +woofs +and +barks""", +] + + +def dastardly_default_value( + cow: String = json.loads("""this +is +quite +the +dastadardly +value!"""), + **kwargs, +): + pass + + +print(f""" + This {animal} + moos and barks +{animal} say +""") +msg = f"""The arguments {bad_arguments} were passed in. +Please use `--build-option` instead, +`--global-option` is reserved to flags like `--verbose` or `--quiet`. +""" + +this_will_become_one_line = "abc" + +this_will_stay_on_three_lines = ( + "a" # comment + "b" + "c" +) + +this_will_also_become_one_line = "abc" # comment +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_no_blank_line_before_docstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_no_blank_line_before_docstring.py.snap new file mode 100644 index 0000000000000..bd93e24292838 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_no_blank_line_before_docstring.py.snap @@ -0,0 +1,134 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_no_blank_line_before_docstring.py +--- +## Input + +```python +def line_before_docstring(): + + """Please move me up""" + + +class LineBeforeDocstring: + + """Please move me up""" + + +class EvenIfThereIsAMethodAfter: + + """I'm the docstring""" + def method(self): + pass + + +class TwoLinesBeforeDocstring: + + + """I want to be treated the same as if I were closer""" + + +class MultilineDocstringsAsWell: + + """I'm so far + + and on so many lines... + """ +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -3,10 +3,12 @@ + + + class LineBeforeDocstring: ++ + """Please move me up""" + + + class EvenIfThereIsAMethodAfter: ++ + """I'm the docstring""" + + def method(self): +@@ -14,10 +16,12 @@ + + + class TwoLinesBeforeDocstring: ++ + """I want to be treated the same as if I were closer""" + + + class MultilineDocstringsAsWell: ++ + """I'm so far + + and on so many lines... +``` + +## Ruff Output + +```python +def line_before_docstring(): + """Please move me up""" + + +class LineBeforeDocstring: + + """Please move me up""" + + +class EvenIfThereIsAMethodAfter: + + """I'm the docstring""" + + def method(self): + pass + + +class TwoLinesBeforeDocstring: + + """I want to be treated the same as if I were closer""" + + +class MultilineDocstringsAsWell: + + """I'm so far + + and on so many lines... + """ +``` + +## Black Output + +```python +def line_before_docstring(): + """Please move me up""" + + +class LineBeforeDocstring: + """Please move me up""" + + +class EvenIfThereIsAMethodAfter: + """I'm the docstring""" + + def method(self): + pass + + +class TwoLinesBeforeDocstring: + """I want to be treated the same as if I were closer""" + + +class MultilineDocstringsAsWell: + """I'm so far + + and on so many lines... + """ +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_pattern_matching_trailing_comma.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_pattern_matching_trailing_comma.py.snap new file mode 100644 index 0000000000000..257d3e63f6003 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_pattern_matching_trailing_comma.py.snap @@ -0,0 +1,104 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pattern_matching_trailing_comma.py +--- +## Input + +```python +match maybe, multiple: + case perhaps, 5: + pass + case perhaps, 6,: + pass + + +match more := (than, one), indeed,: + case _, (5, 6): + pass + case [[5], (6)], [7],: + pass + case _: + pass +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -8,13 +8,16 @@ + pass + + +-match more := (than, one), indeed,: ++match ( ++ more := (than, one), ++ indeed, ++): + case _, (5, 6): + pass +- case ( ++ case [ + [[5], (6)], + [7], +- ): ++ ]: + pass + case _: + pass +``` + +## Ruff Output + +```python +match maybe, multiple: + case perhaps, 5: + pass + case ( + perhaps, + 6, + ): + pass + + +match ( + more := (than, one), + indeed, +): + case _, (5, 6): + pass + case [ + [[5], (6)], + [7], + ]: + pass + case _: + pass +``` + +## Black Output + +```python +match maybe, multiple: + case perhaps, 5: + pass + case ( + perhaps, + 6, + ): + pass + + +match more := (than, one), indeed,: + case _, (5, 6): + pass + case ( + [[5], (6)], + [7], + ): + pass + case _: + pass +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_pep_572.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_pep_572.py.snap new file mode 100644 index 0000000000000..03f27f16c2f35 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_pep_572.py.snap @@ -0,0 +1,38 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep_572.py +--- +## Input + +```python +x[(a:=0):] +x[:(a:=0)] +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,2 +1,2 @@ +-x[(a := 0):] +-x[:(a := 0)] ++x[(a := 0) :] ++x[: (a := 0)] +``` + +## Ruff Output + +```python +x[(a := 0) :] +x[: (a := 0)] +``` + +## Black Output + +```python +x[(a := 0):] +x[:(a := 0)] +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_percent_precedence.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_percent_precedence.py.snap new file mode 100644 index 0000000000000..01f401e99a11a --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_percent_precedence.py.snap @@ -0,0 +1,99 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_percent_precedence.py +--- +## Input + +```python +("" % a) ** 2 +("" % a)[0] +("" % a)() +("" % a).b + +2 * ("" % a) +2 @ ("" % a) +2 / ("" % a) +2 // ("" % a) +2 % ("" % a) ++("" % a) +b + ("" % a) +-("" % a) +b - ("" % a) +b + -("" % a) +~("" % a) +2 ** ("" % a) +await ("" % a) +b[("" % a)] +b(("" % a)) +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -9,9 +9,9 @@ + 2 // ("" % a) + 2 % ("" % a) + +("" % a) +-b + "" % a ++b + ("" % a) + -("" % a) +-b - "" % a ++b - ("" % a) + b + -("" % a) + ~("" % a) + 2 ** ("" % a) +``` + +## Ruff Output + +```python +("" % a) ** 2 +("" % a)[0] +("" % a)() +("" % a).b + +2 * ("" % a) +2 @ ("" % a) +2 / ("" % a) +2 // ("" % a) +2 % ("" % a) ++("" % a) +b + ("" % a) +-("" % a) +b - ("" % a) +b + -("" % a) +~("" % a) +2 ** ("" % a) +await ("" % a) +b[("" % a)] +b(("" % a)) +``` + +## Black Output + +```python +("" % a) ** 2 +("" % a)[0] +("" % a)() +("" % a).b + +2 * ("" % a) +2 @ ("" % a) +2 / ("" % a) +2 // ("" % a) +2 % ("" % a) ++("" % a) +b + "" % a +-("" % a) +b - "" % a +b + -("" % a) +~("" % a) +2 ** ("" % a) +await ("" % a) +b[("" % a)] +b(("" % a)) +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_power_op_spacing.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_power_op_spacing.py.snap new file mode 100644 index 0000000000000..f7cb0914c0304 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_power_op_spacing.py.snap @@ -0,0 +1,354 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_power_op_spacing.py +--- +## Input + +```python +a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 +b = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 +c = 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 +d = 1**1 ** 1**1 ** 1**1 ** 1**1 ** 1**1**1 ** 1 ** 1**1 ** 1**1**1**1**1 ** 1 ** 1**1**1 **1**1** 1 ** 1 ** 1 +e = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 +f = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 + +a = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 +b = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 +c = 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 +d = 1.0**1.0 ** 1.0**1.0 ** 1.0**1.0 ** 1.0**1.0 ** 1.0**1.0**1.0 ** 1.0 ** 1.0**1.0 ** 1.0**1.0**1.0 +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,83 +1,83 @@ + a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 + b = ( + 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 +- ** 1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 ++ **1 + ) + c = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 + d = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 + e = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 + f = ( + 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 +- ** 𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 ++ **𨉟 + ) + + a = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 + b = ( + 1.0 +- ** 1.0 +- ** 1.0 +- ** 1.0 +- ** 1.0 +- ** 1.0 +- ** 1.0 +- ** 1.0 +- ** 1.0 +- ** 1.0 +- ** 1.0 +- ** 1.0 +- ** 1.0 +- ** 1.0 +- ** 1.0 +- ** 1.0 +- ** 1.0 +- ** 1.0 ++ **1.0 ++ **1.0 ++ **1.0 ++ **1.0 ++ **1.0 ++ **1.0 ++ **1.0 ++ **1.0 ++ **1.0 ++ **1.0 ++ **1.0 ++ **1.0 ++ **1.0 ++ **1.0 ++ **1.0 ++ **1.0 ++ **1.0 + ) + c = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 + d = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 +``` + +## Ruff Output + +```python +a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 +b = ( + 1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 + **1 +) +c = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 +d = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 +e = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 +f = ( + 𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 + **𨉟 +) + +a = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 +b = ( + 1.0 + **1.0 + **1.0 + **1.0 + **1.0 + **1.0 + **1.0 + **1.0 + **1.0 + **1.0 + **1.0 + **1.0 + **1.0 + **1.0 + **1.0 + **1.0 + **1.0 + **1.0 +) +c = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 +d = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 +``` + +## Black Output + +```python +a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 +b = ( + 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 + ** 1 +) +c = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 +d = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 +e = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 +f = ( + 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 + ** 𨉟 +) + +a = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 +b = ( + 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 + ** 1.0 +) +c = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 +d = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_prefer_rhs_split.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_prefer_rhs_split.py.snap new file mode 100644 index 0000000000000..18b9fa9a06268 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_prefer_rhs_split.py.snap @@ -0,0 +1,457 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_prefer_rhs_split.py +--- +## Input + +```python +first_item, second_item = ( + some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument + ) +) + +some_dict["with_a_long_key"] = ( + some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument + ) +) + +# Make sure it works when the RHS only has one pair of (optional) parens. +first_item, second_item = ( + some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name +) + +some_dict["with_a_long_key"] = ( + some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name +) + +# Make sure chaining assignments work. +first_item, second_item, third_item, forth_item = m["everything"] = ( + some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument + ) +) + +# Make sure when the RHS's first split at the non-optional paren fits, +# we split there instead of the outer RHS optional paren. +first_item, second_item = some_looooooooong_module.some_loooooog_function_name( + first_argument, second_argument, third_argument +) + +( + first_item, + second_item, + third_item, + forth_item, + fifth_item, + last_item_very_loooooong, +) = some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument +) + +( + first_item, + second_item, + third_item, + forth_item, + fifth_item, + last_item_very_loooooong, +) = everything = some_looooong_function_name( + first_argument, second_argument, third_argument +) + + +# Make sure unsplittable type ignore won't be moved. +some_kind_of_table[some_key] = util.some_function( # type: ignore # noqa: E501 + some_arg +).intersection(pk_cols) + +some_kind_of_table[ + some_key +] = lambda obj: obj.some_long_named_method() # type: ignore # noqa: E501 + +some_kind_of_table[ + some_key # type: ignore # noqa: E501 +] = lambda obj: obj.some_long_named_method() + + +# Make when when the left side of assignment plus the opening paren "... = (" is +# exactly line length limit + 1, it won't be split like that. +xxxxxxxxx_yyy_zzzzzzzz[ + xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxxx=1) +] = 1 + + +# Right side of assignment contains un-nested pairs of inner parens. +some_kind_of_instance.some_kind_of_map[a_key] = ( + isinstance(some_var, SomeClass) + and table.something_and_something != table.something_else +) or ( + isinstance(some_other_var, BaseClass) and table.something != table.some_other_thing +) + +# Multiple targets +a = b = ( + ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +) + +a = b = c = d = e = f = g = ( + hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh +) = i = j = ( + kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk +) + +a = ( + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) = c + +a = ( + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) = ( + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +) = ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,29 +1,31 @@ +-first_item, second_item = ( +- some_looooooooong_module.some_looooooooooooooong_function_name( +- first_argument, second_argument, third_argument +- ) ++( ++ first_item, ++ second_item, ++) = some_looooooooong_module.some_looooooooooooooong_function_name( ++ first_argument, second_argument, third_argument + ) + +-some_dict["with_a_long_key"] = ( +- some_looooooooong_module.some_looooooooooooooong_function_name( +- first_argument, second_argument, third_argument +- ) ++some_dict[ ++ "with_a_long_key" ++] = some_looooooooong_module.some_looooooooooooooong_function_name( ++ first_argument, second_argument, third_argument + ) + + # Make sure it works when the RHS only has one pair of (optional) parens. +-first_item, second_item = ( +- some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name +-) ++( ++ first_item, ++ second_item, ++) = some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name + +-some_dict["with_a_long_key"] = ( +- some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name +-) ++some_dict[ ++ "with_a_long_key" ++] = some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name + + # Make sure chaining assignments work. +-first_item, second_item, third_item, forth_item = m["everything"] = ( +- some_looooooooong_module.some_looooooooooooooong_function_name( +- first_argument, second_argument, third_argument +- ) ++first_item, second_item, third_item, forth_item = m[ ++ "everything" ++] = some_looooooooong_module.some_looooooooooooooong_function_name( ++ first_argument, second_argument, third_argument + ) + + # Make sure when the RHS's first split at the non-optional paren fits, +@@ -60,9 +62,7 @@ + some_arg + ).intersection(pk_cols) + +-some_kind_of_table[ +- some_key +-] = lambda obj: obj.some_long_named_method() # type: ignore # noqa: E501 ++some_kind_of_table[some_key] = lambda obj: obj.some_long_named_method() # type: ignore # noqa: E501 + + some_kind_of_table[ + some_key # type: ignore # noqa: E501 +@@ -85,15 +85,29 @@ + ) + + # Multiple targets +-a = b = ( +- ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +-) ++a = ( ++ b ++) = ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc + +-a = b = c = d = e = f = g = ( ++a = ( ++ b ++) = ( ++ c ++) = ( ++ d ++) = ( ++ e ++) = ( ++ f ++) = ( ++ g ++) = ( + hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh +-) = i = j = ( +- kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk +-) ++) = ( ++ i ++) = ( ++ j ++) = kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk + + a = ( + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +``` + +## Ruff Output + +```python +( + first_item, + second_item, +) = some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument +) + +some_dict[ + "with_a_long_key" +] = some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument +) + +# Make sure it works when the RHS only has one pair of (optional) parens. +( + first_item, + second_item, +) = some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name + +some_dict[ + "with_a_long_key" +] = some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name + +# Make sure chaining assignments work. +first_item, second_item, third_item, forth_item = m[ + "everything" +] = some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument +) + +# Make sure when the RHS's first split at the non-optional paren fits, +# we split there instead of the outer RHS optional paren. +first_item, second_item = some_looooooooong_module.some_loooooog_function_name( + first_argument, second_argument, third_argument +) + +( + first_item, + second_item, + third_item, + forth_item, + fifth_item, + last_item_very_loooooong, +) = some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument +) + +( + first_item, + second_item, + third_item, + forth_item, + fifth_item, + last_item_very_loooooong, +) = everything = some_looooong_function_name( + first_argument, second_argument, third_argument +) + + +# Make sure unsplittable type ignore won't be moved. +some_kind_of_table[some_key] = util.some_function( # type: ignore # noqa: E501 + some_arg +).intersection(pk_cols) + +some_kind_of_table[some_key] = lambda obj: obj.some_long_named_method() # type: ignore # noqa: E501 + +some_kind_of_table[ + some_key # type: ignore # noqa: E501 +] = lambda obj: obj.some_long_named_method() + + +# Make when when the left side of assignment plus the opening paren "... = (" is +# exactly line length limit + 1, it won't be split like that. +xxxxxxxxx_yyy_zzzzzzzz[ + xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxxx=1) +] = 1 + + +# Right side of assignment contains un-nested pairs of inner parens. +some_kind_of_instance.some_kind_of_map[a_key] = ( + isinstance(some_var, SomeClass) + and table.something_and_something != table.something_else +) or ( + isinstance(some_other_var, BaseClass) and table.something != table.some_other_thing +) + +# Multiple targets +a = ( + b +) = ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc + +a = ( + b +) = ( + c +) = ( + d +) = ( + e +) = ( + f +) = ( + g +) = ( + hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh +) = ( + i +) = ( + j +) = kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk + +a = ( + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) = c + +a = ( + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) = ( + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +) = ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd +``` + +## Black Output + +```python +first_item, second_item = ( + some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument + ) +) + +some_dict["with_a_long_key"] = ( + some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument + ) +) + +# Make sure it works when the RHS only has one pair of (optional) parens. +first_item, second_item = ( + some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name +) + +some_dict["with_a_long_key"] = ( + some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name +) + +# Make sure chaining assignments work. +first_item, second_item, third_item, forth_item = m["everything"] = ( + some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument + ) +) + +# Make sure when the RHS's first split at the non-optional paren fits, +# we split there instead of the outer RHS optional paren. +first_item, second_item = some_looooooooong_module.some_loooooog_function_name( + first_argument, second_argument, third_argument +) + +( + first_item, + second_item, + third_item, + forth_item, + fifth_item, + last_item_very_loooooong, +) = some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument +) + +( + first_item, + second_item, + third_item, + forth_item, + fifth_item, + last_item_very_loooooong, +) = everything = some_looooong_function_name( + first_argument, second_argument, third_argument +) + + +# Make sure unsplittable type ignore won't be moved. +some_kind_of_table[some_key] = util.some_function( # type: ignore # noqa: E501 + some_arg +).intersection(pk_cols) + +some_kind_of_table[ + some_key +] = lambda obj: obj.some_long_named_method() # type: ignore # noqa: E501 + +some_kind_of_table[ + some_key # type: ignore # noqa: E501 +] = lambda obj: obj.some_long_named_method() + + +# Make when when the left side of assignment plus the opening paren "... = (" is +# exactly line length limit + 1, it won't be split like that. +xxxxxxxxx_yyy_zzzzzzzz[ + xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxxx=1) +] = 1 + + +# Right side of assignment contains un-nested pairs of inner parens. +some_kind_of_instance.some_kind_of_map[a_key] = ( + isinstance(some_var, SomeClass) + and table.something_and_something != table.something_else +) or ( + isinstance(some_other_var, BaseClass) and table.something != table.some_other_thing +) + +# Multiple targets +a = b = ( + ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +) + +a = b = c = d = e = f = g = ( + hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh +) = i = j = ( + kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk +) + +a = ( + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) = c + +a = ( + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) = ( + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +) = ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_return_annotation_brackets_string.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_return_annotation_brackets_string.py.snap new file mode 100644 index 0000000000000..268fcf0eb8487 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_return_annotation_brackets_string.py.snap @@ -0,0 +1,75 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_return_annotation_brackets_string.py +--- +## Input + +```python +# Long string example +def frobnicate() -> "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisIsTrulyUnreasonablyExtremelyLongClassName]": + pass + +# splitting the string breaks if there's any parameters +def frobnicate(a) -> "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisIsTrulyUnreasonablyExtremelyLongClassName]": + pass +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,13 +1,12 @@ + # Long string example + def frobnicate() -> ( +- "ThisIsTrulyUnreasonablyExtremelyLongClassName |" +- " list[ThisIsTrulyUnreasonablyExtremelyLongClassName]" ++ "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisIsTrulyUnreasonablyExtremelyLongClassName]" + ): + pass + + + # splitting the string breaks if there's any parameters + def frobnicate( +- a, ++ a + ) -> "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisIsTrulyUnreasonablyExtremelyLongClassName]": + pass +``` + +## Ruff Output + +```python +# Long string example +def frobnicate() -> ( + "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisIsTrulyUnreasonablyExtremelyLongClassName]" +): + pass + + +# splitting the string breaks if there's any parameters +def frobnicate( + a +) -> "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisIsTrulyUnreasonablyExtremelyLongClassName]": + pass +``` + +## Black Output + +```python +# Long string example +def frobnicate() -> ( + "ThisIsTrulyUnreasonablyExtremelyLongClassName |" + " list[ThisIsTrulyUnreasonablyExtremelyLongClassName]" +): + pass + + +# splitting the string breaks if there's any parameters +def frobnicate( + a, +) -> "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisIsTrulyUnreasonablyExtremelyLongClassName]": + pass +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_single_line_format_skip_with_multiple_comments.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_single_line_format_skip_with_multiple_comments.py.snap new file mode 100644 index 0000000000000..78dc5bad0d197 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_single_line_format_skip_with_multiple_comments.py.snap @@ -0,0 +1,64 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_single_line_format_skip_with_multiple_comments.py +--- +## Input + +```python +foo = 123 # fmt: skip # noqa: E501 # pylint +bar = ( + 123 , + ( 1 + 5 ) # pylint # fmt:skip +) +baz = "a" + "b" # pylint; fmt: skip; noqa: E501 +skip_will_not_work = "a" + "b" # pylint fmt:skip +skip_will_not_work2 = "a" + "b" # some text; fmt:skip happens to be part of it +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,8 +1,8 @@ +-foo = 123 # fmt: skip # noqa: E501 # pylint ++foo = 123 # fmt: skip # noqa: E501 # pylint + bar = ( +- 123 , +- ( 1 + 5 ) # pylint # fmt:skip ++ 123, ++ (1 + 5), # pylint # fmt:skip + ) +-baz = "a" + "b" # pylint; fmt: skip; noqa: E501 ++baz = "a" + "b" # pylint; fmt: skip; noqa: E501 + skip_will_not_work = "a" + "b" # pylint fmt:skip + skip_will_not_work2 = "a" + "b" # some text; fmt:skip happens to be part of it +``` + +## Ruff Output + +```python +foo = 123 # fmt: skip # noqa: E501 # pylint +bar = ( + 123, + (1 + 5), # pylint # fmt:skip +) +baz = "a" + "b" # pylint; fmt: skip; noqa: E501 +skip_will_not_work = "a" + "b" # pylint fmt:skip +skip_will_not_work2 = "a" + "b" # some text; fmt:skip happens to be part of it +``` + +## Black Output + +```python +foo = 123 # fmt: skip # noqa: E501 # pylint +bar = ( + 123 , + ( 1 + 5 ) # pylint # fmt:skip +) +baz = "a" + "b" # pylint; fmt: skip; noqa: E501 +skip_will_not_work = "a" + "b" # pylint fmt:skip +skip_will_not_work2 = "a" + "b" # some text; fmt:skip happens to be part of it +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__raw_docstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__raw_docstring.py.snap new file mode 100644 index 0000000000000..8b27585265471 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__raw_docstring.py.snap @@ -0,0 +1,89 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/raw_docstring.py +--- +## Input + +```python +class C: + + r"""Raw""" + +def f(): + + r"""Raw""" + +class SingleQuotes: + + + r'''Raw''' + +class UpperCaseR: + R"""Raw""" +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -1,4 +1,5 @@ + class C: ++ + r"""Raw""" + + +@@ -7,8 +8,9 @@ + + + class SingleQuotes: +- r'''Raw''' + ++ r"""Raw""" ++ + + class UpperCaseR: + R"""Raw""" +``` + +## Ruff Output + +```python +class C: + + r"""Raw""" + + +def f(): + r"""Raw""" + + +class SingleQuotes: + + r"""Raw""" + + +class UpperCaseR: + R"""Raw""" +``` + +## Black Output + +```python +class C: + r"""Raw""" + + +def f(): + r"""Raw""" + + +class SingleQuotes: + r'''Raw''' + + +class UpperCaseR: + R"""Raw""" +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_await_parens.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__remove_await_parens.py.snap similarity index 90% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_await_parens.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__remove_await_parens.py.snap index 33eabc6fa9b93..284e85189ee12 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_await_parens.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__remove_await_parens.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_await_parens.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_await_parens.py --- ## Input @@ -86,6 +86,15 @@ async def main(): async def main(): await (yield) + +async def main(): + await (a ** b) + await (a[b] ** c) + await (a ** b[c]) + await ((a + b) ** (c + d)) + await (a + b) + await (a[b]) + await (a[b ** c]) ``` ## Black Differences @@ -213,6 +222,16 @@ async def main(): async def main(): await (yield) + + +async def main(): + await (a**b) + await (a[b] ** c) + await (a ** b[c]) + await ((a + b) ** (c + d)) + await (a + b) + await a[b] + await a[b**c] ``` ## Black Output @@ -311,6 +330,16 @@ async def main(): async def main(): await (yield) + + +async def main(): + await (a**b) + await (a[b] ** c) + await (a ** b[c]) + await ((a + b) ** (c + d)) + await (a + b) + await a[b] + await a[b**c] ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_except_parens.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__remove_except_parens.py.snap similarity index 98% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_except_parens.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__remove_except_parens.py.snap index a0459420e5ce4..55f1e953849c3 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_except_parens.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__remove_except_parens.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_except_parens.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_except_parens.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_for_brackets.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__remove_for_brackets.py.snap similarity index 98% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_for_brackets.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__remove_for_brackets.py.snap index 3c2eb7eab684e..5b98ee4d7f870 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_for_brackets.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__remove_for_brackets.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_for_brackets.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_for_brackets.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__return_annotation_brackets.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__return_annotation_brackets.py.snap similarity index 90% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__return_annotation_brackets.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__return_annotation_brackets.py.snap index fd67777f13055..415daad90c786 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__return_annotation_brackets.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__return_annotation_brackets.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/return_annotation_brackets.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/return_annotation_brackets.py --- ## Input @@ -93,6 +93,11 @@ def foo() -> tuple[loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo # Magic trailing comma example def foo() -> tuple[int, int, int,]: return 2 + +# Magic trailing comma example, with params +# this is broken - the trailing comma is transferred to the param list. Fixed in preview +def foo(a,b) -> tuple[int, int, int,]: + return 2 ``` ## Black Differences @@ -122,6 +127,17 @@ def foo() -> tuple[int, int, int,]: return 2 * a +@@ -124,5 +132,9 @@ + # this is broken - the trailing comma is transferred to the param list. Fixed in preview + def foo( + a, b +-) -> tuple[int, int, int,]: ++) -> tuple[ ++ int, ++ int, ++ int, ++]: + return 2 ``` ## Ruff Output @@ -255,6 +271,18 @@ def foo() -> ( ] ): return 2 + + +# Magic trailing comma example, with params +# this is broken - the trailing comma is transferred to the param list. Fixed in preview +def foo( + a, b +) -> tuple[ + int, + int, + int, +]: + return 2 ``` ## Black Output @@ -380,6 +408,14 @@ def foo() -> ( ] ): return 2 + + +# Magic trailing comma example, with params +# this is broken - the trailing comma is transferred to the param list. Fixed in preview +def foo( + a, b +) -> tuple[int, int, int,]: + return 2 ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__stub.pyi.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__stub.pyi.snap new file mode 100644 index 0000000000000..14b894cda7a0d --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__stub.pyi.snap @@ -0,0 +1,288 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/stub.pyi +--- +## Input + +```python +X: int + +def f(): ... + + +class D: + ... + + +class C: + ... + +class B: + this_lack_of_newline_should_be_kept: int + def b(self) -> None: ... + + but_this_newline_should_also_be_kept: int + +class A: + attr: int + attr2: str + + def f(self) -> int: + ... + + def g(self) -> str: ... + + + +def g(): + ... + +def h(): ... + +if sys.version_info >= (3, 8): + class E: + def f(self): ... + class F: + + def f(self): ... + class G: ... + class H: ... +else: + class I: ... + class J: ... + def f(): ... + + class K: + def f(self): ... + def f(): ... + +class Nested: + class dirty: ... + class little: ... + class secret: + def who_has_to_know(self): ... + def verse(self): ... + +class Conditional: + def f(self): ... + if sys.version_info >= (3, 8): + def g(self): ... + else: + def g(self): ... + def h(self): ... + def i(self): ... + if sys.version_info >= (3, 8): + def j(self): ... + def k(self): ... + if sys.version_info >= (3, 8): + class A: ... + class B: ... + class C: + def l(self): ... + def m(self): ... +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -24,31 +24,24 @@ + if sys.version_info >= (3, 8): + class E: + def f(self): ... +- + class F: + def f(self): ... +- + class G: ... + class H: ... +- + else: + class I: ... + class J: ... +- + def f(): ... + + class K: + def f(self): ... +- + def f(): ... + + class Nested: + class dirty: ... + class little: ... +- + class secret: + def who_has_to_know(self): ... +- + def verse(self): ... + + class Conditional: +@@ -57,17 +50,14 @@ + def g(self): ... + else: + def g(self): ... +- + def h(self): ... + def i(self): ... + if sys.version_info >= (3, 8): + def j(self): ... +- + def k(self): ... + if sys.version_info >= (3, 8): + class A: ... + class B: ... +- + class C: + def l(self): ... + def m(self): ... +``` + +## Ruff Output + +```python +X: int + +def f(): ... + +class D: ... +class C: ... + +class B: + this_lack_of_newline_should_be_kept: int + def b(self) -> None: ... + + but_this_newline_should_also_be_kept: int + +class A: + attr: int + attr2: str + + def f(self) -> int: ... + def g(self) -> str: ... + +def g(): ... +def h(): ... + +if sys.version_info >= (3, 8): + class E: + def f(self): ... + class F: + def f(self): ... + class G: ... + class H: ... +else: + class I: ... + class J: ... + def f(): ... + + class K: + def f(self): ... + def f(): ... + +class Nested: + class dirty: ... + class little: ... + class secret: + def who_has_to_know(self): ... + def verse(self): ... + +class Conditional: + def f(self): ... + if sys.version_info >= (3, 8): + def g(self): ... + else: + def g(self): ... + def h(self): ... + def i(self): ... + if sys.version_info >= (3, 8): + def j(self): ... + def k(self): ... + if sys.version_info >= (3, 8): + class A: ... + class B: ... + class C: + def l(self): ... + def m(self): ... +``` + +## Black Output + +```python +X: int + +def f(): ... + +class D: ... +class C: ... + +class B: + this_lack_of_newline_should_be_kept: int + def b(self) -> None: ... + + but_this_newline_should_also_be_kept: int + +class A: + attr: int + attr2: str + + def f(self) -> int: ... + def g(self) -> str: ... + +def g(): ... +def h(): ... + +if sys.version_info >= (3, 8): + class E: + def f(self): ... + + class F: + def f(self): ... + + class G: ... + class H: ... + +else: + class I: ... + class J: ... + + def f(): ... + + class K: + def f(self): ... + + def f(): ... + +class Nested: + class dirty: ... + class little: ... + + class secret: + def who_has_to_know(self): ... + + def verse(self): ... + +class Conditional: + def f(self): ... + if sys.version_info >= (3, 8): + def g(self): ... + else: + def g(self): ... + + def h(self): ... + def i(self): ... + if sys.version_info >= (3, 8): + def j(self): ... + + def k(self): ... + if sys.version_info >= (3, 8): + class A: ... + class B: ... + + class C: + def l(self): ... + def m(self): ... +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__torture.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__torture.py.snap similarity index 99% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__torture.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__torture.py.snap index 6b7ddaa378e9e..f8e78b1ac0e15 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__torture.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__torture.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/torture.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/torture.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__trailing_commas_in_leading_parts.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__trailing_commas_in_leading_parts.py.snap similarity index 98% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__trailing_commas_in_leading_parts.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__trailing_commas_in_leading_parts.py.snap index 8ad0695b0401c..fd4942632e8a3 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__trailing_commas_in_leading_parts.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__trailing_commas_in_leading_parts.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_commas_in_leading_parts.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/trailing_commas_in_leading_parts.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__tupleassign.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__tupleassign.py.snap similarity index 97% rename from crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__tupleassign.py.snap rename to crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__tupleassign.py.snap index 16f034ed48ce3..654b488efe275 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__tupleassign.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__tupleassign.py.snap @@ -1,6 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/tupleassign.py +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/tupleassign.py --- ## Input diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__decorators.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__decorators.py.snap deleted file mode 100644 index 9eaba761d4f44..0000000000000 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__decorators.py.snap +++ /dev/null @@ -1,624 +0,0 @@ ---- -source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/decorators.py ---- -## Input - -```python -# This file doesn't use the standard decomposition. -# Decorator syntax test cases are separated by double # comments. -# Those before the 'output' comment are valid under the old syntax. -# Those after the 'ouput' comment require PEP614 relaxed syntax. -# Do not remove the double # separator before the first test case, it allows -# the comment before the test case to be ignored. - -## - -@decorator -def f(): - ... - -## - -@decorator() -def f(): - ... - -## - -@decorator(arg) -def f(): - ... - -## - -@decorator(kwarg=0) -def f(): - ... - -## - -@decorator(*args) -def f(): - ... - -## - -@decorator(**kwargs) -def f(): - ... - -## - -@decorator(*args, **kwargs) -def f(): - ... - -## - -@decorator(*args, **kwargs,) -def f(): - ... - -## - -@dotted.decorator -def f(): - ... - -## - -@dotted.decorator(arg) -def f(): - ... - -## - -@dotted.decorator(kwarg=0) -def f(): - ... - -## - -@dotted.decorator(*args) -def f(): - ... - -## - -@dotted.decorator(**kwargs) -def f(): - ... - -## - -@dotted.decorator(*args, **kwargs) -def f(): - ... - -## - -@dotted.decorator(*args, **kwargs,) -def f(): - ... - -## - -@double.dotted.decorator -def f(): - ... - -## - -@double.dotted.decorator(arg) -def f(): - ... - -## - -@double.dotted.decorator(kwarg=0) -def f(): - ... - -## - -@double.dotted.decorator(*args) -def f(): - ... - -## - -@double.dotted.decorator(**kwargs) -def f(): - ... - -## - -@double.dotted.decorator(*args, **kwargs) -def f(): - ... - -## - -@double.dotted.decorator(*args, **kwargs,) -def f(): - ... - -## - -@_(sequence["decorator"]) -def f(): - ... - -## - -@eval("sequence['decorator']") -def f(): - ... -``` - -## Black Differences - -```diff ---- Black -+++ Ruff -@@ -1,29 +1,206 @@ -+# This file doesn't use the standard decomposition. -+# Decorator syntax test cases are separated by double # comments. -+# Those before the 'output' comment are valid under the old syntax. -+# Those after the 'ouput' comment require PEP614 relaxed syntax. -+# Do not remove the double # separator before the first test case, it allows -+# the comment before the test case to be ignored. -+ -+## -+ -+ -+@decorator -+def f(): -+ ... -+ -+ -+## -+ -+ -+@decorator() -+def f(): -+ ... -+ -+ -+## -+ -+ -+@decorator(arg) -+def f(): -+ ... -+ -+ -+## -+ -+ -+@decorator(kwarg=0) -+def f(): -+ ... -+ -+ -+## -+ -+ -+@decorator(*args) -+def f(): -+ ... -+ -+ - ## - --@decorator()() -+ -+@decorator(**kwargs) - def f(): - ... - -+ - ## - --@(decorator) -+ -+@decorator(*args, **kwargs) - def f(): - ... - -+ - ## - --@sequence["decorator"] -+ -+@decorator( -+ *args, -+ **kwargs, -+) - def f(): - ... - -+ - ## - --@decorator[List[str]] -+ -+@dotted.decorator - def f(): - ... - -+ - ## - --@var := decorator -+ -+@dotted.decorator(arg) -+def f(): -+ ... -+ -+ -+## -+ -+ -+@dotted.decorator(kwarg=0) -+def f(): -+ ... -+ -+ -+## -+ -+ -+@dotted.decorator(*args) -+def f(): -+ ... -+ -+ -+## -+ -+ -+@dotted.decorator(**kwargs) -+def f(): -+ ... -+ -+ -+## -+ -+ -+@dotted.decorator(*args, **kwargs) -+def f(): -+ ... -+ -+ -+## -+ -+ -+@dotted.decorator( -+ *args, -+ **kwargs, -+) -+def f(): -+ ... -+ -+ -+## -+ -+ -+@double.dotted.decorator -+def f(): -+ ... -+ -+ -+## -+ -+ -+@double.dotted.decorator(arg) -+def f(): -+ ... -+ -+ -+## -+ -+ -+@double.dotted.decorator(kwarg=0) -+def f(): -+ ... -+ -+ -+## -+ -+ -+@double.dotted.decorator(*args) -+def f(): -+ ... -+ -+ -+## -+ -+ -+@double.dotted.decorator(**kwargs) -+def f(): -+ ... -+ -+ -+## -+ -+ -+@double.dotted.decorator(*args, **kwargs) -+def f(): -+ ... -+ -+ -+## -+ -+ -+@double.dotted.decorator( -+ *args, -+ **kwargs, -+) -+def f(): -+ ... -+ -+ -+## -+ -+ -+@_(sequence["decorator"]) -+def f(): -+ ... -+ -+ -+## -+ -+ -+@eval("sequence['decorator']") - def f(): - ... -``` - -## Ruff Output - -```python -# This file doesn't use the standard decomposition. -# Decorator syntax test cases are separated by double # comments. -# Those before the 'output' comment are valid under the old syntax. -# Those after the 'ouput' comment require PEP614 relaxed syntax. -# Do not remove the double # separator before the first test case, it allows -# the comment before the test case to be ignored. - -## - - -@decorator -def f(): - ... - - -## - - -@decorator() -def f(): - ... - - -## - - -@decorator(arg) -def f(): - ... - - -## - - -@decorator(kwarg=0) -def f(): - ... - - -## - - -@decorator(*args) -def f(): - ... - - -## - - -@decorator(**kwargs) -def f(): - ... - - -## - - -@decorator(*args, **kwargs) -def f(): - ... - - -## - - -@decorator( - *args, - **kwargs, -) -def f(): - ... - - -## - - -@dotted.decorator -def f(): - ... - - -## - - -@dotted.decorator(arg) -def f(): - ... - - -## - - -@dotted.decorator(kwarg=0) -def f(): - ... - - -## - - -@dotted.decorator(*args) -def f(): - ... - - -## - - -@dotted.decorator(**kwargs) -def f(): - ... - - -## - - -@dotted.decorator(*args, **kwargs) -def f(): - ... - - -## - - -@dotted.decorator( - *args, - **kwargs, -) -def f(): - ... - - -## - - -@double.dotted.decorator -def f(): - ... - - -## - - -@double.dotted.decorator(arg) -def f(): - ... - - -## - - -@double.dotted.decorator(kwarg=0) -def f(): - ... - - -## - - -@double.dotted.decorator(*args) -def f(): - ... - - -## - - -@double.dotted.decorator(**kwargs) -def f(): - ... - - -## - - -@double.dotted.decorator(*args, **kwargs) -def f(): - ... - - -## - - -@double.dotted.decorator( - *args, - **kwargs, -) -def f(): - ... - - -## - - -@_(sequence["decorator"]) -def f(): - ... - - -## - - -@eval("sequence['decorator']") -def f(): - ... -``` - -## Black Output - -```python -## - -@decorator()() -def f(): - ... - -## - -@(decorator) -def f(): - ... - -## - -@sequence["decorator"] -def f(): - ... - -## - -@decorator[List[str]] -def f(): - ... - -## - -@var := decorator -def f(): - ... -``` - - diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__force_pyi.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__force_pyi.py.snap index 4eeadc7a82b9d..c2d79524f4838 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__force_pyi.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__force_pyi.py.snap @@ -5,7 +5,6 @@ input_file: crates/ruff_python_formatter/resources/test/fixtures/black/miscellan ## Input ```python -# flags: --pyi from typing import Union @bird @@ -43,8 +42,7 @@ def eggs() -> Union[str, int]: ... ```diff --- Black +++ Ruff -@@ -1,32 +1,59 @@ -+# flags: --pyi +@@ -1,32 +1,58 @@ from typing import Union + @@ -69,13 +67,13 @@ def eggs() -> Union[str, int]: ... - def BMethod(self, arg: List[str]) -> None: ... + def BMethod(self, arg: List[str]) -> None: + ... ++ ++ ++class C: ++ ... -class C: ... -+class C: -+ ... -+ -+ @hmm -class D: ... +class D: @@ -120,7 +118,6 @@ def eggs() -> Union[str, int]: ... ## Ruff Output ```python -# flags: --pyi from typing import Union diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__force_pyi.pyi.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__force_pyi.pyi.snap new file mode 100644 index 0000000000000..2eb67a391b12b --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@miscellaneous__force_pyi.pyi.snap @@ -0,0 +1,128 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/miscellaneous/force_pyi.pyi +--- +## Input + +```python +from typing import Union + +@bird +def zoo(): ... + +class A: ... +@bar +class B: + def BMethod(self) -> None: ... + @overload + def BMethod(self, arg : List[str]) -> None: ... + +class C: ... +@hmm +class D: ... +class E: ... + +@baz +def foo() -> None: + ... + +class F (A , C): ... +def spam() -> None: ... + +@overload +def spam(arg: str) -> str: ... + +var : int = 1 + +def eggs() -> Union[str, int]: ... +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -15,7 +15,6 @@ + + @hmm + class D: ... +- + class E: ... + + @baz +``` + +## Ruff Output + +```python +from typing import Union + +@bird +def zoo(): ... + +class A: ... + +@bar +class B: + def BMethod(self) -> None: ... + @overload + def BMethod(self, arg: List[str]) -> None: ... + +class C: ... + +@hmm +class D: ... +class E: ... + +@baz +def foo() -> None: ... + +class F(A, C): ... + +def spam() -> None: ... +@overload +def spam(arg: str) -> str: ... + +var: int = 1 + +def eggs() -> Union[str, int]: ... +``` + +## Black Output + +```python +from typing import Union + +@bird +def zoo(): ... + +class A: ... + +@bar +class B: + def BMethod(self) -> None: ... + @overload + def BMethod(self, arg: List[str]) -> None: ... + +class C: ... + +@hmm +class D: ... + +class E: ... + +@baz +def foo() -> None: ... + +class F(A, C): ... + +def spam() -> None: ... +@overload +def spam(arg: str) -> str: ... + +var: int = 1 + +def eggs() -> Union[str, int]: ... +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_extras.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_extras.py.snap deleted file mode 100644 index 865bb18e4453a..0000000000000 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_extras.py.snap +++ /dev/null @@ -1,420 +0,0 @@ ---- -source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/py_310/pattern_matching_extras.py ---- -## Input - -```python -import match - -match something: - case [a as b]: - print(b) - case [a as b, c, d, e as f]: - print(f) - case Point(a as b): - print(b) - case Point(int() as x, int() as y): - print(x, y) - - -match = 1 -case: int = re.match(something) - -match re.match(case): - case type("match", match): - pass - case match: - pass - - -def func(match: case, case: match) -> case: - match Something(): - case func(match, case): - ... - case another: - ... - - -match maybe, multiple: - case perhaps, 5: - pass - case perhaps, 6,: - pass - - -match more := (than, one), indeed,: - case _, (5, 6): - pass - case [[5], (6)], [7],: - pass - case _: - pass - - -match a, *b, c: - case [*_]: - assert "seq" == _ - case {}: - assert "map" == b - - -match match( - case, - match( - match, case, match, looooooooooooooooooooooooooooooooooooong, match, case, match - ), - case, -): - case case( - match=case, - case=re.match( - loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong - ), - ): - pass - - case [a as match]: - pass - - case case: - pass - - -match match: - case case: - pass - - -match a, *b(), c: - case d, *f, g: - pass - - -match something: - case { - "key": key as key_1, - "password": PASS.ONE | PASS.TWO | PASS.THREE as password, - }: - pass - case {"maybe": something(complicated as this) as that}: - pass - - -match something: - case 1 as a: - pass - - case 2 as b, 3 as c: - pass - - case 4 as d, (5 as e), (6 | 7 as g), *h: - pass - - -match bar1: - case Foo(aa=Callable() as aa, bb=int()): - print(bar1.aa, bar1.bb) - case _: - print("no match", "\n") - - -match bar1: - case Foo( - normal=x, perhaps=[list, {"x": d, "y": 1.0}] as y, otherwise=something, q=t as u - ): - pass -``` - -## Black Differences - -```diff ---- Black -+++ Ruff -@@ -32,14 +32,23 @@ - match maybe, multiple: - case perhaps, 5: - pass -- case perhaps, 6,: -+ case ( -+ perhaps, -+ 6, -+ ): - pass - - --match more := (than, one), indeed,: -+match ( -+ more := (than, one), -+ indeed, -+): - case _, (5, 6): - pass -- case [[5], (6)], [7],: -+ case [ -+ [[5], (6)], -+ [7], -+ ]: - pass - case _: - pass -``` - -## Ruff Output - -```python -import match - -match something: - case [a as b]: - print(b) - case [a as b, c, d, e as f]: - print(f) - case Point(a as b): - print(b) - case Point(int() as x, int() as y): - print(x, y) - - -match = 1 -case: int = re.match(something) - -match re.match(case): - case type("match", match): - pass - case match: - pass - - -def func(match: case, case: match) -> case: - match Something(): - case func(match, case): - ... - case another: - ... - - -match maybe, multiple: - case perhaps, 5: - pass - case ( - perhaps, - 6, - ): - pass - - -match ( - more := (than, one), - indeed, -): - case _, (5, 6): - pass - case [ - [[5], (6)], - [7], - ]: - pass - case _: - pass - - -match a, *b, c: - case [*_]: - assert "seq" == _ - case {}: - assert "map" == b - - -match match( - case, - match( - match, case, match, looooooooooooooooooooooooooooooooooooong, match, case, match - ), - case, -): - case case( - match=case, - case=re.match( - loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong - ), - ): - pass - - case [a as match]: - pass - - case case: - pass - - -match match: - case case: - pass - - -match a, *b(), c: - case d, *f, g: - pass - - -match something: - case { - "key": key as key_1, - "password": PASS.ONE | PASS.TWO | PASS.THREE as password, - }: - pass - case {"maybe": something(complicated as this) as that}: - pass - - -match something: - case 1 as a: - pass - - case 2 as b, 3 as c: - pass - - case 4 as d, (5 as e), (6 | 7 as g), *h: - pass - - -match bar1: - case Foo(aa=Callable() as aa, bb=int()): - print(bar1.aa, bar1.bb) - case _: - print("no match", "\n") - - -match bar1: - case Foo( - normal=x, perhaps=[list, {"x": d, "y": 1.0}] as y, otherwise=something, q=t as u - ): - pass -``` - -## Black Output - -```python -import match - -match something: - case [a as b]: - print(b) - case [a as b, c, d, e as f]: - print(f) - case Point(a as b): - print(b) - case Point(int() as x, int() as y): - print(x, y) - - -match = 1 -case: int = re.match(something) - -match re.match(case): - case type("match", match): - pass - case match: - pass - - -def func(match: case, case: match) -> case: - match Something(): - case func(match, case): - ... - case another: - ... - - -match maybe, multiple: - case perhaps, 5: - pass - case perhaps, 6,: - pass - - -match more := (than, one), indeed,: - case _, (5, 6): - pass - case [[5], (6)], [7],: - pass - case _: - pass - - -match a, *b, c: - case [*_]: - assert "seq" == _ - case {}: - assert "map" == b - - -match match( - case, - match( - match, case, match, looooooooooooooooooooooooooooooooooooong, match, case, match - ), - case, -): - case case( - match=case, - case=re.match( - loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong - ), - ): - pass - - case [a as match]: - pass - - case case: - pass - - -match match: - case case: - pass - - -match a, *b(), c: - case d, *f, g: - pass - - -match something: - case { - "key": key as key_1, - "password": PASS.ONE | PASS.TWO | PASS.THREE as password, - }: - pass - case {"maybe": something(complicated as this) as that}: - pass - - -match something: - case 1 as a: - pass - - case 2 as b, 3 as c: - pass - - case 4 as d, (5 as e), (6 | 7 as g), *h: - pass - - -match bar1: - case Foo(aa=Callable() as aa, bb=int()): - print(bar1.aa, bar1.bb) - case _: - print("no match", "\n") - - -match bar1: - case Foo( - normal=x, perhaps=[list, {"x": d, "y": 1.0}] as y, otherwise=something, q=t as u - ): - pass -``` - - diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__docstring_preview.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__docstring_preview.py.snap deleted file mode 100644 index afb73efb11279..0000000000000 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__docstring_preview.py.snap +++ /dev/null @@ -1,184 +0,0 @@ ---- -source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring_preview.py ---- -## Input - -```python -def docstring_almost_at_line_limit(): - """long docstring................................................................. - """ - - -def docstring_almost_at_line_limit_with_prefix(): - f"""long docstring................................................................ - """ - - -def mulitline_docstring_almost_at_line_limit(): - """long docstring................................................................. - - .................................................................................. - """ - - -def mulitline_docstring_almost_at_line_limit_with_prefix(): - f"""long docstring................................................................ - - .................................................................................. - """ - - -def docstring_at_line_limit(): - """long docstring................................................................""" - - -def docstring_at_line_limit_with_prefix(): - f"""long docstring...............................................................""" - - -def multiline_docstring_at_line_limit(): - """first line----------------------------------------------------------------------- - - second line----------------------------------------------------------------------""" - - -def multiline_docstring_at_line_limit_with_prefix(): - f"""first line---------------------------------------------------------------------- - - second line----------------------------------------------------------------------""" - - -def single_quote_docstring_over_line_limit(): - "We do not want to put the closing quote on a new line as that is invalid (see GH-3141)." - - -def single_quote_docstring_over_line_limit2(): - 'We do not want to put the closing quote on a new line as that is invalid (see GH-3141).' -``` - -## Black Differences - -```diff ---- Black -+++ Ruff -@@ -3,7 +3,8 @@ - - - def docstring_almost_at_line_limit_with_prefix(): -- f"""long docstring................................................................""" -+ f"""long docstring................................................................ -+ """ - - - def mulitline_docstring_almost_at_line_limit(): -``` - -## Ruff Output - -```python -def docstring_almost_at_line_limit(): - """long docstring.................................................................""" - - -def docstring_almost_at_line_limit_with_prefix(): - f"""long docstring................................................................ - """ - - -def mulitline_docstring_almost_at_line_limit(): - """long docstring................................................................. - - .................................................................................. - """ - - -def mulitline_docstring_almost_at_line_limit_with_prefix(): - f"""long docstring................................................................ - - .................................................................................. - """ - - -def docstring_at_line_limit(): - """long docstring................................................................""" - - -def docstring_at_line_limit_with_prefix(): - f"""long docstring...............................................................""" - - -def multiline_docstring_at_line_limit(): - """first line----------------------------------------------------------------------- - - second line----------------------------------------------------------------------""" - - -def multiline_docstring_at_line_limit_with_prefix(): - f"""first line---------------------------------------------------------------------- - - second line----------------------------------------------------------------------""" - - -def single_quote_docstring_over_line_limit(): - "We do not want to put the closing quote on a new line as that is invalid (see GH-3141)." - - -def single_quote_docstring_over_line_limit2(): - "We do not want to put the closing quote on a new line as that is invalid (see GH-3141)." -``` - -## Black Output - -```python -def docstring_almost_at_line_limit(): - """long docstring.................................................................""" - - -def docstring_almost_at_line_limit_with_prefix(): - f"""long docstring................................................................""" - - -def mulitline_docstring_almost_at_line_limit(): - """long docstring................................................................. - - .................................................................................. - """ - - -def mulitline_docstring_almost_at_line_limit_with_prefix(): - f"""long docstring................................................................ - - .................................................................................. - """ - - -def docstring_at_line_limit(): - """long docstring................................................................""" - - -def docstring_at_line_limit_with_prefix(): - f"""long docstring...............................................................""" - - -def multiline_docstring_at_line_limit(): - """first line----------------------------------------------------------------------- - - second line----------------------------------------------------------------------""" - - -def multiline_docstring_at_line_limit_with_prefix(): - f"""first line---------------------------------------------------------------------- - - second line----------------------------------------------------------------------""" - - -def single_quote_docstring_over_line_limit(): - "We do not want to put the closing quote on a new line as that is invalid (see GH-3141)." - - -def single_quote_docstring_over_line_limit2(): - "We do not want to put the closing quote on a new line as that is invalid (see GH-3141)." -``` - - From 774c77adae24ea26e82d2856d08ecaa83fa7cf33 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 29 Nov 2023 16:11:04 -0800 Subject: [PATCH 060/197] Avoid off-by-one error in with-item named expressions (#8915) ## Summary Given `with (a := b): pass`, we truncate the `WithItem` range by one on both sides such that the parentheses are part of the statement, rather than the item. However, for `with (a := b) as x: pass`, we want to avoid this trick. Closes https://github.com/astral-sh/ruff/issues/8913. --- crates/ruff_python_parser/src/python.lalrpop | 2 +- crates/ruff_python_parser/src/python.rs | 4 ++-- ...n_parser__parser__tests__parenthesized_with_statement.snap | 2 +- .../ruff_python_parser__parser__tests__with_statement.snap | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/ruff_python_parser/src/python.lalrpop b/crates/ruff_python_parser/src/python.lalrpop index 67c49a7b644ab..98ac90fc73e65 100644 --- a/crates/ruff_python_parser/src/python.lalrpop +++ b/crates/ruff_python_parser/src/python.lalrpop @@ -1026,7 +1026,7 @@ WithItems: Vec = { // ``` // In this case, the `(` and `)` are part of the `with` statement. // The same applies to `yield` and `yield from`. - let item = if matches!(item.context_expr, ast::Expr::NamedExpr(_) | ast::Expr::Yield(_) | ast::Expr::YieldFrom(_)) { + let item = if item.optional_vars.is_none() && matches!(item.context_expr, ast::Expr::NamedExpr(_) | ast::Expr::Yield(_) | ast::Expr::YieldFrom(_)) { ast::WithItem { range: item.range().add_start(TextSize::new(1)).sub_end(TextSize::new(1)), context_expr: item.context_expr, diff --git a/crates/ruff_python_parser/src/python.rs b/crates/ruff_python_parser/src/python.rs index 3452ede4e59d8..3b2174bc69456 100644 --- a/crates/ruff_python_parser/src/python.rs +++ b/crates/ruff_python_parser/src/python.rs @@ -1,5 +1,5 @@ // auto-generated: "lalrpop 0.20.0" -// sha3: e999c9c9ca8fe5a29655244aa995b8cf4e639f0bda95099d8f2a395bc06b6408 +// sha3: c7c0b9368fa05f7d2fc1d06a665ff4232555f276a1d9569afdbc86d0905b3a2a use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; use ruff_python_ast::{self as ast, Int, IpyEscapeKind}; use crate::{ @@ -35374,7 +35374,7 @@ fn __action159< // ``` // In this case, the `(` and `)` are part of the `with` statement. // The same applies to `yield` and `yield from`. - let item = if matches!(item.context_expr, ast::Expr::NamedExpr(_) | ast::Expr::Yield(_) | ast::Expr::YieldFrom(_)) { + let item = if item.optional_vars.is_none() && matches!(item.context_expr, ast::Expr::NamedExpr(_) | ast::Expr::Yield(_) | ast::Expr::YieldFrom(_)) { ast::WithItem { range: item.range().add_start(TextSize::new(1)).sub_end(TextSize::new(1)), context_expr: item.context_expr, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parenthesized_with_statement.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parenthesized_with_statement.snap index 8707ba33d6e21..0e703191724d8 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parenthesized_with_statement.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parenthesized_with_statement.snap @@ -347,7 +347,7 @@ expression: "parse_suite(source, \"\").unwrap()" is_async: false, items: [ WithItem { - range: 184..195, + range: 183..196, context_expr: NamedExpr( ExprNamedExpr { range: 184..190, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__with_statement.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__with_statement.snap index de4e64d775aa1..dec15e10e878d 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__with_statement.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__with_statement.snap @@ -782,7 +782,7 @@ expression: "parse_suite(source, \"\").unwrap()" is_async: false, items: [ WithItem { - range: 382..393, + range: 381..394, context_expr: NamedExpr( ExprNamedExpr { range: 382..388, From c324cb62020e54931f6514265402b10fe99ef847 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 29 Nov 2023 17:43:40 -0800 Subject: [PATCH 061/197] [`pep8-naming`] Allow Django model loads in `non-lowercase-variable-in-function` (`N806`) (#8917) ## Summary Allows assignments of the form, e.g., `Attachment = apps.get_model("zerver", "Attachment")`, for better compatibility with Django. Closes https://github.com/astral-sh/ruff/issues/7675. ## Test Plan `cargo test` --- .../test/fixtures/pep8_naming/N806.py | 14 ++++- .../src/checkers/ast/analyze/expression.rs | 16 +---- .../src/rules/pep8_naming/helpers.rs | 63 +++++++++++++++++++ .../non_lowercase_variable_in_function.rs | 10 +++ ...les__pep8_naming__tests__N806_N806.py.snap | 18 ++++++ 5 files changed, 107 insertions(+), 14 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py b/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py index e509a27e12bc5..bbaf2b785fc90 100644 --- a/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py +++ b/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py @@ -1,6 +1,6 @@ import collections from collections import namedtuple -from typing import TypeAlias, TypeVar, NewType, NamedTuple, TypedDict +from typing import Type, TypeAlias, TypeVar, NewType, NamedTuple, TypedDict GLOBAL: str = "foo" @@ -40,3 +40,15 @@ def loop_assign(): global CURRENT_PORT for CURRENT_PORT in range(5): pass + + +def model_assign() -> None: + Bad = apps.get_model("zerver", "Stream") # N806 + Attachment = apps.get_model("zerver", "Attachment") # OK + Recipient = apps.get_model("zerver", model_name="Recipient") # OK + Address: Type = apps.get_model("zerver", "Address") # OK + + from django.utils.module_loading import import_string + + Bad = import_string("django.core.exceptions.ValidationError") # N806 + ValidationError = import_string("django.core.exceptions.ValidationError") # OK diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 7a158449bfcc1..f0e2cdb16bf73 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -205,19 +205,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { ExprContext::Store => { if checker.enabled(Rule::NonLowercaseVariableInFunction) { if checker.semantic.current_scope().kind.is_function() { - // Ignore globals. - if !checker - .semantic - .current_scope() - .get(id) - .is_some_and(|binding_id| { - checker.semantic.binding(binding_id).is_global() - }) - { - pep8_naming::rules::non_lowercase_variable_in_function( - checker, expr, id, - ); - } + pep8_naming::rules::non_lowercase_variable_in_function( + checker, expr, id, + ); } } if checker.enabled(Rule::MixedCaseVariableInClassScope) { diff --git a/crates/ruff_linter/src/rules/pep8_naming/helpers.rs b/crates/ruff_linter/src/rules/pep8_naming/helpers.rs index 24fcb6d92dbb3..fc8f6568af827 100644 --- a/crates/ruff_linter/src/rules/pep8_naming/helpers.rs +++ b/crates/ruff_linter/src/rules/pep8_naming/helpers.rs @@ -1,4 +1,5 @@ use itertools::Itertools; +use ruff_python_ast::call_path::collect_call_path; use ruff_python_ast::{self as ast, Arguments, Expr, Stmt}; use ruff_python_semantic::SemanticModel; @@ -72,6 +73,7 @@ pub(super) fn is_type_alias_assignment(stmt: &Stmt, semantic: &SemanticModel) -> } } +/// Returns `true` if the statement is an assignment to a `TypedDict`. pub(super) fn is_typed_dict_class(arguments: Option<&Arguments>, semantic: &SemanticModel) -> bool { arguments.is_some_and(|arguments| { arguments @@ -81,6 +83,67 @@ pub(super) fn is_typed_dict_class(arguments: Option<&Arguments>, semantic: &Sema }) } +/// Returns `true` if a statement appears to be a dynamic import of a Django model. +/// +/// For example, in Django, it's common to use `get_model` to access a model dynamically, as in: +/// ```python +/// def migrate_existing_attachment_data( +/// apps: StateApps, schema_editor: BaseDatabaseSchemaEditor +/// ) -> None: +/// Attachment = apps.get_model("zerver", "Attachment") +/// ``` +pub(super) fn is_django_model_import(name: &str, stmt: &Stmt, semantic: &SemanticModel) -> bool { + fn match_model_import(name: &str, expr: &Expr, semantic: &SemanticModel) -> bool { + let Expr::Call(ast::ExprCall { + func, arguments, .. + }) = expr + else { + return false; + }; + + // Match against, e.g., `apps.get_model("zerver", "Attachment")`. + if let Some(call_path) = collect_call_path(func.as_ref()) { + if matches!(call_path.as_slice(), [.., "get_model"]) { + if let Some(argument) = + arguments.find_argument("model_name", arguments.args.len() - 1) + { + if let Some(string_literal) = argument.as_string_literal_expr() { + return string_literal.value.to_str() == name; + } + } + } + } + + // Match against, e.g., `import_string("zerver.models.Attachment")`. + if let Some(call_path) = semantic.resolve_call_path(func.as_ref()) { + if matches!( + call_path.as_slice(), + ["django", "utils", "module_loading", "import_string"] + ) { + if let Some(argument) = arguments.find_argument("dotted_path", 0) { + if let Some(string_literal) = argument.as_string_literal_expr() { + if let Some((.., model)) = string_literal.value.to_str().rsplit_once('.') { + return model == name; + } + } + } + } + } + + false + } + + match stmt { + Stmt::AnnAssign(ast::StmtAnnAssign { + value: Some(value), .. + }) => match_model_import(name, value.as_ref(), semantic), + Stmt::Assign(ast::StmtAssign { value, .. }) => { + match_model_import(name, value.as_ref(), semantic) + } + _ => false, + } +} + #[cfg(test)] mod tests { use super::{is_acronym, is_camelcase, is_mixed_case}; diff --git a/crates/ruff_linter/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs b/crates/ruff_linter/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs index 59df8bf60eeae..3e073f343c9c9 100644 --- a/crates/ruff_linter/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs +++ b/crates/ruff_linter/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs @@ -53,6 +53,15 @@ impl Violation for NonLowercaseVariableInFunction { /// N806 pub(crate) fn non_lowercase_variable_in_function(checker: &mut Checker, expr: &Expr, name: &str) { + // Ignore globals. + if checker + .semantic() + .lookup_symbol(name) + .is_some_and(|id| checker.semantic().binding(id).is_global()) + { + return; + } + if checker .settings .pep8_naming @@ -72,6 +81,7 @@ pub(crate) fn non_lowercase_variable_in_function(checker: &mut Checker, expr: &E || helpers::is_typed_dict_assignment(parent, checker.semantic()) || helpers::is_type_var_assignment(parent, checker.semantic()) || helpers::is_type_alias_assignment(parent, checker.semantic()) + || helpers::is_django_model_import(name, parent, checker.semantic()) { return; } diff --git a/crates/ruff_linter/src/rules/pep8_naming/snapshots/ruff_linter__rules__pep8_naming__tests__N806_N806.py.snap b/crates/ruff_linter/src/rules/pep8_naming/snapshots/ruff_linter__rules__pep8_naming__tests__N806_N806.py.snap index 16718b5a9938b..e572eecccb0ad 100644 --- a/crates/ruff_linter/src/rules/pep8_naming/snapshots/ruff_linter__rules__pep8_naming__tests__N806_N806.py.snap +++ b/crates/ruff_linter/src/rules/pep8_naming/snapshots/ruff_linter__rules__pep8_naming__tests__N806_N806.py.snap @@ -20,4 +20,22 @@ N806.py:13:5: N806 Variable `CONSTANT` in function should be lowercase 14 | _ = 0 | +N806.py:46:5: N806 Variable `Bad` in function should be lowercase + | +45 | def model_assign() -> None: +46 | Bad = apps.get_model("zerver", "Stream") # N806 + | ^^^ N806 +47 | Attachment = apps.get_model("zerver", "Attachment") # OK +48 | Recipient = apps.get_model("zerver", model_name="Recipient") # OK + | + +N806.py:53:5: N806 Variable `Bad` in function should be lowercase + | +51 | from django.utils.module_loading import import_string +52 | +53 | Bad = import_string("django.core.exceptions.ValidationError") # N806 + | ^^^ N806 +54 | ValidationError = import_string("django.core.exceptions.ValidationError") # OK + | + From e8da95d09c231ef750d48c97aa71881df9e1cc02 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 29 Nov 2023 17:51:23 -0800 Subject: [PATCH 062/197] Document fix safety for flake8-comprehensions and some pyupgrade rules (#8918) See: https://github.com/astral-sh/ruff/issues/7993. --- .../rules/unnecessary_call_around_sorted.rs | 8 +++++++ .../rules/unnecessary_collection_call.rs | 4 ++++ .../rules/unnecessary_comprehension.rs | 5 +++++ .../unnecessary_comprehension_any_all.rs | 5 +++++ .../unnecessary_double_cast_or_process.rs | 4 ++++ .../rules/unnecessary_generator_dict.rs | 4 ++++ .../rules/unnecessary_generator_list.rs | 4 ++++ .../rules/unnecessary_generator_set.rs | 4 ++++ .../rules/unnecessary_list_call.rs | 4 ++++ .../unnecessary_list_comprehension_dict.rs | 4 ++++ .../unnecessary_list_comprehension_set.rs | 4 ++++ .../rules/unnecessary_literal_dict.rs | 4 ++++ .../rules/unnecessary_literal_set.rs | 4 ++++ .../unnecessary_literal_within_dict_call.rs | 4 ++++ .../unnecessary_literal_within_list_call.rs | 4 ++++ .../unnecessary_literal_within_tuple_call.rs | 4 ++++ .../rules/unnecessary_map.rs | 22 +++++++++++-------- .../pyupgrade/rules/use_pep604_annotation.rs | 5 +++++ 18 files changed, 88 insertions(+), 9 deletions(-) diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_call_around_sorted.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_call_around_sorted.rs index a9191e1495e34..36d4bc1148673 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_call_around_sorted.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_call_around_sorted.rs @@ -30,6 +30,14 @@ use crate::rules::flake8_comprehensions::fixes; /// ```python /// sorted(iterable, reverse=True) /// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as `reversed` and `reverse=True` will +/// yield different results in the event of custom sort keys or equality +/// functions. Specifically, `reversed` will reverse the order of the +/// collection, while `sorted` with `reverse=True` will perform a stable +/// reverse sort, which will preserve the order of elements that compare as +/// equal. #[violation] pub struct UnnecessaryCallAroundSorted { func: String, diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_collection_call.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_collection_call.rs index 8d40f83506666..6e3eb4f4a3a62 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_collection_call.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_collection_call.rs @@ -32,6 +32,10 @@ use crate::rules::flake8_comprehensions::settings::Settings; /// [] /// () /// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the call. In most cases, though, comments will be preserved. #[violation] pub struct UnnecessaryCollectionCall { obj_type: String, diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_comprehension.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_comprehension.rs index f11aa25b63a4e..8cf084a067b6f 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_comprehension.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_comprehension.rs @@ -29,6 +29,11 @@ use crate::rules::flake8_comprehensions::fixes; /// list(iterable) /// set(iterable) /// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the comprehension. In most cases, though, comments will be +/// preserved. #[violation] pub struct UnnecessaryComprehension { obj_type: String, diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_comprehension_any_all.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_comprehension_any_all.rs index 9527082ae8ebf..07fbdd9a07e91 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_comprehension_any_all.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_comprehension_any_all.rs @@ -40,6 +40,11 @@ use crate::rules::flake8_comprehensions::fixes; /// any(x.id for x in bar) /// all(x.id for x in bar) /// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the comprehension. In most cases, though, comments will be +/// preserved. #[violation] pub struct UnnecessaryComprehensionAnyAll; diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_double_cast_or_process.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_double_cast_or_process.rs index 5bdeca9a5725b..10ee56f908e9a 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_double_cast_or_process.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_double_cast_or_process.rs @@ -43,6 +43,10 @@ use crate::rules::flake8_comprehensions::fixes; /// - Instead of `sorted(tuple(iterable))`, use `sorted(iterable)`. /// - Instead of `sorted(sorted(iterable))`, use `sorted(iterable)`. /// - Instead of `sorted(reversed(iterable))`, use `sorted(iterable)`. +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the call. In most cases, though, comments will be preserved. #[violation] pub struct UnnecessaryDoubleCastOrProcess { inner: String, diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_dict.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_dict.rs index e9be9ad143996..30a52354f380d 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_dict.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_dict.rs @@ -27,6 +27,10 @@ use super::helpers; /// ```python /// {x: f(x) for x in foo} /// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the call. In most cases, though, comments will be preserved. #[violation] pub struct UnnecessaryGeneratorDict; diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_list.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_list.rs index 06648ef7b52b7..526fe4970a1e7 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_list.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_list.rs @@ -28,6 +28,10 @@ use super::helpers; /// ```python /// [f(x) for x in foo] /// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the call. In most cases, though, comments will be preserved. #[violation] pub struct UnnecessaryGeneratorList; diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_set.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_set.rs index 124a838dd23a7..f2cdbf86453a0 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_set.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_generator_set.rs @@ -28,6 +28,10 @@ use super::helpers; /// ```python /// {f(x) for x in foo} /// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the call. In most cases, though, comments will be preserved. #[violation] pub struct UnnecessaryGeneratorSet; diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_call.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_call.rs index 587b2754c7708..c01bf23ad3f68 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_call.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_call.rs @@ -25,6 +25,10 @@ use super::helpers; /// ```python /// [f(x) for x in foo] /// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the call. In most cases, though, comments will be preserved. #[violation] pub struct UnnecessaryListCall; diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs index 90b90afcddec8..1b72704fda096 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs @@ -25,6 +25,10 @@ use super::helpers; /// ```python /// {x: f(x) for x in foo} /// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the call. In most cases, though, comments will be preserved. #[violation] pub struct UnnecessaryListComprehensionDict; diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs index 3e5902ccd5afd..3c791385696a1 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs @@ -26,6 +26,10 @@ use super::helpers; /// ```python /// {f(x) for x in foo} /// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the call. In most cases, though, comments will be preserved. #[violation] pub struct UnnecessaryListComprehensionSet; diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs index 26ea9ea0d3563..1aa39d86ec178 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs @@ -29,6 +29,10 @@ use super::helpers; /// {1: 2, 3: 4} /// {} /// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the call. In most cases, though, comments will be preserved. #[violation] pub struct UnnecessaryLiteralDict { obj_type: String, diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_set.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_set.rs index fc4c33a0e8df1..4e3d03aaf5c69 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_set.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_set.rs @@ -31,6 +31,10 @@ use super::helpers; /// {1, 2} /// set() /// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the call. In most cases, though, comments will be preserved. #[violation] pub struct UnnecessaryLiteralSet { obj_type: String, diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_dict_call.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_dict_call.rs index 121ceaf685886..b407e9c0efca4 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_dict_call.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_dict_call.rs @@ -46,6 +46,10 @@ impl fmt::Display for DictKind { /// {} /// {"a": 1} /// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the call. In most cases, though, comments will be preserved. #[violation] pub struct UnnecessaryLiteralWithinDictCall { kind: DictKind, diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_list_call.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_list_call.rs index 6cb4596f9f116..cbf02452d2885 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_list_call.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_list_call.rs @@ -32,6 +32,10 @@ use super::helpers; /// [1, 2] /// [1, 2] /// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the call. In most cases, though, comments will be preserved. #[violation] pub struct UnnecessaryLiteralWithinListCall { literal: String, diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_tuple_call.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_tuple_call.rs index d1600979faf59..c3ca088c27c8e 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_tuple_call.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_literal_within_tuple_call.rs @@ -33,6 +33,10 @@ use super::helpers; /// (1, 2) /// (1, 2) /// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the call. In most cases, though, comments will be preserved. #[violation] pub struct UnnecessaryLiteralWithinTupleCall { literal: String, diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_map.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_map.rs index 549906f0e780c..55dc48000b471 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_map.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_map.rs @@ -22,6 +22,16 @@ use super::helpers; /// using a generator expression or a comprehension, as the latter approach /// avoids the function call overhead, in addition to being more readable. /// +/// This rule also applies to `map` calls within `list`, `set`, and `dict` +/// calls. For example: +/// +/// - Instead of `list(map(lambda num: num * 2, nums))`, use +/// `[num * 2 for num in nums]`. +/// - Instead of `set(map(lambda num: num % 2 == 0, nums))`, use +/// `{num % 2 == 0 for num in nums}`. +/// - Instead of `dict(map(lambda v: (v, v ** 2), values))`, use +/// `{v: v ** 2 for v in values}`. +/// /// ## Examples /// ```python /// map(lambda x: x + 1, iterable) @@ -32,15 +42,9 @@ use super::helpers; /// (x + 1 for x in iterable) /// ``` /// -/// This rule also applies to `map` calls within `list`, `set`, and `dict` -/// calls. For example: -/// -/// - Instead of `list(map(lambda num: num * 2, nums))`, use -/// `[num * 2 for num in nums]`. -/// - Instead of `set(map(lambda num: num % 2 == 0, nums))`, use -/// `{num % 2 == 0 for num in nums}`. -/// - Instead of `dict(map(lambda v: (v, v ** 2), values))`, use -/// `{v: v ** 2 for v in values}`. +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may occasionally drop comments +/// when rewriting the call. In most cases, though, comments will be preserved. #[violation] pub struct UnnecessaryMap { object_type: ObjectType, diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs index cb8a9600dccfa..839252ad6a1e9 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs @@ -36,6 +36,11 @@ use crate::fix::edits::pad; /// foo: int | str = 1 /// ``` /// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may lead to runtime errors when +/// alongside libraries that rely on runtime type annotations, like Pydantic, +/// on Python versions prior to Python 3.10. +/// /// ## Options /// - `target-version` /// - `pyupgrade.keep-runtime-typing` From 073eddb1d91f97a943703000243dc41d693d53c3 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 29 Nov 2023 22:22:04 -0500 Subject: [PATCH 063/197] Use Python version to determine typing rewrite safety (#8919) ## Summary These rewrites are only (potentially) unsafe on Python versions that predate their introduction into the standard library and grammar, so it seems correct to mark them as safe on those later versions. --- .../pyupgrade/rules/use_pep585_annotation.rs | 38 ++++++++++-- .../pyupgrade/rules/use_pep604_annotation.rs | 58 +++++++++++++------ 2 files changed, 71 insertions(+), 25 deletions(-) diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep585_annotation.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep585_annotation.rs index 3b91cd6504a0b..36e10b0a1c1f6 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep585_annotation.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep585_annotation.rs @@ -1,6 +1,6 @@ use ruff_python_ast::Expr; -use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; +use ruff_diagnostics::{Applicability, Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::call_path::compose_call_path; use ruff_python_semantic::analyze::typing::ModuleMember; @@ -8,6 +8,7 @@ use ruff_text_size::Ranged; use crate::checkers::ast::Checker; use crate::importer::ImportRequest; +use crate::settings::types::PythonVersion; /// ## What it does /// Checks for the use of generics that can be replaced with standard library @@ -43,6 +44,11 @@ use crate::importer::ImportRequest; /// foo: list[int] = [1, 2, 3] /// ``` /// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as it may lead to runtime errors when +/// alongside libraries that rely on runtime type annotations, like Pydantic, +/// on Python versions prior to Python 3.9. +/// /// ## Options /// - `target-version` /// - `pyupgrade.keep-runtime-typing` @@ -90,10 +96,18 @@ pub(crate) fn use_pep585_annotation( ModuleMember::BuiltIn(name) => { // Built-in type, like `list`. if checker.semantic().is_builtin(name) { - diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - (*name).to_string(), - expr.range(), - ))); + diagnostic.set_fix(Fix::applicable_edit( + Edit::range_replacement((*name).to_string(), expr.range()), + if checker.settings.preview.is_enabled() { + if checker.settings.target_version >= PythonVersion::Py310 { + Applicability::Safe + } else { + Applicability::Unsafe + } + } else { + Applicability::Safe + }, + )); } } ModuleMember::Member(module, member) => { @@ -105,7 +119,19 @@ pub(crate) fn use_pep585_annotation( checker.semantic(), )?; let reference_edit = Edit::range_replacement(binding, expr.range()); - Ok(Fix::unsafe_edits(import_edit, [reference_edit])) + Ok(Fix::applicable_edits( + import_edit, + [reference_edit], + if checker.settings.preview.is_enabled() { + if checker.settings.target_version >= PythonVersion::Py310 { + Applicability::Safe + } else { + Applicability::Unsafe + } + } else { + Applicability::Unsafe + }, + )) }); } } diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs index 839252ad6a1e9..70aa2cec0eeaf 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs @@ -1,4 +1,4 @@ -use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; +use ruff_diagnostics::{Applicability, Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::{pep_604_optional, pep_604_union}; use ruff_python_ast::{self as ast, Expr}; @@ -7,6 +7,7 @@ use ruff_text_size::Ranged; use crate::checkers::ast::Checker; use crate::fix::edits::pad; +use crate::settings::types::PythonVersion; /// ## What it does /// Check for type annotations that can be rewritten based on [PEP 604] syntax. @@ -75,6 +76,16 @@ pub(crate) fn use_pep604_annotation( && !checker.semantic().in_complex_string_type_definition() && is_allowed_value(slice); + let applicability = if checker.settings.preview.is_enabled() { + if checker.settings.target_version >= PythonVersion::Py310 { + Applicability::Safe + } else { + Applicability::Unsafe + } + } else { + Applicability::Unsafe + }; + match operator { Pep604Operator::Optional => { let mut diagnostic = Diagnostic::new(NonPEP604Annotation, expr.range()); @@ -84,14 +95,17 @@ pub(crate) fn use_pep604_annotation( // Invalid type annotation. } _ => { - diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( - pad( - checker.generator().expr(&pep_604_optional(slice)), + diagnostic.set_fix(Fix::applicable_edit( + Edit::range_replacement( + pad( + checker.generator().expr(&pep_604_optional(slice)), + expr.range(), + checker.locator(), + ), expr.range(), - checker.locator(), ), - expr.range(), - ))); + applicability, + )); } } } @@ -105,25 +119,31 @@ pub(crate) fn use_pep604_annotation( // Invalid type annotation. } Expr::Tuple(ast::ExprTuple { elts, .. }) => { - diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( - pad( - checker.generator().expr(&pep_604_union(elts)), + diagnostic.set_fix(Fix::applicable_edit( + Edit::range_replacement( + pad( + checker.generator().expr(&pep_604_union(elts)), + expr.range(), + checker.locator(), + ), expr.range(), - checker.locator(), ), - expr.range(), - ))); + applicability, + )); } _ => { // Single argument. - diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( - pad( - checker.locator().slice(slice).to_string(), + diagnostic.set_fix(Fix::applicable_edit( + Edit::range_replacement( + pad( + checker.locator().slice(slice).to_string(), + expr.range(), + checker.locator(), + ), expr.range(), - checker.locator(), ), - expr.range(), - ))); + applicability, + )); } } } From 20782ab02c099103b06d1fb28d7df56cee2775ba Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 30 Nov 2023 14:15:19 -0500 Subject: [PATCH 064/197] Support type alias statements in simple statement positions (#8916) ## Summary Our `SoftKeywordTokenizer` only respected soft keywords in compound statement positions -- for example, at the start of a logical line: ```python type X = int ``` However, type aliases can also appear in simple statement positions, like: ```python class Class: type X = int ``` (Note that `match` and `case` are _not_ valid keywords in such positions.) This PR upgrades the tokenizer to track both kinds of valid positions. Closes https://github.com/astral-sh/ruff/issues/8900. Closes https://github.com/astral-sh/ruff/issues/8899. ## Test Plan `cargo test` --- crates/ruff_python_parser/src/parser.rs | 11 +++ ...parser__tests__parse_type_declaration.snap | 94 ++++++++++++++++++ ...er__parser__tests__type_as_identifier.snap | 40 ++++++++ .../ruff_python_parser/src/soft_keywords.rs | 97 +++++++++++++++---- 4 files changed, 224 insertions(+), 18 deletions(-) diff --git a/crates/ruff_python_parser/src/parser.rs b/crates/ruff_python_parser/src/parser.rs index 82b5a26b8f89b..963d3a33064eb 100644 --- a/crates/ruff_python_parser/src/parser.rs +++ b/crates/ruff_python_parser/src/parser.rs @@ -822,6 +822,10 @@ type X \ [T] = T type X[T] \ = T + +# simple statements +type X = int; type X = str; type X = type +class X: type X = int "#; insta::assert_debug_snapshot!(parse_suite(source, "").unwrap()); } @@ -859,10 +863,17 @@ type ( type = 1 type = x = 1 x = type = 1 +lambda x: type "; insta::assert_debug_snapshot!(parse_suite(source, "").unwrap()); } + #[test] + fn test_invalid_type() { + assert!(parse_suite("a: type X = int", "").is_err()); + assert!(parse_suite("lambda: type X = int", "").is_err()); + } + #[test] fn numeric_literals() { let source = r"x = 123456789 diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_type_declaration.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_type_declaration.snap index e8ddd7d13d1eb..7730469ff75ef 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_type_declaration.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_type_declaration.snap @@ -849,4 +849,98 @@ expression: "parse_suite(source, \"\").unwrap()" ), }, ), + TypeAlias( + StmtTypeAlias { + range: 590..602, + name: Name( + ExprName { + range: 595..596, + id: "X", + ctx: Store, + }, + ), + type_params: None, + value: Name( + ExprName { + range: 599..602, + id: "int", + ctx: Load, + }, + ), + }, + ), + TypeAlias( + StmtTypeAlias { + range: 604..616, + name: Name( + ExprName { + range: 609..610, + id: "X", + ctx: Store, + }, + ), + type_params: None, + value: Name( + ExprName { + range: 613..616, + id: "str", + ctx: Load, + }, + ), + }, + ), + TypeAlias( + StmtTypeAlias { + range: 618..631, + name: Name( + ExprName { + range: 623..624, + id: "X", + ctx: Store, + }, + ), + type_params: None, + value: Name( + ExprName { + range: 627..631, + id: "type", + ctx: Load, + }, + ), + }, + ), + ClassDef( + StmtClassDef { + range: 632..653, + decorator_list: [], + name: Identifier { + id: "X", + range: 638..639, + }, + type_params: None, + arguments: None, + body: [ + TypeAlias( + StmtTypeAlias { + range: 641..653, + name: Name( + ExprName { + range: 646..647, + id: "X", + ctx: Store, + }, + ), + type_params: None, + value: Name( + ExprName { + range: 650..653, + id: "int", + ctx: Load, + }, + ), + }, + ), + ], + }, + ), ] diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__type_as_identifier.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__type_as_identifier.snap index ad394b4042ac6..0296e7ad0511e 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__type_as_identifier.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__type_as_identifier.snap @@ -988,4 +988,44 @@ expression: "parse_suite(source, \"\").unwrap()" ), }, ), + Expr( + StmtExpr { + range: 652..666, + value: Lambda( + ExprLambda { + range: 652..666, + parameters: Some( + Parameters { + range: 659..660, + posonlyargs: [], + args: [ + ParameterWithDefault { + range: 659..660, + parameter: Parameter { + range: 659..660, + name: Identifier { + id: "x", + range: 659..660, + }, + annotation: None, + }, + default: None, + }, + ], + vararg: None, + kwonlyargs: [], + kwarg: None, + }, + ), + body: Name( + ExprName { + range: 662..666, + id: "type", + ctx: Load, + }, + ), + }, + ), + }, + ), ] diff --git a/crates/ruff_python_parser/src/soft_keywords.rs b/crates/ruff_python_parser/src/soft_keywords.rs index 6d14dc7f37d72..379ae1c08db38 100644 --- a/crates/ruff_python_parser/src/soft_keywords.rs +++ b/crates/ruff_python_parser/src/soft_keywords.rs @@ -1,6 +1,7 @@ -use crate::{lexer::LexResult, token::Tok, Mode}; use itertools::{Itertools, MultiPeek}; +use crate::{lexer::LexResult, token::Tok, Mode}; + /// An [`Iterator`] that transforms a token stream to accommodate soft keywords (namely, `match` /// `case`, and `type`). /// @@ -21,7 +22,7 @@ where I: Iterator, { underlying: MultiPeek, - start_of_line: bool, + position: Position, } impl SoftKeywordTransformer @@ -31,7 +32,11 @@ where pub fn new(lexer: I, mode: Mode) -> Self { Self { underlying: lexer.multipeek(), // spell-checker:ignore multipeek - start_of_line: !matches!(mode, Mode::Expression), + position: if mode == Mode::Expression { + Position::Other + } else { + Position::Statement + }, } } } @@ -49,7 +54,6 @@ where // If the token is a soft keyword e.g. `type`, `match`, or `case`, check if it's // used as an identifier. We assume every soft keyword use is an identifier unless // a heuristic is met. - match tok { // For `match` and `case`, all of the following conditions must be met: // 1. The token is at the start of a logical line. @@ -57,9 +61,9 @@ where // inside a parenthesized expression, list, or dictionary). // 3. The top-level colon is not the immediate sibling of a `match` or `case` token. // (This is to avoid treating `match` or `case` as identifiers when annotated with - // type hints.) type hints.) + // type hints.) Tok::Match | Tok::Case => { - if self.start_of_line { + if matches!(self.position, Position::Statement) { let mut nesting = 0; let mut first = true; let mut seen_colon = false; @@ -93,7 +97,10 @@ where // 2. The type token is immediately followed by a name token. // 3. The name token is eventually followed by an equality token. Tok::Type => { - if self.start_of_line { + if matches!( + self.position, + Position::Statement | Position::SimpleStatement + ) { let mut is_type_alias = false; if let Some(Ok((tok, _))) = self.underlying.peek() { if matches!( @@ -132,18 +139,56 @@ where } } - self.start_of_line = next.as_ref().is_some_and(|lex_result| { - lex_result.as_ref().is_ok_and(|(tok, _)| { - if matches!(tok, Tok::NonLogicalNewline | Tok::Comment { .. }) { - return self.start_of_line; + // Update the position, to track whether we're at the start of a logical line. + if let Some(lex_result) = next.as_ref() { + if let Ok((tok, _)) = lex_result.as_ref() { + match tok { + Tok::NonLogicalNewline | Tok::Comment { .. } => { + // Nothing to do. + } + Tok::StartModule | Tok::Newline | Tok::Indent | Tok::Dedent => { + self.position = Position::Statement; + } + // If we see a semicolon, assume we're at the start of a simple statement, as in: + // ```python + // type X = int; type Y = float + // ``` + Tok::Semi => { + self.position = Position::SimpleStatement; + } + // If we see a colon, and we're not in a nested context, assume we're at the + // start of a simple statement, as in: + // ```python + // class Class: type X = int + // ``` + Tok::Colon if self.position == Position::Other => { + self.position = Position::SimpleStatement; + } + Tok::Lpar | Tok::Lsqb | Tok::Lbrace => { + self.position = if let Position::Nested(depth) = self.position { + Position::Nested(depth.saturating_add(1)) + } else { + Position::Nested(1) + }; + } + Tok::Rpar | Tok::Rsqb | Tok::Rbrace => { + self.position = if let Position::Nested(depth) = self.position { + let depth = depth.saturating_sub(1); + if depth > 0 { + Position::Nested(depth) + } else { + Position::Other + } + } else { + Position::Other + }; + } + _ => { + self.position = Position::Other; + } } - - matches!( - tok, - Tok::StartModule | Tok::Newline | Tok::Indent | Tok::Dedent - ) - }) - }); + } + } next } @@ -161,3 +206,19 @@ fn soft_to_name(tok: &Tok) -> Tok { name: name.to_owned(), } } + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Position { + /// The lexer is at the start of a logical line, i.e., the start of a simple or compound statement. + Statement, + /// The lexer is at the start of a simple statement, e.g., a statement following a semicolon + /// or colon, as in: + /// ```python + /// class Class: type X = int + /// ``` + SimpleStatement, + /// The lexer is within brackets, with the given bracket nesting depth. + Nested(u32), + /// The lexer is some other location. + Other, +} From d674e7946d3982deee09ab7066f966567f8e2419 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 30 Nov 2023 14:27:04 -0500 Subject: [PATCH 065/197] Ignore underlines when determining docstring logical lines (#8929) --- .../test/fixtures/pydocstyle/D400.py | 9 +++++++ .../src/rules/pydocstyle/helpers.rs | 5 ++-- ...ules__pydocstyle__tests__D400_D400.py.snap | 24 +++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D400.py b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D400.py index 38547d4addd9a..3c6cc5bfce7b1 100644 --- a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D400.py +++ b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D400.py @@ -91,3 +91,12 @@ def f(rounds: list[int], number: int) -> bool: bool: was the round played? """ return number in rounds + + +def f(): + """ + My example + ========== + + My example explanation + """ diff --git a/crates/ruff_linter/src/rules/pydocstyle/helpers.rs b/crates/ruff_linter/src/rules/pydocstyle/helpers.rs index 355ff6ea16a8b..c165d34fa6815 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/helpers.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/helpers.rs @@ -10,8 +10,9 @@ pub(super) fn logical_line(content: &str) -> Option { // Find the first logical line. let mut logical_line = None; for (i, line) in content.universal_newlines().enumerate() { - if line.trim().is_empty() { - // Empty line. If this is the line _after_ the first logical line, stop. + let trimmed = line.trim(); + if trimmed.is_empty() || trimmed.chars().all(|c| matches!(c, '-' | '~' | '=' | '#')) { + // Empty line, or underline. If this is the line _after_ the first logical line, stop. if logical_line.is_some() { break; } diff --git a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D400_D400.py.snap b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D400_D400.py.snap index 6b522fd3e9172..f7a9059cce9bd 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D400_D400.py.snap +++ b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D400_D400.py.snap @@ -247,4 +247,28 @@ D400.py:69:5: D400 [*] First line should end with a period 73 73 | 74 74 | +D400.py:97:5: D400 [*] First line should end with a period + | + 96 | def f(): + 97 | """ + | _____^ + 98 | | My example + 99 | | ========== +100 | | +101 | | My example explanation +102 | | """ + | |_______^ D400 + | + = help: Add period + +ℹ Unsafe fix +95 95 | +96 96 | def f(): +97 97 | """ +98 |- My example + 98 |+ My example. +99 99 | ========== +100 100 | +101 101 | My example explanation + From ee5d95f75118aa594c95a1fb6e35c708f46a94cd Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 30 Nov 2023 15:13:29 -0500 Subject: [PATCH 066/197] Remove duplicate imports from os-stat documentation (#8930) Closes https://github.com/astral-sh/ruff/issues/8799. --- crates/ruff_linter/src/rules/flake8_use_pathlib/violations.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/crates/ruff_linter/src/rules/flake8_use_pathlib/violations.rs b/crates/ruff_linter/src/rules/flake8_use_pathlib/violations.rs index 7e18f8290ed4f..55600d45aceb9 100644 --- a/crates/ruff_linter/src/rules/flake8_use_pathlib/violations.rs +++ b/crates/ruff_linter/src/rules/flake8_use_pathlib/violations.rs @@ -705,8 +705,6 @@ impl Violation for OsReadlink { /// ## Examples /// ```python /// import os -/// -/// import os /// from pwd import getpwuid /// from grp import getgrgid /// @@ -719,8 +717,6 @@ impl Violation for OsReadlink { /// ```python /// from pathlib import Path /// -/// from pathlib import Path -/// /// file_path = Path(file_name) /// stat = file_path.stat() /// owner_name = file_path.owner() From 3ee1ec70ccf5054967f47ff3d6864cb839059247 Mon Sep 17 00:00:00 2001 From: Steve C Date: Thu, 30 Nov 2023 17:02:20 -0500 Subject: [PATCH 067/197] Fix up some types in the ecosystem code (#8898) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fixes up the type annotations to make type analyzers a little happier 😄 ## Test Plan N/A --- python/ruff-ecosystem/ruff_ecosystem/check.py | 2 +- python/ruff-ecosystem/ruff_ecosystem/format.py | 6 +++--- python/ruff-ecosystem/ruff_ecosystem/main.py | 9 +++++---- python/ruff-ecosystem/ruff_ecosystem/markdown.py | 10 ++++++---- python/ruff-ecosystem/ruff_ecosystem/projects.py | 2 +- python/ruff-ecosystem/ruff_ecosystem/types.py | 2 +- 6 files changed, 17 insertions(+), 14 deletions(-) diff --git a/python/ruff-ecosystem/ruff_ecosystem/check.py b/python/ruff-ecosystem/ruff_ecosystem/check.py index 2e996ff006773..fe5ea0c246434 100644 --- a/python/ruff-ecosystem/ruff_ecosystem/check.py +++ b/python/ruff-ecosystem/ruff_ecosystem/check.py @@ -63,7 +63,7 @@ def markdown_check_result(result: Result) -> str: project_rule_changes[project] = changes = RuleChanges.from_diff(diff) all_rule_changes.update(changes) - lines = [] + lines: list[str] = [] total_removed = all_rule_changes.total_removed_violations() total_added = all_rule_changes.total_added_violations() total_added_fixes = all_rule_changes.total_added_fixes() diff --git a/python/ruff-ecosystem/ruff_ecosystem/format.py b/python/ruff-ecosystem/ruff_ecosystem/format.py index f639150a8680f..2a15e62920e95 100644 --- a/python/ruff-ecosystem/ruff_ecosystem/format.py +++ b/python/ruff-ecosystem/ruff_ecosystem/format.py @@ -25,11 +25,11 @@ def markdown_format_result(result: Result) -> str: """ Render a `ruff format` ecosystem check result as markdown. """ - lines = [] + lines: list[str] = [] total_lines_removed = total_lines_added = 0 total_files_modified = 0 error_count = len(result.errored) - patch_sets = [] + patch_sets: list[PatchSet] = [] for project, comparison in result.completed: total_lines_added += comparison.diff.lines_added @@ -97,7 +97,7 @@ def format_patchset(patch_set: PatchSet, repo: ClonedRepository) -> str: """ Convert a patchset to markdown, adding permalinks to the start of each hunk. """ - lines = [] + lines: list[str] = [] for file_patch in patch_set: for hunk in file_patch: # Note: When used for `format` checks, the line number is not exact because diff --git a/python/ruff-ecosystem/ruff_ecosystem/main.py b/python/ruff-ecosystem/ruff_ecosystem/main.py index e7f50093b960a..ca0e3037c78b5 100644 --- a/python/ruff-ecosystem/ruff_ecosystem/main.py +++ b/python/ruff-ecosystem/ruff_ecosystem/main.py @@ -53,7 +53,7 @@ async def limited_parallelism(coroutine: Awaitable[T]) -> T: async with semaphore: return await coroutine - comparisons: list[Exception | Comparison] = await asyncio.gather( + comparisons: list[BaseException | Comparison] = await asyncio.gather( *[ limited_parallelism( clone_and_compare( @@ -72,9 +72,10 @@ async def limited_parallelism(coroutine: Awaitable[T]) -> T: comparisons_by_target = dict(zip(targets, comparisons, strict=True)) # Split comparisons into errored / completed - errored, completed = [], [] + errored: list[tuple[Project, BaseException]] = [] + completed: list[tuple[Project, Comparison]] = [] for target, comparison in comparisons_by_target.items(): - if isinstance(comparison, Exception): + if isinstance(comparison, BaseException): errored.append((target, comparison)) else: completed.append((target, comparison)) @@ -138,7 +139,7 @@ async def clone_and_compare( class JSONEncoder(json.JSONEncoder): - def default(self, o): + def default(self, o: object): if isinstance(o, Serializable): return o.jsonable() if dataclasses.is_dataclass(o): diff --git a/python/ruff-ecosystem/ruff_ecosystem/markdown.py b/python/ruff-ecosystem/ruff_ecosystem/markdown.py index e6f606069515e..0af3b20367971 100644 --- a/python/ruff-ecosystem/ruff_ecosystem/markdown.py +++ b/python/ruff-ecosystem/ruff_ecosystem/markdown.py @@ -3,11 +3,11 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from ruff_ecosystem.projects import Project + from ruff_ecosystem.projects import CommandOptions, Project def markdown_project_section( - title: str, content: str | list[str], options: object, project: Project + title: str, content: str | list[str], options: CommandOptions, project: Project ) -> list[str]: return markdown_details( summary=f'{project.repo.fullname} ({title})', @@ -28,8 +28,10 @@ def markdown_plus_minus(added: int, removed: int) -> str: return f"+{added} -{removed}" -def markdown_details(summary: str, content: str | list[str], preface: str): - lines = [] +def markdown_details( + summary: str, content: str | list[str], preface: str | None +) -> list[str]: + lines: list[str] = [] lines.append(f"
{summary}") if preface: lines.append("

") diff --git a/python/ruff-ecosystem/ruff_ecosystem/projects.py b/python/ruff-ecosystem/ruff_ecosystem/projects.py index d4fb64e804ed9..fa5f8224a8958 100644 --- a/python/ruff-ecosystem/ruff_ecosystem/projects.py +++ b/python/ruff-ecosystem/ruff_ecosystem/projects.py @@ -104,7 +104,7 @@ def to_ruff_args(self) -> list[str]: return args def to_black_args(self) -> list[str]: - args = [] + args: list[str] = [] if self.exclude: args.extend(["--exclude", self.exclude]) if self.preview: diff --git a/python/ruff-ecosystem/ruff_ecosystem/types.py b/python/ruff-ecosystem/ruff_ecosystem/types.py index 41a9b02aab310..687ab31ce82b4 100644 --- a/python/ruff-ecosystem/ruff_ecosystem/types.py +++ b/python/ruff-ecosystem/ruff_ecosystem/types.py @@ -75,7 +75,7 @@ class Result(Serializable): The result of an ecosystem check for a collection of projects. """ - errored: list[tuple[Project, Exception]] + errored: list[tuple[Project, BaseException]] completed: list[tuple[Project, Comparison]] From bbad4b4c939bd193b7b9b64c187ab956d5b1d422 Mon Sep 17 00:00:00 2001 From: Steve C Date: Thu, 30 Nov 2023 17:16:57 -0500 Subject: [PATCH 068/197] Add autofix for `PYI030` (#7934) ## Summary Part 2 of implementing the reverted autofix for `PYI030` Also handles `typing.Union` and `typing_extensions.Literal` etc, uses the first subscript name it finds for each offensive line. ## Test Plan `cargo test` and manually --------- Co-authored-by: Zanie Blue --- .../test/fixtures/flake8_pyi/PYI030.py | 51 ++++++ .../test/fixtures/flake8_pyi/PYI030.pyi | 3 + .../rules/unnecessary_literal_union.rs | 145 ++++++++++++++-- ...__flake8_pyi__tests__PYI030_PYI030.py.snap | 158 ++++++++++++++++++ ..._flake8_pyi__tests__PYI030_PYI030.pyi.snap | 35 ++++ 5 files changed, 380 insertions(+), 12 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI030.py b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI030.py index 3c9d0ac15c9c3..c6cd2b453707a 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI030.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI030.py @@ -36,3 +36,54 @@ def func2() -> Literal[1] | Literal[2]: # Error # Should emit for union in generic parent type. field11: dict[Literal[1] | Literal[2], str] # Error + +# Should emit for unions with more than two cases +field12: Literal[1] | Literal[2] | Literal[3] # Error +field13: Literal[1] | Literal[2] | Literal[3] | Literal[4] # Error + +# Should emit for unions with more than two cases, even if not directly adjacent +field14: Literal[1] | Literal[2] | str | Literal[3] # Error + +# Should emit for unions with mixed literal internal types +field15: Literal[1] | Literal["foo"] | Literal[True] # Error + +# Shouldn't emit for duplicate field types with same value; covered by Y016 +field16: Literal[1] | Literal[1] # OK + +# Shouldn't emit if in new parent type +field17: Literal[1] | dict[Literal[2], str] # OK + +# Shouldn't emit if not in a union parent +field18: dict[Literal[1], Literal[2]] # OK + +# Should respect name of literal type used +field19: typing.Literal[1] | typing.Literal[2] # Error + +# Should emit in cases with newlines +field20: typing.Union[ + Literal[ + 1 # test + ], + Literal[2], +] # Error, newline and comment will not be emitted in message + +# Should handle multiple unions with multiple members +field21: Literal[1, 2] | Literal[3, 4] # Error + +# Should emit in cases with `typing.Union` instead of `|` +field22: typing.Union[Literal[1], Literal[2]] # Error + +# Should emit in cases with `typing_extensions.Literal` +field23: typing_extensions.Literal[1] | typing_extensions.Literal[2] # Error + +# Should emit in cases with nested `typing.Union` +field24: typing.Union[Literal[1], typing.Union[Literal[2], str]] # Error + +# Should emit in cases with mixed `typing.Union` and `|` +field25: typing.Union[Literal[1], Literal[2] | str] # Error + +# Should emit only once in cases with multiple nested `typing.Union` +field24: typing.Union[Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]]] # Error + +# Should use the first literal subscript attribute when fixing +field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI030.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI030.pyi index e92af925df67d..c6cd2b453707a 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI030.pyi +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI030.pyi @@ -84,3 +84,6 @@ field25: typing.Union[Literal[1], Literal[2] | str] # Error # Should emit only once in cases with multiple nested `typing.Union` field24: typing.Union[Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]]] # Error + +# Should use the first literal subscript attribute when fixing +field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_literal_union.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_literal_union.rs index 187837905fe60..7b56371e837c3 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_literal_union.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_literal_union.rs @@ -1,9 +1,11 @@ -use ruff_diagnostics::{Diagnostic, Violation}; +use ast::{ExprSubscript, Operator}; +use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::{self as ast, Expr}; -use ruff_text_size::Ranged; +use ruff_text_size::{Ranged, TextRange}; use crate::checkers::ast::Checker; + use crate::rules::flake8_pyi::helpers::traverse_union; /// ## What it does @@ -32,6 +34,8 @@ pub struct UnnecessaryLiteralUnion { } impl Violation for UnnecessaryLiteralUnion { + const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes; + #[derive_message_formats] fn message(&self) -> String { format!( @@ -39,36 +43,153 @@ impl Violation for UnnecessaryLiteralUnion { self.members.join(", ") ) } + + fn fix_title(&self) -> Option { + Some(format!("Replace with a single `Literal`",)) + } +} + +fn concatenate_bin_ors(exprs: Vec<&Expr>) -> Expr { + let mut exprs = exprs.into_iter(); + let first = exprs.next().unwrap(); + exprs.fold((*first).clone(), |acc, expr| { + Expr::BinOp(ast::ExprBinOp { + left: Box::new(acc), + op: Operator::BitOr, + right: Box::new((*expr).clone()), + range: TextRange::default(), + }) + }) +} + +fn make_union(subscript: &ExprSubscript, exprs: Vec<&Expr>) -> Expr { + Expr::Subscript(ast::ExprSubscript { + value: subscript.value.clone(), + slice: Box::new(Expr::Tuple(ast::ExprTuple { + elts: exprs.into_iter().map(|expr| (*expr).clone()).collect(), + range: TextRange::default(), + ctx: ast::ExprContext::Load, + })), + range: TextRange::default(), + ctx: ast::ExprContext::Load, + }) +} + +fn make_literal_expr(subscript: Option, exprs: Vec<&Expr>) -> Expr { + let use_subscript = if let subscript @ Some(_) = subscript { + subscript.unwrap().clone() + } else { + Expr::Name(ast::ExprName { + id: "Literal".to_string(), + range: TextRange::default(), + ctx: ast::ExprContext::Load, + }) + }; + Expr::Subscript(ast::ExprSubscript { + value: Box::new(use_subscript), + slice: Box::new(Expr::Tuple(ast::ExprTuple { + elts: exprs.into_iter().map(|expr| (*expr).clone()).collect(), + range: TextRange::default(), + ctx: ast::ExprContext::Load, + })), + range: TextRange::default(), + ctx: ast::ExprContext::Load, + }) } /// PYI030 pub(crate) fn unnecessary_literal_union<'a>(checker: &mut Checker, expr: &'a Expr) { let mut literal_exprs = Vec::new(); + let mut other_exprs = Vec::new(); + + // for the sake of consistency and correctness, we'll use the first `Literal` subscript attribute + // to construct the fix + let mut literal_subscript = None; + let mut total_literals = 0; - // Adds a member to `literal_exprs` if it is a `Literal` annotation + // Split members into `literal_exprs` if they are a `Literal` annotation and `other_exprs` otherwise let mut collect_literal_expr = |expr: &'a Expr, _| { if let Expr::Subscript(ast::ExprSubscript { value, slice, .. }) = expr { if checker.semantic().match_typing_expr(value, "Literal") { - literal_exprs.push(slice); + total_literals += 1; + + if literal_subscript.is_none() { + literal_subscript = Some(*value.clone()); + } + + // flatten already-unioned literals to later union again + if let Expr::Tuple(ast::ExprTuple { + elts, + range: _, + ctx: _, + }) = slice.as_ref() + { + for expr in elts { + literal_exprs.push(expr); + } + } else { + literal_exprs.push(slice.as_ref()); + } } + } else { + other_exprs.push(expr); } }; - // Traverse the union, collect all literal members + // Traverse the union, collect all members, split out the literals from the rest. traverse_union(&mut collect_literal_expr, checker.semantic(), expr, None); - // Raise a violation if more than one - if literal_exprs.len() > 1 { - let diagnostic = Diagnostic::new( + let union_subscript = expr.as_subscript_expr(); + if union_subscript.is_some_and(|subscript| { + !checker + .semantic() + .match_typing_expr(&subscript.value, "Union") + }) { + return; + } + + // Raise a violation if more than one. + if total_literals > 1 { + let literal_members: Vec = literal_exprs + .clone() + .into_iter() + .map(|expr| checker.locator().slice(expr).to_string()) + .collect(); + + let mut diagnostic = Diagnostic::new( UnnecessaryLiteralUnion { - members: literal_exprs - .into_iter() - .map(|expr| checker.locator().slice(expr.as_ref()).to_string()) - .collect(), + members: literal_members.clone(), }, expr.range(), ); + if checker.settings.preview.is_enabled() { + let literals = + make_literal_expr(literal_subscript, literal_exprs.into_iter().collect()); + + if other_exprs.is_empty() { + // if the union is only literals, we just replace the whole thing with a single literal + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + checker.generator().expr(&literals), + expr.range(), + ))); + } else { + let mut expr_vec: Vec<&Expr> = other_exprs.clone().into_iter().collect(); + expr_vec.insert(0, &literals); + + let content = if let Some(subscript) = union_subscript { + checker.generator().expr(&make_union(subscript, expr_vec)) + } else { + checker.generator().expr(&concatenate_bin_ors(expr_vec)) + }; + + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + content, + expr.range(), + ))); + } + } + checker.diagnostics.push(diagnostic); } } diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI030_PYI030.py.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI030_PYI030.py.snap index 8f6838bde1deb..b06ed30fe2396 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI030_PYI030.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI030_PYI030.py.snap @@ -9,6 +9,7 @@ PYI030.py:9:9: PYI030 Multiple literal members in a union. Use a single literal, 10 | 11 | # Should emit for union types in arguments. | + = help: Replace with a single `Literal` PYI030.py:12:17: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -17,6 +18,7 @@ PYI030.py:12:17: PYI030 Multiple literal members in a union. Use a single litera | ^^^^^^^^^^^^^^^^^^^^^^^ PYI030 13 | print(arg1) | + = help: Replace with a single `Literal` PYI030.py:17:16: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -25,6 +27,7 @@ PYI030.py:17:16: PYI030 Multiple literal members in a union. Use a single litera | ^^^^^^^^^^^^^^^^^^^^^^^ PYI030 18 | return "my Literal[1]ing" | + = help: Replace with a single `Literal` PYI030.py:22:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -34,6 +37,7 @@ PYI030.py:22:9: PYI030 Multiple literal members in a union. Use a single literal 23 | field4: str | Literal[1] | Literal[2] # Error 24 | field5: Literal[1] | str | Literal[2] # Error | + = help: Replace with a single `Literal` PYI030.py:23:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -44,6 +48,7 @@ PYI030.py:23:9: PYI030 Multiple literal members in a union. Use a single literal 24 | field5: Literal[1] | str | Literal[2] # Error 25 | field6: Literal[1] | bool | Literal[2] | str # Error | + = help: Replace with a single `Literal` PYI030.py:24:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -53,6 +58,7 @@ PYI030.py:24:9: PYI030 Multiple literal members in a union. Use a single literal | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 25 | field6: Literal[1] | bool | Literal[2] | str # Error | + = help: Replace with a single `Literal` PYI030.py:25:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -63,6 +69,7 @@ PYI030.py:25:9: PYI030 Multiple literal members in a union. Use a single literal 26 | 27 | # Should emit for non-type unions. | + = help: Replace with a single `Literal` PYI030.py:28:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -72,6 +79,7 @@ PYI030.py:28:10: PYI030 Multiple literal members in a union. Use a single litera 29 | 30 | # Should emit for parenthesized unions. | + = help: Replace with a single `Literal` PYI030.py:31:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -81,6 +89,7 @@ PYI030.py:31:9: PYI030 Multiple literal members in a union. Use a single literal 32 | 33 | # Should handle user parentheses when fixing. | + = help: Replace with a single `Literal` PYI030.py:34:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -89,6 +98,7 @@ PYI030.py:34:9: PYI030 Multiple literal members in a union. Use a single literal | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 35 | field10: (Literal[1] | str) | Literal[2] # Error | + = help: Replace with a single `Literal` PYI030.py:35:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -99,12 +109,160 @@ PYI030.py:35:10: PYI030 Multiple literal members in a union. Use a single litera 36 | 37 | # Should emit for union in generic parent type. | + = help: Replace with a single `Literal` PYI030.py:38:15: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | 37 | # Should emit for union in generic parent type. 38 | field11: dict[Literal[1] | Literal[2], str] # Error | ^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +39 | +40 | # Should emit for unions with more than two cases | + = help: Replace with a single `Literal` + +PYI030.py:41:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3]` + | +40 | # Should emit for unions with more than two cases +41 | field12: Literal[1] | Literal[2] | Literal[3] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +42 | field13: Literal[1] | Literal[2] | Literal[3] | Literal[4] # Error + | + = help: Replace with a single `Literal` + +PYI030.py:42:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]` + | +40 | # Should emit for unions with more than two cases +41 | field12: Literal[1] | Literal[2] | Literal[3] # Error +42 | field13: Literal[1] | Literal[2] | Literal[3] | Literal[4] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +43 | +44 | # Should emit for unions with more than two cases, even if not directly adjacent + | + = help: Replace with a single `Literal` + +PYI030.py:45:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3]` + | +44 | # Should emit for unions with more than two cases, even if not directly adjacent +45 | field14: Literal[1] | Literal[2] | str | Literal[3] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +46 | +47 | # Should emit for unions with mixed literal internal types + | + = help: Replace with a single `Literal` + +PYI030.py:48:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, "foo", True]` + | +47 | # Should emit for unions with mixed literal internal types +48 | field15: Literal[1] | Literal["foo"] | Literal[True] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +49 | +50 | # Shouldn't emit for duplicate field types with same value; covered by Y016 + | + = help: Replace with a single `Literal` + +PYI030.py:51:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 1]` + | +50 | # Shouldn't emit for duplicate field types with same value; covered by Y016 +51 | field16: Literal[1] | Literal[1] # OK + | ^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +52 | +53 | # Shouldn't emit if in new parent type + | + = help: Replace with a single `Literal` + +PYI030.py:60:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +59 | # Should respect name of literal type used +60 | field19: typing.Literal[1] | typing.Literal[2] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +61 | +62 | # Should emit in cases with newlines + | + = help: Replace with a single `Literal` + +PYI030.py:63:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +62 | # Should emit in cases with newlines +63 | field20: typing.Union[ + | __________^ +64 | | Literal[ +65 | | 1 # test +66 | | ], +67 | | Literal[2], +68 | | ] # Error, newline and comment will not be emitted in message + | |_^ PYI030 +69 | +70 | # Should handle multiple unions with multiple members + | + = help: Replace with a single `Literal` + +PYI030.py:71:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]` + | +70 | # Should handle multiple unions with multiple members +71 | field21: Literal[1, 2] | Literal[3, 4] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +72 | +73 | # Should emit in cases with `typing.Union` instead of `|` + | + = help: Replace with a single `Literal` + +PYI030.py:74:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +73 | # Should emit in cases with `typing.Union` instead of `|` +74 | field22: typing.Union[Literal[1], Literal[2]] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +75 | +76 | # Should emit in cases with `typing_extensions.Literal` + | + = help: Replace with a single `Literal` + +PYI030.py:77:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +76 | # Should emit in cases with `typing_extensions.Literal` +77 | field23: typing_extensions.Literal[1] | typing_extensions.Literal[2] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +78 | +79 | # Should emit in cases with nested `typing.Union` + | + = help: Replace with a single `Literal` + +PYI030.py:80:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +79 | # Should emit in cases with nested `typing.Union` +80 | field24: typing.Union[Literal[1], typing.Union[Literal[2], str]] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +81 | +82 | # Should emit in cases with mixed `typing.Union` and `|` + | + = help: Replace with a single `Literal` + +PYI030.py:83:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +82 | # Should emit in cases with mixed `typing.Union` and `|` +83 | field25: typing.Union[Literal[1], Literal[2] | str] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +84 | +85 | # Should emit only once in cases with multiple nested `typing.Union` + | + = help: Replace with a single `Literal` + +PYI030.py:86:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]` + | +85 | # Should emit only once in cases with multiple nested `typing.Union` +86 | field24: typing.Union[Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]]] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +87 | +88 | # Should use the first literal subscript attribute when fixing + | + = help: Replace with a single `Literal` + +PYI030.py:89:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]` + | +88 | # Should use the first literal subscript attribute when fixing +89 | field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 + | + = help: Replace with a single `Literal` diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI030_PYI030.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI030_PYI030.pyi.snap index 6e9214a8a4c43..ec113b46dd315 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI030_PYI030.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI030_PYI030.pyi.snap @@ -9,6 +9,7 @@ PYI030.pyi:9:9: PYI030 Multiple literal members in a union. Use a single literal 10 | 11 | # Should emit for union types in arguments. | + = help: Replace with a single `Literal` PYI030.pyi:12:17: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -17,6 +18,7 @@ PYI030.pyi:12:17: PYI030 Multiple literal members in a union. Use a single liter | ^^^^^^^^^^^^^^^^^^^^^^^ PYI030 13 | print(arg1) | + = help: Replace with a single `Literal` PYI030.pyi:17:16: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -25,6 +27,7 @@ PYI030.pyi:17:16: PYI030 Multiple literal members in a union. Use a single liter | ^^^^^^^^^^^^^^^^^^^^^^^ PYI030 18 | return "my Literal[1]ing" | + = help: Replace with a single `Literal` PYI030.pyi:22:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -34,6 +37,7 @@ PYI030.pyi:22:9: PYI030 Multiple literal members in a union. Use a single litera 23 | field4: str | Literal[1] | Literal[2] # Error 24 | field5: Literal[1] | str | Literal[2] # Error | + = help: Replace with a single `Literal` PYI030.pyi:23:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -44,6 +48,7 @@ PYI030.pyi:23:9: PYI030 Multiple literal members in a union. Use a single litera 24 | field5: Literal[1] | str | Literal[2] # Error 25 | field6: Literal[1] | bool | Literal[2] | str # Error | + = help: Replace with a single `Literal` PYI030.pyi:24:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -53,6 +58,7 @@ PYI030.pyi:24:9: PYI030 Multiple literal members in a union. Use a single litera | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 25 | field6: Literal[1] | bool | Literal[2] | str # Error | + = help: Replace with a single `Literal` PYI030.pyi:25:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -63,6 +69,7 @@ PYI030.pyi:25:9: PYI030 Multiple literal members in a union. Use a single litera 26 | 27 | # Should emit for non-type unions. | + = help: Replace with a single `Literal` PYI030.pyi:28:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -72,6 +79,7 @@ PYI030.pyi:28:10: PYI030 Multiple literal members in a union. Use a single liter 29 | 30 | # Should emit for parenthesized unions. | + = help: Replace with a single `Literal` PYI030.pyi:31:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -81,6 +89,7 @@ PYI030.pyi:31:9: PYI030 Multiple literal members in a union. Use a single litera 32 | 33 | # Should handle user parentheses when fixing. | + = help: Replace with a single `Literal` PYI030.pyi:34:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -89,6 +98,7 @@ PYI030.pyi:34:9: PYI030 Multiple literal members in a union. Use a single litera | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 35 | field10: (Literal[1] | str) | Literal[2] # Error | + = help: Replace with a single `Literal` PYI030.pyi:35:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -99,6 +109,7 @@ PYI030.pyi:35:10: PYI030 Multiple literal members in a union. Use a single liter 36 | 37 | # Should emit for union in generic parent type. | + = help: Replace with a single `Literal` PYI030.pyi:38:15: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -108,6 +119,7 @@ PYI030.pyi:38:15: PYI030 Multiple literal members in a union. Use a single liter 39 | 40 | # Should emit for unions with more than two cases | + = help: Replace with a single `Literal` PYI030.pyi:41:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3]` | @@ -116,6 +128,7 @@ PYI030.pyi:41:10: PYI030 Multiple literal members in a union. Use a single liter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 42 | field13: Literal[1] | Literal[2] | Literal[3] | Literal[4] # Error | + = help: Replace with a single `Literal` PYI030.pyi:42:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]` | @@ -126,6 +139,7 @@ PYI030.pyi:42:10: PYI030 Multiple literal members in a union. Use a single liter 43 | 44 | # Should emit for unions with more than two cases, even if not directly adjacent | + = help: Replace with a single `Literal` PYI030.pyi:45:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3]` | @@ -135,6 +149,7 @@ PYI030.pyi:45:10: PYI030 Multiple literal members in a union. Use a single liter 46 | 47 | # Should emit for unions with mixed literal internal types | + = help: Replace with a single `Literal` PYI030.pyi:48:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, "foo", True]` | @@ -144,6 +159,7 @@ PYI030.pyi:48:10: PYI030 Multiple literal members in a union. Use a single liter 49 | 50 | # Shouldn't emit for duplicate field types with same value; covered by Y016 | + = help: Replace with a single `Literal` PYI030.pyi:51:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 1]` | @@ -153,6 +169,7 @@ PYI030.pyi:51:10: PYI030 Multiple literal members in a union. Use a single liter 52 | 53 | # Shouldn't emit if in new parent type | + = help: Replace with a single `Literal` PYI030.pyi:60:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -162,6 +179,7 @@ PYI030.pyi:60:10: PYI030 Multiple literal members in a union. Use a single liter 61 | 62 | # Should emit in cases with newlines | + = help: Replace with a single `Literal` PYI030.pyi:63:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -177,6 +195,7 @@ PYI030.pyi:63:10: PYI030 Multiple literal members in a union. Use a single liter 69 | 70 | # Should handle multiple unions with multiple members | + = help: Replace with a single `Literal` PYI030.pyi:71:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]` | @@ -186,6 +205,7 @@ PYI030.pyi:71:10: PYI030 Multiple literal members in a union. Use a single liter 72 | 73 | # Should emit in cases with `typing.Union` instead of `|` | + = help: Replace with a single `Literal` PYI030.pyi:74:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -195,6 +215,7 @@ PYI030.pyi:74:10: PYI030 Multiple literal members in a union. Use a single liter 75 | 76 | # Should emit in cases with `typing_extensions.Literal` | + = help: Replace with a single `Literal` PYI030.pyi:77:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -204,6 +225,7 @@ PYI030.pyi:77:10: PYI030 Multiple literal members in a union. Use a single liter 78 | 79 | # Should emit in cases with nested `typing.Union` | + = help: Replace with a single `Literal` PYI030.pyi:80:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -213,6 +235,7 @@ PYI030.pyi:80:10: PYI030 Multiple literal members in a union. Use a single liter 81 | 82 | # Should emit in cases with mixed `typing.Union` and `|` | + = help: Replace with a single `Literal` PYI030.pyi:83:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` | @@ -222,12 +245,24 @@ PYI030.pyi:83:10: PYI030 Multiple literal members in a union. Use a single liter 84 | 85 | # Should emit only once in cases with multiple nested `typing.Union` | + = help: Replace with a single `Literal` PYI030.pyi:86:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]` | 85 | # Should emit only once in cases with multiple nested `typing.Union` 86 | field24: typing.Union[Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]]] # Error | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +87 | +88 | # Should use the first literal subscript attribute when fixing | + = help: Replace with a single `Literal` + +PYI030.pyi:89:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]` + | +88 | # Should use the first literal subscript attribute when fixing +89 | field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 + | + = help: Replace with a single `Literal` From 4212b417961fa73cc7f618f26b3c213b96437c80 Mon Sep 17 00:00:00 2001 From: Steve C Date: Thu, 30 Nov 2023 17:18:09 -0500 Subject: [PATCH 069/197] [pylint] - implement R0202 and R0203 with autofixes (#8335) ## Summary Implements [`no-classmethod-decorator`/`R0202`](https://pylint.readthedocs.io/en/latest/user_guide/messages/refactor/no-classmethod-decorator.html) and [`no-staticmethod-decorator`/`R0203`](https://pylint.readthedocs.io/en/latest/user_guide/messages/refactor/no-staticmethod-decorator.html) with autofixes. They're similar enough that all code is reusable for both. See: #970 ## Test Plan `cargo test` --- .../fixtures/pylint/no_method_decorator.py | 19 ++ .../src/checkers/ast/analyze/statement.rs | 6 + crates/ruff_linter/src/codes.rs | 2 + crates/ruff_linter/src/rules/pylint/mod.rs | 2 + .../ruff_linter/src/rules/pylint/rules/mod.rs | 2 + .../rules/pylint/rules/no_method_decorator.rs | 202 ++++++++++++++++++ ...tests__PLR0202_no_method_decorator.py.snap | 31 +++ ...tests__PLR0203_no_method_decorator.py.snap | 27 +++ ruff.schema.json | 2 + 9 files changed, 293 insertions(+) create mode 100644 crates/ruff_linter/resources/test/fixtures/pylint/no_method_decorator.py create mode 100644 crates/ruff_linter/src/rules/pylint/rules/no_method_decorator.rs create mode 100644 crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0202_no_method_decorator.py.snap create mode 100644 crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0203_no_method_decorator.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/no_method_decorator.py b/crates/ruff_linter/resources/test/fixtures/pylint/no_method_decorator.py new file mode 100644 index 0000000000000..e8351cb80ad61 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/pylint/no_method_decorator.py @@ -0,0 +1,19 @@ +from random import choice + +class Fruit: + COLORS = [] + + def __init__(self, color): + self.color = color + + def pick_colors(cls, *args): # [no-classmethod-decorator] + """classmethod to pick fruit colors""" + cls.COLORS = args + + pick_colors = classmethod(pick_colors) + + def pick_one_color(): # [no-staticmethod-decorator] + """staticmethod to pick one fruit color""" + return choice(Fruit.COLORS) + + pick_one_color = staticmethod(pick_one_color) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 448ce1d2bac06..addf24b8103c4 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -384,6 +384,12 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { range: _, }, ) => { + if checker.enabled(Rule::NoClassmethodDecorator) { + pylint::rules::no_classmethod_decorator(checker, class_def); + } + if checker.enabled(Rule::NoStaticmethodDecorator) { + pylint::rules::no_staticmethod_decorator(checker, class_def); + } if checker.enabled(Rule::DjangoNullableModelStringField) { flake8_django::rules::nullable_model_string_field(checker, body); } diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index 4dc1f13c55e05..e127c26c68e35 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -245,6 +245,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Pylint, "E2515") => (RuleGroup::Stable, rules::pylint::rules::InvalidCharacterZeroWidthSpace), (Pylint, "R0124") => (RuleGroup::Stable, rules::pylint::rules::ComparisonWithItself), (Pylint, "R0133") => (RuleGroup::Stable, rules::pylint::rules::ComparisonOfConstant), + (Pylint, "R0202") => (RuleGroup::Preview, rules::pylint::rules::NoClassmethodDecorator), + (Pylint, "R0203") => (RuleGroup::Preview, rules::pylint::rules::NoStaticmethodDecorator), (Pylint, "R0206") => (RuleGroup::Stable, rules::pylint::rules::PropertyWithParameters), (Pylint, "R0402") => (RuleGroup::Stable, rules::pylint::rules::ManualFromImport), (Pylint, "R0911") => (RuleGroup::Stable, rules::pylint::rules::TooManyReturnStatements), diff --git a/crates/ruff_linter/src/rules/pylint/mod.rs b/crates/ruff_linter/src/rules/pylint/mod.rs index e2f272619b2ce..b2ebed57d6edb 100644 --- a/crates/ruff_linter/src/rules/pylint/mod.rs +++ b/crates/ruff_linter/src/rules/pylint/mod.rs @@ -154,6 +154,8 @@ mod tests { Rule::RepeatedKeywordArgument, Path::new("repeated_keyword_argument.py") )] + #[test_case(Rule::NoClassmethodDecorator, Path::new("no_method_decorator.py"))] + #[test_case(Rule::NoStaticmethodDecorator, Path::new("no_method_decorator.py"))] fn rules(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/pylint/rules/mod.rs b/crates/ruff_linter/src/rules/pylint/rules/mod.rs index b130d36260182..c332cdd243646 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/mod.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/mod.rs @@ -35,6 +35,7 @@ pub(crate) use manual_import_from::*; pub(crate) use misplaced_bare_raise::*; pub(crate) use named_expr_without_context::*; pub(crate) use nested_min_max::*; +pub(crate) use no_method_decorator::*; pub(crate) use no_self_use::*; pub(crate) use non_ascii_module_import::*; pub(crate) use non_ascii_name::*; @@ -108,6 +109,7 @@ mod manual_import_from; mod misplaced_bare_raise; mod named_expr_without_context; mod nested_min_max; +mod no_method_decorator; mod no_self_use; mod non_ascii_module_import; mod non_ascii_name; diff --git a/crates/ruff_linter/src/rules/pylint/rules/no_method_decorator.rs b/crates/ruff_linter/src/rules/pylint/rules/no_method_decorator.rs new file mode 100644 index 0000000000000..d2dc1ea329484 --- /dev/null +++ b/crates/ruff_linter/src/rules/pylint/rules/no_method_decorator.rs @@ -0,0 +1,202 @@ +use std::collections::HashMap; + +use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, DiagnosticKind, Edit, Fix}; +use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::{self as ast, Expr, Stmt}; +use ruff_python_trivia::indentation_at_offset; +use ruff_text_size::{Ranged, TextRange, TextSize}; + +use crate::checkers::ast::Checker; + +/// ## What it does +/// Checks for the use of a classmethod being made without the decorator. +/// +/// ## Why is this bad? +/// When it comes to consistency and readability, it's preferred to use the decorator. +/// +/// ## Example +/// ```python +/// class Foo: +/// def bar(cls): +/// ... +/// +/// bar = classmethod(bar) +/// ``` +/// +/// Use instead: +/// ```python +/// class Foo: +/// @classmethod +/// def bar(cls): +/// ... +/// ``` +#[violation] +pub struct NoClassmethodDecorator; + +impl AlwaysFixableViolation for NoClassmethodDecorator { + #[derive_message_formats] + fn message(&self) -> String { + format!("Class method defined without decorator") + } + + fn fix_title(&self) -> String { + format!("Add @classmethod decorator") + } +} + +/// ## What it does +/// Checks for the use of a staticmethod being made without the decorator. +/// +/// ## Why is this bad? +/// When it comes to consistency and readability, it's preferred to use the decorator. +/// +/// ## Example +/// ```python +/// class Foo: +/// def bar(cls): +/// ... +/// +/// bar = staticmethod(bar) +/// ``` +/// +/// Use instead: +/// ```python +/// class Foo: +/// @staticmethod +/// def bar(cls): +/// ... +/// ``` +#[violation] +pub struct NoStaticmethodDecorator; + +impl AlwaysFixableViolation for NoStaticmethodDecorator { + #[derive_message_formats] + fn message(&self) -> String { + format!("Static method defined without decorator") + } + + fn fix_title(&self) -> String { + format!("Add @staticmethod decorator") + } +} + +enum MethodType { + Classmethod, + Staticmethod, +} + +/// PLR0202 +pub(crate) fn no_classmethod_decorator(checker: &mut Checker, class_def: &ast::StmtClassDef) { + get_undecorated_methods(checker, class_def, &MethodType::Classmethod); +} + +/// PLR0203 +pub(crate) fn no_staticmethod_decorator(checker: &mut Checker, class_def: &ast::StmtClassDef) { + get_undecorated_methods(checker, class_def, &MethodType::Staticmethod); +} + +fn get_undecorated_methods( + checker: &mut Checker, + class_def: &ast::StmtClassDef, + method_type: &MethodType, +) { + let mut explicit_decorator_calls: HashMap = HashMap::default(); + + let (method_name, diagnostic_type): (&str, DiagnosticKind) = match method_type { + MethodType::Classmethod => ("classmethod", NoClassmethodDecorator.into()), + MethodType::Staticmethod => ("staticmethod", NoStaticmethodDecorator.into()), + }; + + // gather all explicit *method calls + for stmt in &class_def.body { + if let Stmt::Assign(ast::StmtAssign { targets, value, .. }) = stmt { + if let Expr::Call(ast::ExprCall { + func, arguments, .. + }) = value.as_ref() + { + if let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() { + if id == method_name && checker.semantic().is_builtin(method_name) { + if arguments.args.len() != 1 { + continue; + } + + if targets.len() != 1 { + continue; + } + + let target_name = match targets.first() { + Some(Expr::Name(ast::ExprName { id, .. })) => id.to_string(), + _ => continue, + }; + + if let Expr::Name(ast::ExprName { id, .. }) = &arguments.args[0] { + if target_name == *id { + explicit_decorator_calls.insert(id.clone(), stmt.range()); + } + }; + } + } + } + }; + } + + if explicit_decorator_calls.is_empty() { + return; + }; + + for stmt in &class_def.body { + if let Stmt::FunctionDef(ast::StmtFunctionDef { + name, + decorator_list, + .. + }) = stmt + { + if !explicit_decorator_calls.contains_key(name.as_str()) { + continue; + }; + + // if we find the decorator we're looking for, skip + if decorator_list.iter().any(|decorator| { + if let Expr::Name(ast::ExprName { id, .. }) = &decorator.expression { + if id == method_name && checker.semantic().is_builtin(method_name) { + return true; + } + } + + false + }) { + continue; + } + + let mut diagnostic = Diagnostic::new( + diagnostic_type.clone(), + TextRange::new(stmt.range().start(), stmt.range().start()), + ); + + let indentation = indentation_at_offset(stmt.range().start(), checker.locator()); + + match indentation { + Some(indentation) => { + let range = &explicit_decorator_calls[name.as_str()]; + + // SAFETY: Ruff only supports formatting files <= 4GB + #[allow(clippy::cast_possible_truncation)] + diagnostic.set_fix(Fix::safe_edits( + Edit::insertion( + format!("@{method_name}\n{indentation}"), + stmt.range().start(), + ), + [Edit::deletion( + range.start() - TextSize::from(indentation.len() as u32), + range.end(), + )], + )); + checker.diagnostics.push(diagnostic); + } + None => { + continue; + } + }; + }; + } +} diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0202_no_method_decorator.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0202_no_method_decorator.py.snap new file mode 100644 index 0000000000000..d6fb47065915b --- /dev/null +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0202_no_method_decorator.py.snap @@ -0,0 +1,31 @@ +--- +source: crates/ruff_linter/src/rules/pylint/mod.rs +--- +no_method_decorator.py:9:5: PLR0202 [*] Class method defined without decorator + | + 7 | self.color = color + 8 | + 9 | def pick_colors(cls, *args): # [no-classmethod-decorator] + | PLR0202 +10 | """classmethod to pick fruit colors""" +11 | cls.COLORS = args + | + = help: Add @classmethod decorator + +ℹ Safe fix +6 6 | def __init__(self, color): +7 7 | self.color = color +8 8 | + 9 |+ @classmethod +9 10 | def pick_colors(cls, *args): # [no-classmethod-decorator] +10 11 | """classmethod to pick fruit colors""" +11 12 | cls.COLORS = args +12 13 | +13 |- pick_colors = classmethod(pick_colors) +14 14 | + 15 |+ +15 16 | def pick_one_color(): # [no-staticmethod-decorator] +16 17 | """staticmethod to pick one fruit color""" +17 18 | return choice(Fruit.COLORS) + + diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0203_no_method_decorator.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0203_no_method_decorator.py.snap new file mode 100644 index 0000000000000..a1fe06afafc1a --- /dev/null +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0203_no_method_decorator.py.snap @@ -0,0 +1,27 @@ +--- +source: crates/ruff_linter/src/rules/pylint/mod.rs +--- +no_method_decorator.py:15:5: PLR0203 [*] Static method defined without decorator + | +13 | pick_colors = classmethod(pick_colors) +14 | +15 | def pick_one_color(): # [no-staticmethod-decorator] + | PLR0203 +16 | """staticmethod to pick one fruit color""" +17 | return choice(Fruit.COLORS) + | + = help: Add @staticmethod decorator + +ℹ Safe fix +12 12 | +13 13 | pick_colors = classmethod(pick_colors) +14 14 | + 15 |+ @staticmethod +15 16 | def pick_one_color(): # [no-staticmethod-decorator] +16 17 | """staticmethod to pick one fruit color""" +17 18 | return choice(Fruit.COLORS) +18 19 | +19 |- pick_one_color = staticmethod(pick_one_color) + 20 |+ + + diff --git a/ruff.schema.json b/ruff.schema.json index cb37f44161c40..b8cac040eb644 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -3102,6 +3102,8 @@ "PLR0133", "PLR02", "PLR020", + "PLR0202", + "PLR0203", "PLR0206", "PLR04", "PLR040", From 70febb1862155e3e863c052926baea539768b637 Mon Sep 17 00:00:00 2001 From: Steve C Date: Thu, 30 Nov 2023 18:45:12 -0500 Subject: [PATCH 070/197] [pylint] - add `unnecessary-list-index-lookup` (`PLR1736`) + autofix (#7999) ## Summary Add [R1736](https://pylint.readthedocs.io/en/latest/user_guide/messages/refactor/unnecessary-list-index-lookup.html) along with the autofix See #970 ## Test Plan `cargo test` and manually --------- Co-authored-by: Zanie Blue --- .../pylint/unnecessary_list_index_lookup.py | 59 ++++ .../src/checkers/ast/analyze/expression.rs | 12 + .../src/checkers/ast/analyze/statement.rs | 3 + crates/ruff_linter/src/codes.rs | 1 + crates/ruff_linter/src/rules/pylint/mod.rs | 4 + .../ruff_linter/src/rules/pylint/rules/mod.rs | 2 + .../rules/unnecessary_list_index_lookup.rs | 280 ++++++++++++++++++ ...1736_unnecessary_list_index_lookup.py.snap | 185 ++++++++++++ ruff.schema.json | 2 + 9 files changed, 548 insertions(+) create mode 100644 crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_list_index_lookup.py create mode 100644 crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs create mode 100644 crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1736_unnecessary_list_index_lookup.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_list_index_lookup.py b/crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_list_index_lookup.py new file mode 100644 index 0000000000000..182e63cb7b913 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_list_index_lookup.py @@ -0,0 +1,59 @@ +import builtins + +letters = ["a", "b", "c"] + + +def fix_these(): + [letters[index] for index, letter in enumerate(letters)] # PLR1736 + {letters[index] for index, letter in enumerate(letters)} # PLR1736 + {letter: letters[index] for index, letter in enumerate(letters)} # PLR1736 + + for index, letter in enumerate(letters): + print(letters[index]) # PLR1736 + blah = letters[index] # PLR1736 + assert letters[index] == "d" # PLR1736 + + for index, letter in builtins.enumerate(letters): + print(letters[index]) # PLR1736 + blah = letters[index] # PLR1736 + assert letters[index] == "d" # PLR1736 + + +def dont_fix_these(): + # once there is an assignment to the sequence[index], we stop emitting diagnostics + for index, letter in enumerate(letters): + letters[index] = "d" # Ok + letters[index] += "e" # Ok + assert letters[index] == "de" # Ok + + # once there is an assignment to the index, we stop emitting diagnostics + for index, letter in enumerate(letters): + index += 1 # Ok + print(letters[index]) # Ok + + # once there is an assignment to the sequence, we stop emitting diagnostics + for index, letter in enumerate(letters): + letters = ["d", "e", "f"] # Ok + print(letters[index]) # Ok + + # once there is an deletion from or of the sequence or index, we stop emitting diagnostics + for index, letter in enumerate(letters): + del letters[index] # Ok + print(letters[index]) # Ok + for index, letter in enumerate(letters): + del letters # Ok + print(letters[index]) # Ok + for index, letter in enumerate(letters): + del index # Ok + print(letters[index]) # Ok + + +def value_intentionally_unused(): + [letters[index] for index, _ in enumerate(letters)] # Ok + {letters[index] for index, _ in enumerate(letters)} # Ok + {index: letters[index] for index, _ in enumerate(letters)} # Ok + + for index, _ in enumerate(letters): + print(letters[index]) # Ok + blah = letters[index] # Ok + letters[index] = "d" # Ok diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index f0e2cdb16bf73..0f5a7c3b60643 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -1330,6 +1330,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { range: _, }, ) => { + if checker.enabled(Rule::UnnecessaryListIndexLookup) { + pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr); + } if checker.enabled(Rule::UnnecessaryComprehension) { flake8_comprehensions::rules::unnecessary_list_set_comprehension( checker, expr, elt, generators, @@ -1354,6 +1357,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { range: _, }, ) => { + if checker.enabled(Rule::UnnecessaryListIndexLookup) { + pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr); + } if checker.enabled(Rule::UnnecessaryComprehension) { flake8_comprehensions::rules::unnecessary_list_set_comprehension( checker, expr, elt, generators, @@ -1377,6 +1383,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { generators, range: _, }) => { + if checker.enabled(Rule::UnnecessaryListIndexLookup) { + pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr); + } if checker.enabled(Rule::UnnecessaryComprehension) { flake8_comprehensions::rules::unnecessary_dict_comprehension( checker, expr, key, value, generators, @@ -1401,6 +1410,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { range: _, }, ) => { + if checker.enabled(Rule::UnnecessaryListIndexLookup) { + pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr); + } if checker.enabled(Rule::FunctionUsesLoopVariable) { flake8_bugbear::rules::function_uses_loop_variable(checker, &Node::Expr(expr)); } diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index addf24b8103c4..2208db8779b7d 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -1277,6 +1277,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if checker.enabled(Rule::UnnecessaryListCast) { perflint::rules::unnecessary_list_cast(checker, iter, body); } + if checker.enabled(Rule::UnnecessaryListIndexLookup) { + pylint::rules::unnecessary_list_index_lookup(checker, for_stmt); + } if !is_async { if checker.enabled(Rule::ReimplementedBuiltin) { flake8_simplify::rules::convert_for_loop_to_any_all(checker, stmt); diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index e127c26c68e35..8ee01e94a1f39 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -260,6 +260,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Pylint, "R1714") => (RuleGroup::Stable, rules::pylint::rules::RepeatedEqualityComparison), (Pylint, "R1706") => (RuleGroup::Preview, rules::pylint::rules::AndOrTernary), (Pylint, "R1722") => (RuleGroup::Stable, rules::pylint::rules::SysExitAlias), + (Pylint, "R1736") => (RuleGroup::Preview, rules::pylint::rules::UnnecessaryListIndexLookup), (Pylint, "R2004") => (RuleGroup::Stable, rules::pylint::rules::MagicValueComparison), (Pylint, "R5501") => (RuleGroup::Stable, rules::pylint::rules::CollapsibleElseIf), (Pylint, "R6201") => (RuleGroup::Preview, rules::pylint::rules::LiteralMembership), diff --git a/crates/ruff_linter/src/rules/pylint/mod.rs b/crates/ruff_linter/src/rules/pylint/mod.rs index b2ebed57d6edb..f8417646232ea 100644 --- a/crates/ruff_linter/src/rules/pylint/mod.rs +++ b/crates/ruff_linter/src/rules/pylint/mod.rs @@ -154,6 +154,10 @@ mod tests { Rule::RepeatedKeywordArgument, Path::new("repeated_keyword_argument.py") )] + #[test_case( + Rule::UnnecessaryListIndexLookup, + Path::new("unnecessary_list_index_lookup.py") + )] #[test_case(Rule::NoClassmethodDecorator, Path::new("no_method_decorator.py"))] #[test_case(Rule::NoStaticmethodDecorator, Path::new("no_method_decorator.py"))] fn rules(rule_code: Rule, path: &Path) -> Result<()> { diff --git a/crates/ruff_linter/src/rules/pylint/rules/mod.rs b/crates/ruff_linter/src/rules/pylint/rules/mod.rs index c332cdd243646..6497f9dcb7e27 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/mod.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/mod.rs @@ -64,6 +64,7 @@ pub(crate) use type_param_name_mismatch::*; pub(crate) use unexpected_special_method_signature::*; pub(crate) use unnecessary_direct_lambda_call::*; pub(crate) use unnecessary_lambda::*; +pub(crate) use unnecessary_list_index_lookup::*; pub(crate) use unspecified_encoding::*; pub(crate) use useless_else_on_loop::*; pub(crate) use useless_import_alias::*; @@ -138,6 +139,7 @@ mod type_param_name_mismatch; mod unexpected_special_method_signature; mod unnecessary_direct_lambda_call; mod unnecessary_lambda; +mod unnecessary_list_index_lookup; mod unspecified_encoding; mod useless_else_on_loop; mod useless_import_alias; diff --git a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs new file mode 100644 index 0000000000000..a668812ff0fd1 --- /dev/null +++ b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs @@ -0,0 +1,280 @@ +use ruff_python_ast::{self as ast, Expr, Stmt, StmtFor}; + +use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; +use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::visitor; +use ruff_python_ast::visitor::Visitor; +use ruff_text_size::TextRange; + +use crate::checkers::ast::Checker; + +/// ## What it does +/// Checks for access of a list item at the current index when using enumeration. +/// +/// ## Why is this bad? +/// It is more succinct to use the variable for the value at the current index which is already in scope from the iterator. +/// +/// ## Example +/// ```python +/// letters = ["a", "b", "c"] +/// +/// for index, letter in enumerate(letters): +/// print(letters[index]) +/// ``` +/// +/// Use instead: +/// ```python +/// letters = ["a", "b", "c"] +/// +/// for index, letter in enumerate(letters): +/// print(letter) +/// ``` +#[violation] +pub struct UnnecessaryListIndexLookup; + +impl AlwaysFixableViolation for UnnecessaryListIndexLookup { + #[derive_message_formats] + fn message(&self) -> String { + format!("Unnecessary lookup of list item by index") + } + + fn fix_title(&self) -> String { + format!("Use existing item variable instead") + } +} + +struct SubscriptVisitor<'a> { + sequence_name: &'a str, + index_name: &'a str, + diagnostic_ranges: Vec, + modified: bool, +} + +impl<'a> SubscriptVisitor<'a> { + fn new(sequence_name: &'a str, index_name: &'a str) -> Self { + Self { + sequence_name, + index_name, + diagnostic_ranges: Vec::new(), + modified: false, + } + } +} + +fn check_target_for_assignment(expr: &Expr, sequence_name: &str, index_name: &str) -> bool { + // if we see the sequence, a subscript, or the index being modified, we'll stop emitting diagnostics + match expr { + Expr::Name(ast::ExprName { id, .. }) => id == sequence_name || id == index_name, + Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => { + let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { + return false; + }; + if id == sequence_name { + let Expr::Name(ast::ExprName { id, .. }) = slice.as_ref() else { + return false; + }; + if id == index_name { + return true; + } + } + false + } + _ => false, + } +} + +impl<'a> Visitor<'_> for SubscriptVisitor<'a> { + fn visit_expr(&mut self, expr: &Expr) { + if self.modified { + return; + } + match expr { + Expr::Subscript(ast::ExprSubscript { + value, + slice, + range, + .. + }) => { + let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { + return; + }; + if id == self.sequence_name { + let Expr::Name(ast::ExprName { id, .. }) = slice.as_ref() else { + return; + }; + if id == self.index_name { + self.diagnostic_ranges.push(*range); + } + } + } + _ => visitor::walk_expr(self, expr), + } + } + + fn visit_stmt(&mut self, stmt: &Stmt) { + if self.modified { + return; + } + match stmt { + Stmt::Assign(ast::StmtAssign { targets, value, .. }) => { + self.modified = targets.iter().any(|target| { + check_target_for_assignment(target, self.sequence_name, self.index_name) + }); + self.visit_expr(value); + } + Stmt::AnnAssign(ast::StmtAnnAssign { target, value, .. }) => { + if let Some(value) = value { + self.modified = + check_target_for_assignment(target, self.sequence_name, self.index_name); + self.visit_expr(value); + } + } + Stmt::AugAssign(ast::StmtAugAssign { target, value, .. }) => { + self.modified = + check_target_for_assignment(target, self.sequence_name, self.index_name); + self.visit_expr(value); + } + Stmt::Delete(ast::StmtDelete { targets, .. }) => { + self.modified = targets.iter().any(|target| match target { + Expr::Name(ast::ExprName { id, .. }) => { + id == self.sequence_name || id == self.index_name + } + Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => { + let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { + return false; + }; + if id == self.sequence_name { + let Expr::Name(ast::ExprName { id, .. }) = slice.as_ref() else { + return false; + }; + if id == self.index_name { + return true; + } + } + false + } + _ => false, + }); + } + _ => visitor::walk_stmt(self, stmt), + } + } +} + +/// PLR1736 +pub(crate) fn unnecessary_list_index_lookup(checker: &mut Checker, stmt_for: &StmtFor) { + let Some((sequence, index_name, value_name)) = + enumerate_items(checker, &stmt_for.iter, &stmt_for.target) + else { + return; + }; + + let mut visitor = SubscriptVisitor::new(&sequence, &index_name); + + visitor.visit_body(&stmt_for.body); + visitor.visit_body(&stmt_for.orelse); + + for range in visitor.diagnostic_ranges { + let mut diagnostic = Diagnostic::new(UnnecessaryListIndexLookup, range); + + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + value_name.clone(), + range, + ))); + + checker.diagnostics.push(diagnostic); + } +} + +/// PLR1736 +pub(crate) fn unnecessary_list_index_lookup_comprehension(checker: &mut Checker, expr: &Expr) { + match expr { + Expr::GeneratorExp(ast::ExprGeneratorExp { + elt, generators, .. + }) + | Expr::DictComp(ast::ExprDictComp { + value: elt, + generators, + .. + }) + | Expr::SetComp(ast::ExprSetComp { + elt, generators, .. + }) + | Expr::ListComp(ast::ExprListComp { + elt, generators, .. + }) => { + for comp in generators { + let Some((sequence, index_name, value_name)) = + enumerate_items(checker, &comp.iter, &comp.target) + else { + return; + }; + + let mut visitor = SubscriptVisitor::new(&sequence, &index_name); + + visitor.visit_expr(elt.as_ref()); + + for range in visitor.diagnostic_ranges { + let mut diagnostic = Diagnostic::new(UnnecessaryListIndexLookup, range); + + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + value_name.clone(), + range, + ))); + + checker.diagnostics.push(diagnostic); + } + } + } + _ => (), + } +} + +fn enumerate_items( + checker: &mut Checker, + call_expr: &Expr, + tuple_expr: &Expr, +) -> Option<(String, String, String)> { + let ast::ExprCall { + func, arguments, .. + } = call_expr.as_call_expr()?; + + // Check that the function is the `enumerate` builtin. + let Some(call_path) = checker.semantic().resolve_call_path(func.as_ref()) else { + return None; + }; + + match call_path.as_slice() { + ["", "enumerate"] => (), + ["builtins", "enumerate"] => (), + _ => return None, + } + + let Expr::Tuple(ast::ExprTuple { elts, .. }) = tuple_expr else { + return None; + }; + let [index, value] = elts.as_slice() else { + return None; + }; + + // Grab the variable names + let Expr::Name(ast::ExprName { id: index_name, .. }) = index else { + return None; + }; + + let Expr::Name(ast::ExprName { id: value_name, .. }) = value else { + return None; + }; + + // If either of the variable names are intentionally ignored by naming them `_`, then don't emit + if index_name == "_" || value_name == "_" { + return None; + } + + // Get the first argument of the enumerate call + let Some(Expr::Name(ast::ExprName { id: sequence, .. })) = arguments.args.first() else { + return None; + }; + + Some((sequence.clone(), index_name.clone(), value_name.clone())) +} diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1736_unnecessary_list_index_lookup.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1736_unnecessary_list_index_lookup.py.snap new file mode 100644 index 0000000000000..aab105471a4c7 --- /dev/null +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1736_unnecessary_list_index_lookup.py.snap @@ -0,0 +1,185 @@ +--- +source: crates/ruff_linter/src/rules/pylint/mod.rs +--- +unnecessary_list_index_lookup.py:7:6: PLR1736 [*] Unnecessary lookup of list item by index + | +6 | def fix_these(): +7 | [letters[index] for index, letter in enumerate(letters)] # PLR1736 + | ^^^^^^^^^^^^^^ PLR1736 +8 | {letters[index] for index, letter in enumerate(letters)} # PLR1736 +9 | {letter: letters[index] for index, letter in enumerate(letters)} # PLR1736 + | + = help: Use existing item variable instead + +ℹ Safe fix +4 4 | +5 5 | +6 6 | def fix_these(): +7 |- [letters[index] for index, letter in enumerate(letters)] # PLR1736 + 7 |+ [letter for index, letter in enumerate(letters)] # PLR1736 +8 8 | {letters[index] for index, letter in enumerate(letters)} # PLR1736 +9 9 | {letter: letters[index] for index, letter in enumerate(letters)} # PLR1736 +10 10 | + +unnecessary_list_index_lookup.py:8:6: PLR1736 [*] Unnecessary lookup of list item by index + | +6 | def fix_these(): +7 | [letters[index] for index, letter in enumerate(letters)] # PLR1736 +8 | {letters[index] for index, letter in enumerate(letters)} # PLR1736 + | ^^^^^^^^^^^^^^ PLR1736 +9 | {letter: letters[index] for index, letter in enumerate(letters)} # PLR1736 + | + = help: Use existing item variable instead + +ℹ Safe fix +5 5 | +6 6 | def fix_these(): +7 7 | [letters[index] for index, letter in enumerate(letters)] # PLR1736 +8 |- {letters[index] for index, letter in enumerate(letters)} # PLR1736 + 8 |+ {letter for index, letter in enumerate(letters)} # PLR1736 +9 9 | {letter: letters[index] for index, letter in enumerate(letters)} # PLR1736 +10 10 | +11 11 | for index, letter in enumerate(letters): + +unnecessary_list_index_lookup.py:9:14: PLR1736 [*] Unnecessary lookup of list item by index + | + 7 | [letters[index] for index, letter in enumerate(letters)] # PLR1736 + 8 | {letters[index] for index, letter in enumerate(letters)} # PLR1736 + 9 | {letter: letters[index] for index, letter in enumerate(letters)} # PLR1736 + | ^^^^^^^^^^^^^^ PLR1736 +10 | +11 | for index, letter in enumerate(letters): + | + = help: Use existing item variable instead + +ℹ Safe fix +6 6 | def fix_these(): +7 7 | [letters[index] for index, letter in enumerate(letters)] # PLR1736 +8 8 | {letters[index] for index, letter in enumerate(letters)} # PLR1736 +9 |- {letter: letters[index] for index, letter in enumerate(letters)} # PLR1736 + 9 |+ {letter: letter for index, letter in enumerate(letters)} # PLR1736 +10 10 | +11 11 | for index, letter in enumerate(letters): +12 12 | print(letters[index]) # PLR1736 + +unnecessary_list_index_lookup.py:12:15: PLR1736 [*] Unnecessary lookup of list item by index + | +11 | for index, letter in enumerate(letters): +12 | print(letters[index]) # PLR1736 + | ^^^^^^^^^^^^^^ PLR1736 +13 | blah = letters[index] # PLR1736 +14 | assert letters[index] == "d" # PLR1736 + | + = help: Use existing item variable instead + +ℹ Safe fix +9 9 | {letter: letters[index] for index, letter in enumerate(letters)} # PLR1736 +10 10 | +11 11 | for index, letter in enumerate(letters): +12 |- print(letters[index]) # PLR1736 + 12 |+ print(letter) # PLR1736 +13 13 | blah = letters[index] # PLR1736 +14 14 | assert letters[index] == "d" # PLR1736 +15 15 | + +unnecessary_list_index_lookup.py:13:16: PLR1736 [*] Unnecessary lookup of list item by index + | +11 | for index, letter in enumerate(letters): +12 | print(letters[index]) # PLR1736 +13 | blah = letters[index] # PLR1736 + | ^^^^^^^^^^^^^^ PLR1736 +14 | assert letters[index] == "d" # PLR1736 + | + = help: Use existing item variable instead + +ℹ Safe fix +10 10 | +11 11 | for index, letter in enumerate(letters): +12 12 | print(letters[index]) # PLR1736 +13 |- blah = letters[index] # PLR1736 + 13 |+ blah = letter # PLR1736 +14 14 | assert letters[index] == "d" # PLR1736 +15 15 | +16 16 | for index, letter in builtins.enumerate(letters): + +unnecessary_list_index_lookup.py:14:16: PLR1736 [*] Unnecessary lookup of list item by index + | +12 | print(letters[index]) # PLR1736 +13 | blah = letters[index] # PLR1736 +14 | assert letters[index] == "d" # PLR1736 + | ^^^^^^^^^^^^^^ PLR1736 +15 | +16 | for index, letter in builtins.enumerate(letters): + | + = help: Use existing item variable instead + +ℹ Safe fix +11 11 | for index, letter in enumerate(letters): +12 12 | print(letters[index]) # PLR1736 +13 13 | blah = letters[index] # PLR1736 +14 |- assert letters[index] == "d" # PLR1736 + 14 |+ assert letter == "d" # PLR1736 +15 15 | +16 16 | for index, letter in builtins.enumerate(letters): +17 17 | print(letters[index]) # PLR1736 + +unnecessary_list_index_lookup.py:17:15: PLR1736 [*] Unnecessary lookup of list item by index + | +16 | for index, letter in builtins.enumerate(letters): +17 | print(letters[index]) # PLR1736 + | ^^^^^^^^^^^^^^ PLR1736 +18 | blah = letters[index] # PLR1736 +19 | assert letters[index] == "d" # PLR1736 + | + = help: Use existing item variable instead + +ℹ Safe fix +14 14 | assert letters[index] == "d" # PLR1736 +15 15 | +16 16 | for index, letter in builtins.enumerate(letters): +17 |- print(letters[index]) # PLR1736 + 17 |+ print(letter) # PLR1736 +18 18 | blah = letters[index] # PLR1736 +19 19 | assert letters[index] == "d" # PLR1736 +20 20 | + +unnecessary_list_index_lookup.py:18:16: PLR1736 [*] Unnecessary lookup of list item by index + | +16 | for index, letter in builtins.enumerate(letters): +17 | print(letters[index]) # PLR1736 +18 | blah = letters[index] # PLR1736 + | ^^^^^^^^^^^^^^ PLR1736 +19 | assert letters[index] == "d" # PLR1736 + | + = help: Use existing item variable instead + +ℹ Safe fix +15 15 | +16 16 | for index, letter in builtins.enumerate(letters): +17 17 | print(letters[index]) # PLR1736 +18 |- blah = letters[index] # PLR1736 + 18 |+ blah = letter # PLR1736 +19 19 | assert letters[index] == "d" # PLR1736 +20 20 | +21 21 | + +unnecessary_list_index_lookup.py:19:16: PLR1736 [*] Unnecessary lookup of list item by index + | +17 | print(letters[index]) # PLR1736 +18 | blah = letters[index] # PLR1736 +19 | assert letters[index] == "d" # PLR1736 + | ^^^^^^^^^^^^^^ PLR1736 + | + = help: Use existing item variable instead + +ℹ Safe fix +16 16 | for index, letter in builtins.enumerate(letters): +17 17 | print(letters[index]) # PLR1736 +18 18 | blah = letters[index] # PLR1736 +19 |- assert letters[index] == "d" # PLR1736 + 19 |+ assert letter == "d" # PLR1736 +20 20 | +21 21 | +22 22 | def dont_fix_these(): + + diff --git a/ruff.schema.json b/ruff.schema.json index b8cac040eb644..4f39eaeb420e0 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -3128,6 +3128,8 @@ "PLR1714", "PLR172", "PLR1722", + "PLR173", + "PLR1736", "PLR2", "PLR20", "PLR200", From c1dc4a60bed4177c12e9718fc5c28d2c87327a4e Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 30 Nov 2023 19:53:26 -0500 Subject: [PATCH 071/197] Apply some minor changes to `unnecessary-list-index-lookup` (#8932) ## Summary I was late in reviewing this but found a few things I wanted to tweak. No functional changes. --- .../rules/unnecessary_list_index_lookup.rs | 340 +++++++++--------- ...1736_unnecessary_list_index_lookup.py.snap | 18 +- 2 files changed, 171 insertions(+), 187 deletions(-) diff --git a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs index a668812ff0fd1..17a42b29e25a2 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs @@ -4,15 +4,18 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::visitor; use ruff_python_ast::visitor::Visitor; +use ruff_python_semantic::SemanticModel; use ruff_text_size::TextRange; use crate::checkers::ast::Checker; /// ## What it does -/// Checks for access of a list item at the current index when using enumeration. +/// Checks for index-based list accesses during `enumerate` iterations. /// /// ## Why is this bad? -/// It is more succinct to use the variable for the value at the current index which is already in scope from the iterator. +/// When iterating over a list with `enumerate`, the current item is already +/// available alongside its index. Using the index to look up the item is +/// unnecessary. /// /// ## Example /// ```python @@ -39,10 +42,127 @@ impl AlwaysFixableViolation for UnnecessaryListIndexLookup { } fn fix_title(&self) -> String { - format!("Use existing item variable instead") + format!("Use existing variable") } } +/// PLR1736 +pub(crate) fn unnecessary_list_index_lookup(checker: &mut Checker, stmt_for: &StmtFor) { + let Some((sequence, index_name, value_name)) = + enumerate_items(&stmt_for.iter, &stmt_for.target, checker.semantic()) + else { + return; + }; + + let ranges = { + let mut visitor = SubscriptVisitor::new(sequence, index_name); + visitor.visit_body(&stmt_for.body); + visitor.visit_body(&stmt_for.orelse); + visitor.diagnostic_ranges + }; + + for range in ranges { + let mut diagnostic = Diagnostic::new(UnnecessaryListIndexLookup, range); + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + value_name.to_string(), + range, + ))); + checker.diagnostics.push(diagnostic); + } +} + +/// PLR1736 +pub(crate) fn unnecessary_list_index_lookup_comprehension(checker: &mut Checker, expr: &Expr) { + let (Expr::GeneratorExp(ast::ExprGeneratorExp { + elt, generators, .. + }) + | Expr::DictComp(ast::ExprDictComp { + value: elt, + generators, + .. + }) + | Expr::SetComp(ast::ExprSetComp { + elt, generators, .. + }) + | Expr::ListComp(ast::ExprListComp { + elt, generators, .. + })) = expr + else { + return; + }; + + for comp in generators { + let Some((sequence, index_name, value_name)) = + enumerate_items(&comp.iter, &comp.target, checker.semantic()) + else { + return; + }; + + let ranges = { + let mut visitor = SubscriptVisitor::new(sequence, index_name); + visitor.visit_expr(elt.as_ref()); + visitor.diagnostic_ranges + }; + + for range in ranges { + let mut diagnostic = Diagnostic::new(UnnecessaryListIndexLookup, range); + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + value_name.to_string(), + range, + ))); + checker.diagnostics.push(diagnostic); + } + } +} + +fn enumerate_items<'a>( + call_expr: &'a Expr, + tuple_expr: &'a Expr, + semantic: &SemanticModel, +) -> Option<(&'a str, &'a str, &'a str)> { + let ast::ExprCall { + func, arguments, .. + } = call_expr.as_call_expr()?; + + // Check that the function is the `enumerate` builtin. + if !semantic + .resolve_call_path(func.as_ref()) + .is_some_and(|call_path| matches!(call_path.as_slice(), ["builtins" | "", "enumerate"])) + { + return None; + } + + let Expr::Tuple(ast::ExprTuple { elts, .. }) = tuple_expr else { + return None; + }; + let [index, value] = elts.as_slice() else { + return None; + }; + + // Grab the variable names. + let Expr::Name(ast::ExprName { id: index_name, .. }) = index else { + return None; + }; + + let Expr::Name(ast::ExprName { id: value_name, .. }) = value else { + return None; + }; + + // If either of the variable names are intentionally ignored by naming them `_`, then don't + // emit. + if index_name == "_" || value_name == "_" { + return None; + } + + // Get the first argument of the enumerate call. + let Some(Expr::Name(ast::ExprName { id: sequence, .. })) = arguments.args.first() else { + return None; + }; + + Some((sequence, index_name, value_name)) +} + +#[derive(Debug)] struct SubscriptVisitor<'a> { sequence_name: &'a str, index_name: &'a str, @@ -61,220 +181,84 @@ impl<'a> SubscriptVisitor<'a> { } } -fn check_target_for_assignment(expr: &Expr, sequence_name: &str, index_name: &str) -> bool { - // if we see the sequence, a subscript, or the index being modified, we'll stop emitting diagnostics - match expr { - Expr::Name(ast::ExprName { id, .. }) => id == sequence_name || id == index_name, - Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => { - let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { - return false; - }; - if id == sequence_name { - let Expr::Name(ast::ExprName { id, .. }) = slice.as_ref() else { - return false; - }; - if id == index_name { - return true; - } - } - false - } - _ => false, - } -} - -impl<'a> Visitor<'_> for SubscriptVisitor<'a> { - fn visit_expr(&mut self, expr: &Expr) { - if self.modified { - return; - } +impl SubscriptVisitor<'_> { + fn is_assignment(&self, expr: &Expr) -> bool { + // If we see the sequence, a subscript, or the index being modified, we'll stop emitting + // diagnostics. match expr { - Expr::Subscript(ast::ExprSubscript { - value, - slice, - range, - .. - }) => { + Expr::Name(ast::ExprName { id, .. }) => { + id == self.sequence_name || id == self.index_name + } + Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => { let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { - return; + return false; }; if id == self.sequence_name { let Expr::Name(ast::ExprName { id, .. }) = slice.as_ref() else { - return; + return false; }; if id == self.index_name { - self.diagnostic_ranges.push(*range); + return true; } } + false } - _ => visitor::walk_expr(self, expr), + _ => false, } } +} +impl<'a> Visitor<'_> for SubscriptVisitor<'a> { fn visit_stmt(&mut self, stmt: &Stmt) { if self.modified { return; } match stmt { Stmt::Assign(ast::StmtAssign { targets, value, .. }) => { - self.modified = targets.iter().any(|target| { - check_target_for_assignment(target, self.sequence_name, self.index_name) - }); + self.modified = targets.iter().any(|target| self.is_assignment(target)); self.visit_expr(value); } Stmt::AnnAssign(ast::StmtAnnAssign { target, value, .. }) => { if let Some(value) = value { - self.modified = - check_target_for_assignment(target, self.sequence_name, self.index_name); + self.modified = self.is_assignment(target); self.visit_expr(value); } } Stmt::AugAssign(ast::StmtAugAssign { target, value, .. }) => { - self.modified = - check_target_for_assignment(target, self.sequence_name, self.index_name); + self.modified = self.is_assignment(target); self.visit_expr(value); } Stmt::Delete(ast::StmtDelete { targets, .. }) => { - self.modified = targets.iter().any(|target| match target { - Expr::Name(ast::ExprName { id, .. }) => { - id == self.sequence_name || id == self.index_name - } - Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => { - let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { - return false; - }; - if id == self.sequence_name { - let Expr::Name(ast::ExprName { id, .. }) = slice.as_ref() else { - return false; - }; - if id == self.index_name { - return true; - } - } - false - } - _ => false, - }); + self.modified = targets.iter().any(|target| self.is_assignment(target)); } _ => visitor::walk_stmt(self, stmt), } } -} - -/// PLR1736 -pub(crate) fn unnecessary_list_index_lookup(checker: &mut Checker, stmt_for: &StmtFor) { - let Some((sequence, index_name, value_name)) = - enumerate_items(checker, &stmt_for.iter, &stmt_for.target) - else { - return; - }; - - let mut visitor = SubscriptVisitor::new(&sequence, &index_name); - - visitor.visit_body(&stmt_for.body); - visitor.visit_body(&stmt_for.orelse); - - for range in visitor.diagnostic_ranges { - let mut diagnostic = Diagnostic::new(UnnecessaryListIndexLookup, range); - - diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - value_name.clone(), - range, - ))); - - checker.diagnostics.push(diagnostic); - } -} -/// PLR1736 -pub(crate) fn unnecessary_list_index_lookup_comprehension(checker: &mut Checker, expr: &Expr) { - match expr { - Expr::GeneratorExp(ast::ExprGeneratorExp { - elt, generators, .. - }) - | Expr::DictComp(ast::ExprDictComp { - value: elt, - generators, - .. - }) - | Expr::SetComp(ast::ExprSetComp { - elt, generators, .. - }) - | Expr::ListComp(ast::ExprListComp { - elt, generators, .. - }) => { - for comp in generators { - let Some((sequence, index_name, value_name)) = - enumerate_items(checker, &comp.iter, &comp.target) - else { + fn visit_expr(&mut self, expr: &Expr) { + if self.modified { + return; + } + match expr { + Expr::Subscript(ast::ExprSubscript { + value, + slice, + range, + .. + }) => { + let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { return; }; - - let mut visitor = SubscriptVisitor::new(&sequence, &index_name); - - visitor.visit_expr(elt.as_ref()); - - for range in visitor.diagnostic_ranges { - let mut diagnostic = Diagnostic::new(UnnecessaryListIndexLookup, range); - - diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - value_name.clone(), - range, - ))); - - checker.diagnostics.push(diagnostic); + if id == self.sequence_name { + let Expr::Name(ast::ExprName { id, .. }) = slice.as_ref() else { + return; + }; + if id == self.index_name { + self.diagnostic_ranges.push(*range); + } } } + _ => visitor::walk_expr(self, expr), } - _ => (), - } -} - -fn enumerate_items( - checker: &mut Checker, - call_expr: &Expr, - tuple_expr: &Expr, -) -> Option<(String, String, String)> { - let ast::ExprCall { - func, arguments, .. - } = call_expr.as_call_expr()?; - - // Check that the function is the `enumerate` builtin. - let Some(call_path) = checker.semantic().resolve_call_path(func.as_ref()) else { - return None; - }; - - match call_path.as_slice() { - ["", "enumerate"] => (), - ["builtins", "enumerate"] => (), - _ => return None, } - - let Expr::Tuple(ast::ExprTuple { elts, .. }) = tuple_expr else { - return None; - }; - let [index, value] = elts.as_slice() else { - return None; - }; - - // Grab the variable names - let Expr::Name(ast::ExprName { id: index_name, .. }) = index else { - return None; - }; - - let Expr::Name(ast::ExprName { id: value_name, .. }) = value else { - return None; - }; - - // If either of the variable names are intentionally ignored by naming them `_`, then don't emit - if index_name == "_" || value_name == "_" { - return None; - } - - // Get the first argument of the enumerate call - let Some(Expr::Name(ast::ExprName { id: sequence, .. })) = arguments.args.first() else { - return None; - }; - - Some((sequence.clone(), index_name.clone(), value_name.clone())) } diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1736_unnecessary_list_index_lookup.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1736_unnecessary_list_index_lookup.py.snap index aab105471a4c7..8e4d22472df3d 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1736_unnecessary_list_index_lookup.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1736_unnecessary_list_index_lookup.py.snap @@ -9,7 +9,7 @@ unnecessary_list_index_lookup.py:7:6: PLR1736 [*] Unnecessary lookup of list ite 8 | {letters[index] for index, letter in enumerate(letters)} # PLR1736 9 | {letter: letters[index] for index, letter in enumerate(letters)} # PLR1736 | - = help: Use existing item variable instead + = help: Use existing variable ℹ Safe fix 4 4 | @@ -29,7 +29,7 @@ unnecessary_list_index_lookup.py:8:6: PLR1736 [*] Unnecessary lookup of list ite | ^^^^^^^^^^^^^^ PLR1736 9 | {letter: letters[index] for index, letter in enumerate(letters)} # PLR1736 | - = help: Use existing item variable instead + = help: Use existing variable ℹ Safe fix 5 5 | @@ -50,7 +50,7 @@ unnecessary_list_index_lookup.py:9:14: PLR1736 [*] Unnecessary lookup of list it 10 | 11 | for index, letter in enumerate(letters): | - = help: Use existing item variable instead + = help: Use existing variable ℹ Safe fix 6 6 | def fix_these(): @@ -70,7 +70,7 @@ unnecessary_list_index_lookup.py:12:15: PLR1736 [*] Unnecessary lookup of list i 13 | blah = letters[index] # PLR1736 14 | assert letters[index] == "d" # PLR1736 | - = help: Use existing item variable instead + = help: Use existing variable ℹ Safe fix 9 9 | {letter: letters[index] for index, letter in enumerate(letters)} # PLR1736 @@ -90,7 +90,7 @@ unnecessary_list_index_lookup.py:13:16: PLR1736 [*] Unnecessary lookup of list i | ^^^^^^^^^^^^^^ PLR1736 14 | assert letters[index] == "d" # PLR1736 | - = help: Use existing item variable instead + = help: Use existing variable ℹ Safe fix 10 10 | @@ -111,7 +111,7 @@ unnecessary_list_index_lookup.py:14:16: PLR1736 [*] Unnecessary lookup of list i 15 | 16 | for index, letter in builtins.enumerate(letters): | - = help: Use existing item variable instead + = help: Use existing variable ℹ Safe fix 11 11 | for index, letter in enumerate(letters): @@ -131,7 +131,7 @@ unnecessary_list_index_lookup.py:17:15: PLR1736 [*] Unnecessary lookup of list i 18 | blah = letters[index] # PLR1736 19 | assert letters[index] == "d" # PLR1736 | - = help: Use existing item variable instead + = help: Use existing variable ℹ Safe fix 14 14 | assert letters[index] == "d" # PLR1736 @@ -151,7 +151,7 @@ unnecessary_list_index_lookup.py:18:16: PLR1736 [*] Unnecessary lookup of list i | ^^^^^^^^^^^^^^ PLR1736 19 | assert letters[index] == "d" # PLR1736 | - = help: Use existing item variable instead + = help: Use existing variable ℹ Safe fix 15 15 | @@ -170,7 +170,7 @@ unnecessary_list_index_lookup.py:19:16: PLR1736 [*] Unnecessary lookup of list i 19 | assert letters[index] == "d" # PLR1736 | ^^^^^^^^^^^^^^ PLR1736 | - = help: Use existing item variable instead + = help: Use existing variable ℹ Safe fix 16 16 | for index, letter in builtins.enumerate(letters): From f06c5dc896a9b751620750e5f449f95ffd84bbc7 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Thu, 30 Nov 2023 19:42:46 -0600 Subject: [PATCH 072/197] Use correct range for `TRIO115` fix (#8933) ## Summary This PR fixes the bug where the autofix for `TRIO115` was taking the entire arguments range for the fix which included the parenthesis as well. This means that the fix would remove the arguments and the parenthesis. The fix is to use the correct range. fixes: #8713 ## Test Plan Update existing snapshots :) --- .../src/rules/flake8_trio/rules/zero_sleep_call.rs | 2 +- ..._rules__flake8_trio__tests__TRIO115_TRIO115.py.snap | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs b/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs index aa583d0d67eaa..6ddd3d572d053 100644 --- a/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs +++ b/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs @@ -103,7 +103,7 @@ pub(crate) fn zero_sleep_call(checker: &mut Checker, call: &ExprCall) { )?; let reference_edit = Edit::range_replacement(format!("{binding}.checkpoint"), call.func.range()); - let arg_edit = Edit::range_deletion(call.arguments.range); + let arg_edit = Edit::range_deletion(arg.range()); Ok(Fix::safe_edits(import_edit, [reference_edit, arg_edit])) }); checker.diagnostics.push(diagnostic); diff --git a/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap b/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap index 9e2fa6d2b5f5f..6b4c34efd1197 100644 --- a/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap +++ b/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap @@ -17,7 +17,7 @@ TRIO115.py:5:11: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.s 3 3 | from trio import sleep 4 4 | 5 |- await trio.sleep(0) # TRIO115 - 5 |+ await trio.lowlevel.checkpoint # TRIO115 + 5 |+ await trio.lowlevel.checkpoint() # TRIO115 6 6 | await trio.sleep(1) # OK 7 7 | await trio.sleep(0, 1) # OK 8 8 | await trio.sleep(...) # OK @@ -38,7 +38,7 @@ TRIO115.py:11:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.s 9 9 | await trio.sleep() # OK 10 10 | 11 |- trio.sleep(0) # TRIO115 - 11 |+ trio.lowlevel.checkpoint # TRIO115 + 11 |+ trio.lowlevel.checkpoint() # TRIO115 12 12 | foo = 0 13 13 | trio.sleep(foo) # TRIO115 14 14 | trio.sleep(1) # OK @@ -59,7 +59,7 @@ TRIO115.py:13:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.s 11 11 | trio.sleep(0) # TRIO115 12 12 | foo = 0 13 |- trio.sleep(foo) # TRIO115 - 13 |+ trio.lowlevel.checkpoint # TRIO115 + 13 |+ trio.lowlevel.checkpoint() # TRIO115 14 14 | trio.sleep(1) # OK 15 15 | time.sleep(0) # OK 16 16 | @@ -80,7 +80,7 @@ TRIO115.py:17:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.s 15 15 | time.sleep(0) # OK 16 16 | 17 |- sleep(0) # TRIO115 - 17 |+ trio.lowlevel.checkpoint # TRIO115 + 17 |+ trio.lowlevel.checkpoint() # TRIO115 18 18 | 19 19 | bar = "bar" 20 20 | trio.sleep(bar) @@ -102,6 +102,6 @@ TRIO115.py:30:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.s 28 28 | 29 29 | def func(): 30 |- sleep(0) # TRIO115 - 30 |+ lowlevel.checkpoint # TRIO115 + 30 |+ lowlevel.checkpoint() # TRIO115 From 019d9aebe9742607cbac7d64bec61d3ab1dd8bd9 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 30 Nov 2023 21:11:14 -0500 Subject: [PATCH 073/197] Implement multiline dictionary and list hugging for preview style (#8293) ## Summary This PR implement's Black's new single-argument hugging for lists, sets, and dictionaries under preview style. For example, this: ```python foo( [ 1, 2, 3, ] ) ``` Would instead now be formatted as: ```python foo([ 1, 2, 3, ]) ``` A couple notes: - This doesn't apply when the argument has a magic trailing comma. - This _does_ apply when the argument is starred or double-starred. - We don't apply this when there are comments before or after the argument, though Black does in some cases (and moves the comments outside the call parentheses). It doesn't say it in the originating PR (https://github.com/psf/black/pull/3964), but I think this also applies to parenthesized expressions? At least, it does in my testing of preview vs. stable, though it's possible that behavior predated the linked PR. See: #8279. ## Test Plan Before: | project | similarity index | total files | changed files | |----------------|------------------:|------------------:|------------------:| | cpython | 0.75804 | 1799 | 1648 | | django | 0.99984 | 2772 | 34 | | home-assistant | 0.99963 | 10596 | 146 | | poetry | 0.99925 | 317 | 12 | | transformers | 0.99967 | 2657 | 322 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99980 | 3669 | 18 | | warehouse | 0.99977 | 654 | 13 | | zulip | 0.99970 | 1459 | 21 | After: | project | similarity index | total files | changed files | |----------------|------------------:|------------------:|------------------:| | cpython | 0.75804 | 1799 | 1648 | | django | 0.99984 | 2772 | 34 | | home-assistant | 0.99963 | 10596 | 146 | | poetry | 0.96215 | 317 | 34 | | transformers | 0.99967 | 2657 | 322 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99980 | 3669 | 18 | | warehouse | 0.99977 | 654 | 13 | | zulip | 0.99970 | 1459 | 21 | --- ...th_braces_and_square_brackets.options.json | 3 + ..._parens_with_braces_and_square_brackets.py | 141 ++++ ..._with_braces_and_square_brackets.py.expect | 159 ++++ .../test/fixtures/ruff/expression/hug.py | 153 ++++ crates/ruff_python_formatter/src/builders.rs | 27 +- .../src/expression/mod.rs | 95 ++- .../src/expression/parentheses.rs | 21 +- .../src/other/arguments.rs | 70 +- ...ns_with_braces_and_square_brackets.py.snap | 543 +++++++++++++ .../snapshots/format@expression__hug.py.snap | 752 ++++++++++++++++++ ...t@expression__split_empty_brackets.py.snap | 20 + 11 files changed, 1969 insertions(+), 15 deletions(-) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/preview_hug_parens_with_braces_and_square_brackets.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/preview_hug_parens_with_braces_and_square_brackets.py create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/preview_hug_parens_with_braces_and_square_brackets.py.expect create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/hug.py create mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__preview_hug_parens_with_braces_and_square_brackets.py.snap create mode 100644 crates/ruff_python_formatter/tests/snapshots/format@expression__hug.py.snap diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/preview_hug_parens_with_braces_and_square_brackets.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/preview_hug_parens_with_braces_and_square_brackets.options.json new file mode 100644 index 0000000000000..c106a9c8f36ea --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/preview_hug_parens_with_braces_and_square_brackets.options.json @@ -0,0 +1,3 @@ +{ + "preview": "enabled" +} diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/preview_hug_parens_with_braces_and_square_brackets.py b/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/preview_hug_parens_with_braces_and_square_brackets.py new file mode 100644 index 0000000000000..eff37f23c008b --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/preview_hug_parens_with_braces_and_square_brackets.py @@ -0,0 +1,141 @@ +def foo_brackets(request): + return JsonResponse( + { + "var_1": foo, + "var_2": bar, + } + ) + +def foo_square_brackets(request): + return JsonResponse( + [ + "var_1", + "var_2", + ] + ) + +func({"a": 37, "b": 42, "c": 927, "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111}) + +func(["random_string_number_one","random_string_number_two","random_string_number_three","random_string_number_four"]) + +func( + { + # expand me + 'a':37, + 'b':42, + 'c':927 + } +) + +func( + [ + 'a', + 'b', + 'c', + ] +) + +func( + [ + 'a', + 'b', + 'c', + ], +) + +func( # a + [ # b + "c", # c + "d", # d + "e", # e + ] # f +) # g + +func( # a + { # b + "c": 1, # c + "d": 2, # d + "e": 3, # e + } # f +) # g + +func( + # preserve me + [ + "c", + "d", + "e", + ] +) + +func( + [ # preserve me but hug brackets + "c", + "d", + "e", + ] +) + +func( + [ + # preserve me but hug brackets + "c", + "d", + "e", + ] +) + +func( + [ + "c", + # preserve me but hug brackets + "d", + "e", + ] +) + +func( + [ + "c", + "d", + "e", + # preserve me but hug brackets + ] +) + +func( + [ + "c", + "d", + "e", + ] # preserve me but hug brackets +) + +func( + [ + "c", + "d", + "e", + ] + # preserve me +) + +func([x for x in "short line"]) +func([x for x in "long line long line long line long line long line long line long line"]) +func([x for x in [x for x in "long line long line long line long line long line long line long line"]]) + +func({"short line"}) +func({"long line", "long long line", "long long long line", "long long long long line", "long long long long long line"}) +func({{"long line", "long long line", "long long long line", "long long long long line", "long long long long long line"}}) + +foooooooooooooooooooo( + [{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size} +) + +baaaaaaaaaaaaar( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +) + +foo(*["long long long long long line", "long long long long long line", "long long long long long line"]) + +foo(*[str(i) for i in range(100000000000000000000000000000000000000000000000000000000000)]) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/preview_hug_parens_with_braces_and_square_brackets.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/preview_hug_parens_with_braces_and_square_brackets.py.expect new file mode 100644 index 0000000000000..963fb7c4040a4 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/preview_hug_parens_with_braces_and_square_brackets.py.expect @@ -0,0 +1,159 @@ +def foo_brackets(request): + return JsonResponse({ + "var_1": foo, + "var_2": bar, + }) + + +def foo_square_brackets(request): + return JsonResponse([ + "var_1", + "var_2", + ]) + + +func({ + "a": 37, + "b": 42, + "c": 927, + "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111, +}) + +func([ + "random_string_number_one", + "random_string_number_two", + "random_string_number_three", + "random_string_number_four", +]) + +func({ + # expand me + "a": 37, + "b": 42, + "c": 927, +}) + +func([ + "a", + "b", + "c", +]) + +func( + [ + "a", + "b", + "c", + ], +) + +func([ # a # b + "c", # c + "d", # d + "e", # e +]) # f # g + +func({ # a # b + "c": 1, # c + "d": 2, # d + "e": 3, # e +}) # f # g + +func( + # preserve me + [ + "c", + "d", + "e", + ] +) + +func([ # preserve me but hug brackets + "c", + "d", + "e", +]) + +func([ + # preserve me but hug brackets + "c", + "d", + "e", +]) + +func([ + "c", + # preserve me but hug brackets + "d", + "e", +]) + +func([ + "c", + "d", + "e", + # preserve me but hug brackets +]) + +func([ + "c", + "d", + "e", +]) # preserve me but hug brackets + +func( + [ + "c", + "d", + "e", + ] + # preserve me +) + +func([x for x in "short line"]) +func([ + x for x in "long line long line long line long line long line long line long line" +]) +func([ + x + for x in [ + x + for x in "long line long line long line long line long line long line long line" + ] +]) + +func({"short line"}) +func({ + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +}) +func({ + { + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", + } +}) + +foooooooooooooooooooo( + [{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size} +) + +baaaaaaaaaaaaar( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +) + +foo(*[ + "long long long long long line", + "long long long long long line", + "long long long long long line", +]) + +foo(*[ + str(i) for i in range(100000000000000000000000000000000000000000000000000000000000) +]) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/hug.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/hug.py new file mode 100644 index 0000000000000..bbd41b51a8ba7 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/hug.py @@ -0,0 +1,153 @@ +# Preview style: hug brackets to call parentheses. +func([1, 2, 3,]) + +func( # comment +[1, 2, 3,]) + +func( + # comment +[1, 2, 3,]) + +func([1, 2, 3,] # comment +) + +func([1, 2, 3,] + # comment +) + +func([ # comment + 1, 2, 3,] +) + +func(([1, 2, 3,])) + + +func( + ( + 1, + 2, + 3, + ) +) + +# Ensure that comprehensions hug too. +func([(x, y,) for (x, y) in z]) + +# Ensure that dictionaries hug too. +func({1: 2, 3: 4, 5: 6,}) + +# Ensure that the same behavior is applied to parenthesized expressions. +([1, 2, 3,]) + +( # comment + [1, 2, 3,]) + +( + [ # comment + 1, 2, 3,]) + +# Ensure that starred arguments are also hugged. +foo( + *[ + a_long_function_name(a_long_variable_name) + for a_long_variable_name in some_generator + ] +) + +foo( + * # comment + [ + a_long_function_name(a_long_variable_name) + for a_long_variable_name in some_generator + ] +) + +foo( + **[ + a_long_function_name(a_long_variable_name) + for a_long_variable_name in some_generator + ] +) + +foo( + ** # comment + [ + a_long_function_name(a_long_variable_name) + for a_long_variable_name in some_generator + ] +) + +# Ensure that multi-argument calls are _not_ hugged. +func([1, 2, 3,], bar) + +func([(x, y,) for (x, y) in z], bar) + +# Ensure that return type annotations (which use `parenthesize_if_expands`) are also hugged. +def func() -> [1, 2, 3,]: + pass + +def func() -> ([1, 2, 3,]): + pass + +def func() -> ([1, 2, 3,]): + pass + +def func() -> ( # comment + [1, 2, 3,]): + pass + +def func() -> ( + [1, 2, 3,] # comment +): + pass + +def func() -> ( + [1, 2, 3,] + # comment +): + pass + +# Ensure that nested lists are hugged. +func([ + [ + 1, + 2, + 3, + ] +]) + + +func([ + # comment + [ + 1, + 2, + 3, + ] +]) + +func([ + [ + 1, + 2, + 3, + ] + # comment +]) + +func([ + [ # comment + 1, + 2, + 3, + ] +]) + + +func([ # comment + [ + 1, + 2, + 3, + ] +]) diff --git a/crates/ruff_python_formatter/src/builders.rs b/crates/ruff_python_formatter/src/builders.rs index 581fdc5194a66..e4e2909a4a6dd 100644 --- a/crates/ruff_python_formatter/src/builders.rs +++ b/crates/ruff_python_formatter/src/builders.rs @@ -1,4 +1,4 @@ -use ruff_formatter::{format_args, write, Argument, Arguments}; +use ruff_formatter::{write, Argument, Arguments}; use ruff_text_size::{Ranged, TextRange, TextSize}; use crate::context::{NodeLevel, WithNodeLevel}; @@ -12,11 +12,20 @@ where { ParenthesizeIfExpands { inner: Argument::new(content), + indent: true, } } pub(crate) struct ParenthesizeIfExpands<'a, 'ast> { inner: Argument<'a, PyFormatContext<'ast>>, + indent: bool, +} + +impl ParenthesizeIfExpands<'_, '_> { + pub(crate) fn with_indent(mut self, indent: bool) -> Self { + self.indent = indent; + self + } } impl<'ast> Format> for ParenthesizeIfExpands<'_, 'ast> { @@ -26,11 +35,17 @@ impl<'ast> Format> for ParenthesizeIfExpands<'_, 'ast> { write!( f, - [group(&format_args![ - if_group_breaks(&token("(")), - soft_block_indent(&Arguments::from(&self.inner)), - if_group_breaks(&token(")")), - ])] + [group(&format_with(|f| { + if_group_breaks(&token("(")).fmt(f)?; + + if self.indent { + soft_block_indent(&Arguments::from(&self.inner)).fmt(f)?; + } else { + Arguments::from(&self.inner).fmt(f)?; + }; + + if_group_breaks(&token(")")).fmt(f) + }))] ) } } diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index 86fae5137a448..b9dc9e8520a04 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -23,6 +23,7 @@ use crate::expression::parentheses::{ OptionalParentheses, Parentheses, Parenthesize, }; use crate::prelude::*; +use crate::PyFormatOptions; mod binary_like; pub(crate) mod expr_attribute; @@ -126,10 +127,12 @@ impl FormatRule> for FormatExpr { Parentheses::Never => false, }; if parenthesize { - let comment = f.context().comments().clone(); - let node_comments = comment.leading_dangling_trailing(expression); + let comments = f.context().comments().clone(); + let node_comments = comments.leading_dangling_trailing(expression); if !node_comments.has_leading() && !node_comments.has_trailing() { - parenthesized("(", &format_expr, ")").fmt(f) + parenthesized("(", &format_expr, ")") + .with_indent(!is_expression_huggable(expression, f.options())) + .fmt(f) } else { format_with_parentheses_comments(expression, &node_comments, f) } @@ -403,9 +406,11 @@ impl Format> for MaybeParenthesizeExpression<'_> { parenthesize_if_expands(&expression.format().with_options(Parentheses::Never)) .fmt(f) } + Parenthesize::IfRequired => { expression.format().with_options(Parentheses::Never).fmt(f) } + Parenthesize::Optional | Parenthesize::IfBreaks => { if can_omit_optional_parentheses(expression, f.context()) { optional_parentheses(&expression.format().with_options(Parentheses::Never)) @@ -427,6 +432,7 @@ impl Format> for MaybeParenthesizeExpression<'_> { Parenthesize::Optional | Parenthesize::IfRequired => { expression.format().with_options(Parentheses::Never).fmt(f) } + Parenthesize::IfBreaks => { // Is the expression the last token in the parent statement. // Excludes `await` and `yield` for which Black doesn't seem to apply the layout? @@ -534,6 +540,7 @@ impl Format> for MaybeParenthesizeExpression<'_> { OptionalParentheses::Never => match parenthesize { Parenthesize::IfBreaksOrIfRequired => { parenthesize_if_expands(&expression.format().with_options(Parentheses::Never)) + .with_indent(!is_expression_huggable(expression, f.options())) .fmt(f) } @@ -1119,6 +1126,86 @@ pub(crate) fn has_own_parentheses( } } +/// Returns `true` if the expression can hug directly to enclosing parentheses, as in Black's +/// `hug_parens_with_braces_and_square_brackets` preview style behavior. +/// +/// For example, in preview style, given: +/// ```python +/// ([1, 2, 3,]) +/// ``` +/// +/// We want to format it as: +/// ```python +/// ([ +/// 1, +/// 2, +/// 3, +/// ]) +/// ``` +/// +/// As opposed to: +/// ```python +/// ( +/// [ +/// 1, +/// 2, +/// 3, +/// ] +/// ) +/// ``` +pub(crate) fn is_expression_huggable(expr: &Expr, options: &PyFormatOptions) -> bool { + if !options.preview().is_enabled() { + return false; + } + + match expr { + Expr::Tuple(_) + | Expr::List(_) + | Expr::Set(_) + | Expr::Dict(_) + | Expr::ListComp(_) + | Expr::SetComp(_) + | Expr::DictComp(_) => true, + + Expr::Starred(ast::ExprStarred { value, .. }) => matches!( + value.as_ref(), + Expr::Tuple(_) + | Expr::List(_) + | Expr::Set(_) + | Expr::Dict(_) + | Expr::ListComp(_) + | Expr::SetComp(_) + | Expr::DictComp(_) + ), + + Expr::BoolOp(_) + | Expr::NamedExpr(_) + | Expr::BinOp(_) + | Expr::UnaryOp(_) + | Expr::Lambda(_) + | Expr::IfExp(_) + | Expr::GeneratorExp(_) + | Expr::Await(_) + | Expr::Yield(_) + | Expr::YieldFrom(_) + | Expr::Compare(_) + | Expr::Call(_) + | Expr::FormattedValue(_) + | Expr::FString(_) + | Expr::Attribute(_) + | Expr::Subscript(_) + | Expr::Name(_) + | Expr::Slice(_) + | Expr::IpyEscapeCommand(_) + | Expr::StringLiteral(_) + | Expr::BytesLiteral(_) + | Expr::NumberLiteral(_) + | Expr::BooleanLiteral(_) + | Expr::NoneLiteral(_) + | Expr::EllipsisLiteral(_) => false, + } +} + /// The precedence of [python operators](https://docs.python.org/3/reference/expressions.html#operator-precedence) from /// highest to lowest priority. /// @@ -1144,7 +1231,7 @@ enum OperatorPrecedence { Conditional, } -impl From for OperatorPrecedence { +impl From for OperatorPrecedence { fn from(value: Operator) -> Self { match value { Operator::Add | Operator::Sub => OperatorPrecedence::Additive, diff --git a/crates/ruff_python_formatter/src/expression/parentheses.rs b/crates/ruff_python_formatter/src/expression/parentheses.rs index d05b9dcbd7d5f..971d913146609 100644 --- a/crates/ruff_python_formatter/src/expression/parentheses.rs +++ b/crates/ruff_python_formatter/src/expression/parentheses.rs @@ -84,6 +84,7 @@ pub enum Parentheses { Never, } +/// Returns `true` if the [`ExpressionRef`] is enclosed by parentheses in the source code. pub(crate) fn is_expression_parenthesized( expr: ExpressionRef, comment_ranges: &CommentRanges, @@ -125,6 +126,7 @@ where FormatParenthesized { left, comments: &[], + indent: true, content: Argument::new(content), right, } @@ -133,6 +135,7 @@ where pub(crate) struct FormatParenthesized<'content, 'ast> { left: &'static str, comments: &'content [SourceComment], + indent: bool, content: Argument<'content, PyFormatContext<'ast>>, right: &'static str, } @@ -153,6 +156,11 @@ impl<'content, 'ast> FormatParenthesized<'content, 'ast> { ) -> FormatParenthesized<'content, 'ast> { FormatParenthesized { comments, ..self } } + + /// Whether to indent the content within the parentheses. + pub(crate) fn with_indent(self, indent: bool) -> FormatParenthesized<'content, 'ast> { + FormatParenthesized { indent, ..self } + } } impl<'ast> Format> for FormatParenthesized<'_, 'ast> { @@ -160,10 +168,15 @@ impl<'ast> Format> for FormatParenthesized<'_, 'ast> { let current_level = f.context().node_level(); let content = format_with(|f| { - group(&format_args![ - dangling_open_parenthesis_comments(self.comments), - soft_block_indent(&Arguments::from(&self.content)) - ]) + group(&format_with(|f| { + dangling_open_parenthesis_comments(self.comments).fmt(f)?; + if self.indent || !self.comments.is_empty() { + soft_block_indent(&Arguments::from(&self.content)).fmt(f)?; + } else { + Arguments::from(&self.content).fmt(f)?; + } + Ok(()) + })) .fmt(f) }); diff --git a/crates/ruff_python_formatter/src/other/arguments.rs b/crates/ruff_python_formatter/src/other/arguments.rs index 5baa9fa741c46..a48596cac0eb3 100644 --- a/crates/ruff_python_formatter/src/other/arguments.rs +++ b/crates/ruff_python_formatter/src/other/arguments.rs @@ -1,11 +1,13 @@ -use ruff_formatter::write; +use ruff_formatter::{write, FormatContext}; use ruff_python_ast::{ArgOrKeyword, Arguments, Expr}; use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer}; use ruff_text_size::{Ranged, TextRange, TextSize}; use crate::comments::SourceComment; use crate::expression::expr_generator_exp::GeneratorExpParentheses; +use crate::expression::is_expression_huggable; use crate::expression::parentheses::{empty_parenthesized, parenthesized, Parentheses}; +use crate::other::commas; use crate::prelude::*; #[derive(Default)] @@ -104,6 +106,7 @@ impl FormatNodeRule for FormatArguments { // ) // ``` parenthesized("(", &group(&all_arguments), ")") + .with_indent(!is_argument_huggable(item, f.context())) .with_dangling_comments(dangling_comments) ] ) @@ -143,3 +146,68 @@ fn is_single_argument_parenthesized(argument: &Expr, call_end: TextSize, source: false } +/// Returns `true` if the arguments can hug directly to the enclosing parentheses in the call, as +/// in Black's `hug_parens_with_braces_and_square_brackets` preview style behavior. +/// +/// For example, in preview style, given: +/// ```python +/// func([1, 2, 3,]) +/// ``` +/// +/// We want to format it as: +/// ```python +/// func([ +/// 1, +/// 2, +/// 3, +/// ]) +/// ``` +/// +/// As opposed to: +/// ```python +/// func( +/// [ +/// 1, +/// 2, +/// 3, +/// ] +/// ) +/// ``` +/// +/// Hugging should only be applied to single-argument collections, like lists, or starred versions +/// of those collections. +fn is_argument_huggable(item: &Arguments, context: &PyFormatContext) -> bool { + let options = context.options(); + if !options.preview().is_enabled() { + return false; + } + + // Find the lone argument or `**kwargs` keyword. + let arg = match (item.args.as_slice(), item.keywords.as_slice()) { + ([arg], []) => arg, + ([], [keyword]) if keyword.arg.is_none() && !context.comments().has(keyword) => { + &keyword.value + } + _ => return false, + }; + + // If the expression itself isn't huggable, then we can't hug it. + if !is_expression_huggable(arg, options) { + return false; + } + + // If the expression has leading or trailing comments, then we can't hug it. + let comments = context.comments().leading_dangling_trailing(arg); + if comments.has_leading() || comments.has_trailing() { + return false; + } + + // If the expression has a trailing comma, then we can't hug it. + if options.magic_trailing_comma().is_respect() + && commas::has_magic_trailing_comma(TextRange::new(arg.end(), item.end()), options, context) + { + return false; + } + + true +} diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__preview_hug_parens_with_braces_and_square_brackets.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__preview_hug_parens_with_braces_and_square_brackets.py.snap new file mode 100644 index 0000000000000..df9471aac22dc --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__preview_hug_parens_with_braces_and_square_brackets.py.snap @@ -0,0 +1,543 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/preview_hug_parens_with_braces_and_square_brackets.py +--- +## Input + +```python +def foo_brackets(request): + return JsonResponse( + { + "var_1": foo, + "var_2": bar, + } + ) + +def foo_square_brackets(request): + return JsonResponse( + [ + "var_1", + "var_2", + ] + ) + +func({"a": 37, "b": 42, "c": 927, "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111}) + +func(["random_string_number_one","random_string_number_two","random_string_number_three","random_string_number_four"]) + +func( + { + # expand me + 'a':37, + 'b':42, + 'c':927 + } +) + +func( + [ + 'a', + 'b', + 'c', + ] +) + +func( + [ + 'a', + 'b', + 'c', + ], +) + +func( # a + [ # b + "c", # c + "d", # d + "e", # e + ] # f +) # g + +func( # a + { # b + "c": 1, # c + "d": 2, # d + "e": 3, # e + } # f +) # g + +func( + # preserve me + [ + "c", + "d", + "e", + ] +) + +func( + [ # preserve me but hug brackets + "c", + "d", + "e", + ] +) + +func( + [ + # preserve me but hug brackets + "c", + "d", + "e", + ] +) + +func( + [ + "c", + # preserve me but hug brackets + "d", + "e", + ] +) + +func( + [ + "c", + "d", + "e", + # preserve me but hug brackets + ] +) + +func( + [ + "c", + "d", + "e", + ] # preserve me but hug brackets +) + +func( + [ + "c", + "d", + "e", + ] + # preserve me +) + +func([x for x in "short line"]) +func([x for x in "long line long line long line long line long line long line long line"]) +func([x for x in [x for x in "long line long line long line long line long line long line long line"]]) + +func({"short line"}) +func({"long line", "long long line", "long long long line", "long long long long line", "long long long long long line"}) +func({{"long line", "long long line", "long long long line", "long long long long line", "long long long long long line"}}) + +foooooooooooooooooooo( + [{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size} +) + +baaaaaaaaaaaaar( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +) + +foo(*["long long long long long line", "long long long long long line", "long long long long long line"]) + +foo(*[str(i) for i in range(100000000000000000000000000000000000000000000000000000000000)]) +``` + +## Black Differences + +```diff +--- Black ++++ Ruff +@@ -47,17 +47,21 @@ + ], + ) + +-func([ # a # b +- "c", # c +- "d", # d +- "e", # e +-]) # f # g ++func( # a ++ [ # b ++ "c", # c ++ "d", # d ++ "e", # e ++ ] # f ++) # g + +-func({ # a # b +- "c": 1, # c +- "d": 2, # d +- "e": 3, # e +-}) # f # g ++func( # a ++ { # b ++ "c": 1, # c ++ "d": 2, # d ++ "e": 3, # e ++ } # f ++) # g + + func( + # preserve me +@@ -95,11 +99,13 @@ + # preserve me but hug brackets + ]) + +-func([ +- "c", +- "d", +- "e", +-]) # preserve me but hug brackets ++func( ++ [ ++ "c", ++ "d", ++ "e", ++ ] # preserve me but hug brackets ++) + + func( + [ +``` + +## Ruff Output + +```python +def foo_brackets(request): + return JsonResponse({ + "var_1": foo, + "var_2": bar, + }) + + +def foo_square_brackets(request): + return JsonResponse([ + "var_1", + "var_2", + ]) + + +func({ + "a": 37, + "b": 42, + "c": 927, + "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111, +}) + +func([ + "random_string_number_one", + "random_string_number_two", + "random_string_number_three", + "random_string_number_four", +]) + +func({ + # expand me + "a": 37, + "b": 42, + "c": 927, +}) + +func([ + "a", + "b", + "c", +]) + +func( + [ + "a", + "b", + "c", + ], +) + +func( # a + [ # b + "c", # c + "d", # d + "e", # e + ] # f +) # g + +func( # a + { # b + "c": 1, # c + "d": 2, # d + "e": 3, # e + } # f +) # g + +func( + # preserve me + [ + "c", + "d", + "e", + ] +) + +func([ # preserve me but hug brackets + "c", + "d", + "e", +]) + +func([ + # preserve me but hug brackets + "c", + "d", + "e", +]) + +func([ + "c", + # preserve me but hug brackets + "d", + "e", +]) + +func([ + "c", + "d", + "e", + # preserve me but hug brackets +]) + +func( + [ + "c", + "d", + "e", + ] # preserve me but hug brackets +) + +func( + [ + "c", + "d", + "e", + ] + # preserve me +) + +func([x for x in "short line"]) +func([ + x for x in "long line long line long line long line long line long line long line" +]) +func([ + x + for x in [ + x + for x in "long line long line long line long line long line long line long line" + ] +]) + +func({"short line"}) +func({ + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +}) +func({ + { + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", + } +}) + +foooooooooooooooooooo( + [{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size} +) + +baaaaaaaaaaaaar( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +) + +foo(*[ + "long long long long long line", + "long long long long long line", + "long long long long long line", +]) + +foo(*[ + str(i) for i in range(100000000000000000000000000000000000000000000000000000000000) +]) +``` + +## Black Output + +```python +def foo_brackets(request): + return JsonResponse({ + "var_1": foo, + "var_2": bar, + }) + + +def foo_square_brackets(request): + return JsonResponse([ + "var_1", + "var_2", + ]) + + +func({ + "a": 37, + "b": 42, + "c": 927, + "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111, +}) + +func([ + "random_string_number_one", + "random_string_number_two", + "random_string_number_three", + "random_string_number_four", +]) + +func({ + # expand me + "a": 37, + "b": 42, + "c": 927, +}) + +func([ + "a", + "b", + "c", +]) + +func( + [ + "a", + "b", + "c", + ], +) + +func([ # a # b + "c", # c + "d", # d + "e", # e +]) # f # g + +func({ # a # b + "c": 1, # c + "d": 2, # d + "e": 3, # e +}) # f # g + +func( + # preserve me + [ + "c", + "d", + "e", + ] +) + +func([ # preserve me but hug brackets + "c", + "d", + "e", +]) + +func([ + # preserve me but hug brackets + "c", + "d", + "e", +]) + +func([ + "c", + # preserve me but hug brackets + "d", + "e", +]) + +func([ + "c", + "d", + "e", + # preserve me but hug brackets +]) + +func([ + "c", + "d", + "e", +]) # preserve me but hug brackets + +func( + [ + "c", + "d", + "e", + ] + # preserve me +) + +func([x for x in "short line"]) +func([ + x for x in "long line long line long line long line long line long line long line" +]) +func([ + x + for x in [ + x + for x in "long line long line long line long line long line long line long line" + ] +]) + +func({"short line"}) +func({ + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +}) +func({ + { + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", + } +}) + +foooooooooooooooooooo( + [{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size} +) + +baaaaaaaaaaaaar( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +) + +foo(*[ + "long long long long long line", + "long long long long long line", + "long long long long long line", +]) + +foo(*[ + str(i) for i in range(100000000000000000000000000000000000000000000000000000000000) +]) +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__hug.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__hug.py.snap new file mode 100644 index 0000000000000..f9a4ca0ba5be8 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__hug.py.snap @@ -0,0 +1,752 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/hug.py +--- +## Input +```python +# Preview style: hug brackets to call parentheses. +func([1, 2, 3,]) + +func( # comment +[1, 2, 3,]) + +func( + # comment +[1, 2, 3,]) + +func([1, 2, 3,] # comment +) + +func([1, 2, 3,] + # comment +) + +func([ # comment + 1, 2, 3,] +) + +func(([1, 2, 3,])) + + +func( + ( + 1, + 2, + 3, + ) +) + +# Ensure that comprehensions hug too. +func([(x, y,) for (x, y) in z]) + +# Ensure that dictionaries hug too. +func({1: 2, 3: 4, 5: 6,}) + +# Ensure that the same behavior is applied to parenthesized expressions. +([1, 2, 3,]) + +( # comment + [1, 2, 3,]) + +( + [ # comment + 1, 2, 3,]) + +# Ensure that starred arguments are also hugged. +foo( + *[ + a_long_function_name(a_long_variable_name) + for a_long_variable_name in some_generator + ] +) + +foo( + * # comment + [ + a_long_function_name(a_long_variable_name) + for a_long_variable_name in some_generator + ] +) + +foo( + **[ + a_long_function_name(a_long_variable_name) + for a_long_variable_name in some_generator + ] +) + +foo( + ** # comment + [ + a_long_function_name(a_long_variable_name) + for a_long_variable_name in some_generator + ] +) + +# Ensure that multi-argument calls are _not_ hugged. +func([1, 2, 3,], bar) + +func([(x, y,) for (x, y) in z], bar) + +# Ensure that return type annotations (which use `parenthesize_if_expands`) are also hugged. +def func() -> [1, 2, 3,]: + pass + +def func() -> ([1, 2, 3,]): + pass + +def func() -> ([1, 2, 3,]): + pass + +def func() -> ( # comment + [1, 2, 3,]): + pass + +def func() -> ( + [1, 2, 3,] # comment +): + pass + +def func() -> ( + [1, 2, 3,] + # comment +): + pass + +# Ensure that nested lists are hugged. +func([ + [ + 1, + 2, + 3, + ] +]) + + +func([ + # comment + [ + 1, + 2, + 3, + ] +]) + +func([ + [ + 1, + 2, + 3, + ] + # comment +]) + +func([ + [ # comment + 1, + 2, + 3, + ] +]) + + +func([ # comment + [ + 1, + 2, + 3, + ] +]) +``` + +## Output +```python +# Preview style: hug brackets to call parentheses. +func( + [ + 1, + 2, + 3, + ] +) + +func( # comment + [ + 1, + 2, + 3, + ] +) + +func( + # comment + [ + 1, + 2, + 3, + ] +) + +func( + [ + 1, + 2, + 3, + ] # comment +) + +func( + [ + 1, + 2, + 3, + ] + # comment +) + +func( + [ # comment + 1, + 2, + 3, + ] +) + +func( + ( + [ + 1, + 2, + 3, + ] + ) +) + + +func( + ( + 1, + 2, + 3, + ) +) + +# Ensure that comprehensions hug too. +func( + [ + ( + x, + y, + ) + for (x, y) in z + ] +) + +# Ensure that dictionaries hug too. +func( + { + 1: 2, + 3: 4, + 5: 6, + } +) + +# Ensure that the same behavior is applied to parenthesized expressions. +( + [ + 1, + 2, + 3, + ] +) + +( # comment + [ + 1, + 2, + 3, + ] +) + +( + [ # comment + 1, + 2, + 3, + ] +) + +# Ensure that starred arguments are also hugged. +foo( + *[ + a_long_function_name(a_long_variable_name) + for a_long_variable_name in some_generator + ] +) + +foo( + # comment + *[ + a_long_function_name(a_long_variable_name) + for a_long_variable_name in some_generator + ] +) + +foo( + **[ + a_long_function_name(a_long_variable_name) + for a_long_variable_name in some_generator + ] +) + +foo( + # comment + **[ + a_long_function_name(a_long_variable_name) + for a_long_variable_name in some_generator + ] +) + +# Ensure that multi-argument calls are _not_ hugged. +func( + [ + 1, + 2, + 3, + ], + bar, +) + +func( + [ + ( + x, + y, + ) + for (x, y) in z + ], + bar, +) + + +# Ensure that return type annotations (which use `parenthesize_if_expands`) are also hugged. +def func() -> ( + [ + 1, + 2, + 3, + ] +): + pass + + +def func() -> ( + [ + 1, + 2, + 3, + ] +): + pass + + +def func() -> ( + [ + 1, + 2, + 3, + ] +): + pass + + +def func() -> ( # comment + [ + 1, + 2, + 3, + ] +): + pass + + +def func() -> ( + [ + 1, + 2, + 3, + ] # comment +): + pass + + +def func() -> ( + [ + 1, + 2, + 3, + ] + # comment +): + pass + + +# Ensure that nested lists are hugged. +func( + [ + [ + 1, + 2, + 3, + ] + ] +) + + +func( + [ + # comment + [ + 1, + 2, + 3, + ] + ] +) + +func( + [ + [ + 1, + 2, + 3, + ] + # comment + ] +) + +func( + [ + [ # comment + 1, + 2, + 3, + ] + ] +) + + +func( + [ # comment + [ + 1, + 2, + 3, + ] + ] +) +``` + + +## Preview changes +```diff +--- Stable ++++ Preview +@@ -1,11 +1,9 @@ + # Preview style: hug brackets to call parentheses. +-func( +- [ +- 1, +- 2, +- 3, +- ] +-) ++func([ ++ 1, ++ 2, ++ 3, ++]) + + func( # comment + [ +@@ -41,61 +39,47 @@ + # comment + ) + +-func( +- [ # comment +- 1, +- 2, +- 3, +- ] +-) ++func([ # comment ++ 1, ++ 2, ++ 3, ++]) + +-func( +- ( +- [ +- 1, +- 2, +- 3, +- ] +- ) +-) ++func(([ ++ 1, ++ 2, ++ 3, ++])) + + +-func( +- ( +- 1, +- 2, +- 3, +- ) +-) ++func(( ++ 1, ++ 2, ++ 3, ++)) + + # Ensure that comprehensions hug too. +-func( +- [ +- ( +- x, +- y, +- ) +- for (x, y) in z +- ] +-) ++func([ ++ ( ++ x, ++ y, ++ ) ++ for (x, y) in z ++]) + + # Ensure that dictionaries hug too. +-func( +- { +- 1: 2, +- 3: 4, +- 5: 6, +- } +-) ++func({ ++ 1: 2, ++ 3: 4, ++ 5: 6, ++}) + + # Ensure that the same behavior is applied to parenthesized expressions. +-( +- [ +- 1, +- 2, +- 3, +- ] +-) ++([ ++ 1, ++ 2, ++ 3, ++]) + + ( # comment + [ +@@ -105,21 +89,17 @@ + ] + ) + +-( +- [ # comment +- 1, +- 2, +- 3, +- ] +-) ++([ # comment ++ 1, ++ 2, ++ 3, ++]) + + # Ensure that starred arguments are also hugged. +-foo( +- *[ +- a_long_function_name(a_long_variable_name) +- for a_long_variable_name in some_generator +- ] +-) ++foo(*[ ++ a_long_function_name(a_long_variable_name) ++ for a_long_variable_name in some_generator ++]) + + foo( + # comment +@@ -129,12 +109,10 @@ + ] + ) + +-foo( +- **[ +- a_long_function_name(a_long_variable_name) +- for a_long_variable_name in some_generator +- ] +-) ++foo(**[ ++ a_long_function_name(a_long_variable_name) ++ for a_long_variable_name in some_generator ++]) + + foo( + # comment +@@ -167,33 +145,27 @@ + + + # Ensure that return type annotations (which use `parenthesize_if_expands`) are also hugged. +-def func() -> ( +- [ +- 1, +- 2, +- 3, +- ] +-): ++def func() -> ([ ++ 1, ++ 2, ++ 3, ++]): + pass + + +-def func() -> ( +- [ +- 1, +- 2, +- 3, +- ] +-): ++def func() -> ([ ++ 1, ++ 2, ++ 3, ++]): + pass + + +-def func() -> ( +- [ +- 1, +- 2, +- 3, +- ] +-): ++def func() -> ([ ++ 1, ++ 2, ++ 3, ++]): + pass + + +@@ -229,56 +201,46 @@ + + + # Ensure that nested lists are hugged. +-func( ++func([ + [ +- [ +- 1, +- 2, +- 3, +- ] ++ 1, ++ 2, ++ 3, + ] +-) ++]) + + +-func( ++func([ ++ # comment + [ +- # comment +- [ +- 1, +- 2, +- 3, +- ] ++ 1, ++ 2, ++ 3, + ] +-) ++]) + +-func( ++func([ + [ +- [ +- 1, +- 2, +- 3, +- ] +- # comment ++ 1, ++ 2, ++ 3, + ] +-) ++ # comment ++]) + +-func( +- [ +- [ # comment +- 1, +- 2, +- 3, +- ] ++func([ ++ [ # comment ++ 1, ++ 2, ++ 3, + ] +-) ++]) + + +-func( +- [ # comment +- [ +- 1, +- 2, +- 3, +- ] ++func([ # comment ++ [ ++ 1, ++ 2, ++ 3, + ] +-) ++]) +``` + + + diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__split_empty_brackets.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__split_empty_brackets.py.snap index 810964acc19a2..2c9fb1d380816 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__split_empty_brackets.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__split_empty_brackets.py.snap @@ -194,4 +194,24 @@ response = await sync_to_async( ``` +## Preview changes +```diff +--- Stable ++++ Preview +@@ -62,9 +62,9 @@ + 1 + }.unicodedata.normalize("NFKCNFKCNFKCNFKCNFKC", s2).casefold() + +-ct_match = ([]).unicodedata.normalize("NFKC", s1).casefold() == ( +- [] +-).unicodedata.normalize("NFKCNFKCNFKCNFKCNFKC", s2).casefold() ++ct_match = ([]).unicodedata.normalize( ++ "NFKC", s1 ++).casefold() == ([]).unicodedata.normalize("NFKCNFKCNFKCNFKCNFKC", s2).casefold() + + return await self.http_client.fetch( + f"http://127.0.0.1:{self.port}{path}", +``` + + From eaa310429fc9b6d0b67d7b174ec3444921c80873 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 30 Nov 2023 21:49:28 -0500 Subject: [PATCH 074/197] Insert trailing comma when function breaks with single argument (#8921) ## Summary Given: ```python def _example_function_xxxxxxx( variable: Optional[List[str]] ) -> List[example.ExampleConfig]: pass ``` We should be inserting a trailing comma after the argument (as long as it's a single-argument function). This was an inconsistency with Black, but also led to some internal inconsistencies, whereby we added the comma if the argument contained a trailing end-of-line comment, but not otherwise. Closes https://github.com/astral-sh/ruff/issues/8912. ## Test Plan `cargo test` Before: | project | similarity index | total files | changed files | |----------------|------------------:|------------------:|------------------:| | cpython | 0.75804 | 1799 | 1648 | | django | 0.99984 | 2772 | 34 | | home-assistant | 0.99963 | 10596 | 146 | | poetry | 0.99925 | 317 | 12 | | transformers | 0.99967 | 2657 | 322 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99980 | 3669 | 18 | | warehouse | 0.99977 | 654 | 13 | | zulip | 0.99970 | 1459 | 21 | After: | project | similarity index | total files | changed files | |----------------|------------------:|------------------:|------------------:| | cpython | 0.75804 | 1799 | 1648 | | django | 0.99984 | 2772 | 34 | | home-assistant | 0.99955 | 10596 | 213 | | poetry | 0.99917 | 317 | 13 | | transformers | 0.99967 | 2657 | 324 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99980 | 3669 | 18 | | warehouse | 0.99976 | 654 | 14 | | zulip | 0.99957 | 1459 | 36 | --- .../src/other/parameters.rs | 13 ++++ ...funcdef_return_type_trailing_comma.py.snap | 24 ++----- ..._return_annotation_brackets_string.py.snap | 11 +--- ...@cases__return_annotation_brackets.py.snap | 8 +-- ..._opening_parentheses_comment_value.py.snap | 2 +- .../format@statement__function.py.snap | 2 +- ...ormat@statement__return_annotation.py.snap | 66 +++++++++---------- 7 files changed, 60 insertions(+), 66 deletions(-) diff --git a/crates/ruff_python_formatter/src/other/parameters.rs b/crates/ruff_python_formatter/src/other/parameters.rs index 86cad5869b2ce..d095d33ae1975 100644 --- a/crates/ruff_python_formatter/src/other/parameters.rs +++ b/crates/ruff_python_formatter/src/other/parameters.rs @@ -252,6 +252,19 @@ impl FormatNodeRule for FormatParameters { let mut f = WithNodeLevel::new(NodeLevel::ParenthesizedExpression, f); // No parameters, format any dangling comments between `()` write!(f, [empty_parenthesized("(", dangling, ")")]) + } else if num_parameters == 1 { + // If we have a single argument, avoid the inner group, to ensure that we insert a + // trailing comma if the outer group breaks. + let mut f = WithNodeLevel::new(NodeLevel::ParenthesizedExpression, f); + write!( + f, + [ + token("("), + dangling_open_parenthesis_comments(parenthesis_dangling), + soft_block_indent(&format_inner), + token(")") + ] + ) } else { // Intentionally avoid `parenthesized`, which groups the entire formatted contents. // We want parameters to be grouped alongside return types, one level up, so we diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__funcdef_return_type_trailing_comma.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__funcdef_return_type_trailing_comma.py.snap index a10744872cd4a..09c380567e951 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__funcdef_return_type_trailing_comma.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__funcdef_return_type_trailing_comma.py.snap @@ -179,13 +179,7 @@ def SimplePyFn( p, q, ]: -@@ -63,16 +67,18 @@ - # long function definition, return type is longer - # this should maybe split on rhs? - def aaaaaaaaaaaaaaaaa( -- bbbbbbbbbbbbbbbbbb, -+ bbbbbbbbbbbbbbbbbb - ) -> list[Ccccccccccccccccccccccccccccccccccccccccccccccccccc, Dddddd]: ... +@@ -68,11 +72,13 @@ # long return type, no param list @@ -204,25 +198,19 @@ def SimplePyFn( # long function name, no param list, no return value -@@ -93,12 +99,16 @@ +@@ -93,7 +99,11 @@ # unskippable type hint (??) -def foo(a) -> list[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]: # type: ignore +def foo( -+ a ++ a, +) -> list[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +]: # type: ignore pass - def foo( -- a, -+ a - ) -> list[ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - ]: # abpedeifnore @@ -112,7 +122,13 @@ @@ -333,7 +321,7 @@ def aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa( # long function definition, return type is longer # this should maybe split on rhs? def aaaaaaaaaaaaaaaaa( - bbbbbbbbbbbbbbbbbb + bbbbbbbbbbbbbbbbbb, ) -> list[Ccccccccccccccccccccccccccccccccccccccccccccccccccc, Dddddd]: ... @@ -366,7 +354,7 @@ def thiiiiiiiiiiiiiiiiiis_iiiiiiiiiiiiiiiiiiiiiiiiiiiiiis_veeeeeeeeeeeeeeeeeeeee # unskippable type hint (??) def foo( - a + a, ) -> list[ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ]: # type: ignore @@ -374,7 +362,7 @@ def foo( def foo( - a + a, ) -> list[ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ]: # abpedeifnore diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_return_annotation_brackets_string.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_return_annotation_brackets_string.py.snap index 268fcf0eb8487..5f43f1a7d20b5 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_return_annotation_brackets_string.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_return_annotation_brackets_string.py.snap @@ -19,7 +19,7 @@ def frobnicate(a) -> "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisI ```diff --- Black +++ Ruff -@@ -1,13 +1,12 @@ +@@ -1,7 +1,6 @@ # Long string example def frobnicate() -> ( - "ThisIsTrulyUnreasonablyExtremelyLongClassName |" @@ -28,13 +28,6 @@ def frobnicate(a) -> "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisI ): pass - - # splitting the string breaks if there's any parameters - def frobnicate( -- a, -+ a - ) -> "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisIsTrulyUnreasonablyExtremelyLongClassName]": - pass ``` ## Ruff Output @@ -49,7 +42,7 @@ def frobnicate() -> ( # splitting the string breaks if there's any parameters def frobnicate( - a + a, ) -> "ThisIsTrulyUnreasonablyExtremelyLongClassName | list[ThisIsTrulyUnreasonablyExtremelyLongClassName]": pass ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__return_annotation_brackets.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__return_annotation_brackets.py.snap index 415daad90c786..9bf6a451152c9 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__return_annotation_brackets.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__return_annotation_brackets.py.snap @@ -111,7 +111,7 @@ def foo(a,b) -> tuple[int, int, int,]: # Don't lose the comments -def double(a: int) -> int: # Hello +def double( -+ a: int ++ a: int, +) -> ( # Hello + int +): @@ -120,7 +120,7 @@ def foo(a,b) -> tuple[int, int, int,]: -def double(a: int) -> int: # Hello +def double( -+ a: int ++ a: int, +) -> ( + int # Hello +): @@ -168,7 +168,7 @@ def double(a: int) -> int: # Don't lose the comments def double( - a: int + a: int, ) -> ( # Hello int ): @@ -176,7 +176,7 @@ def double( def double( - a: int + a: int, ) -> ( int # Hello ): diff --git a/crates/ruff_python_formatter/tests/snapshots/format@parentheses__opening_parentheses_comment_value.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@parentheses__opening_parentheses_comment_value.py.snap index 4c226dd8c3d9a..2dc81368793b1 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@parentheses__opening_parentheses_comment_value.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@parentheses__opening_parentheses_comment_value.py.snap @@ -253,7 +253,7 @@ except ( # d 9 def e1( # e 1 - x + x, ): pass diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__function.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__function.py.snap index 5b0684becdfa4..7a8e97566ecb3 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__function.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__function.py.snap @@ -928,7 +928,7 @@ def f( # first def f( # first - a + a, ): # second ... diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__return_annotation.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__return_annotation.py.snap index d32669cbbc5b6..d7e7f4074a620 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__return_annotation.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__return_annotation.py.snap @@ -281,7 +281,7 @@ def double( def double( - a: int + a: int, ) -> ( # Hello int ): @@ -289,7 +289,7 @@ def double( def double( - a: int + a: int, ) -> ( # Hello ): return 2 * a @@ -298,7 +298,7 @@ def double( # Breaking over parameters and return types. (Black adds a trailing comma when the # function arguments break here with a single argument; we do not.) def f( - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, ) -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: ... @@ -310,13 +310,13 @@ def f( def f( - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, ) -> a: ... def f( - a + a, ) -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: ... @@ -334,13 +334,13 @@ def f[ def f[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]( - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, ) -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: ... def f[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]( - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, ) -> a: ... @@ -380,7 +380,7 @@ def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> ( def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( - x + x, ) -> Set[ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ]: @@ -388,7 +388,7 @@ def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( - x + x, ) -> Set[ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ]: @@ -396,7 +396,7 @@ def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( - *args + *args, ) -> Set[ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ]: @@ -431,13 +431,13 @@ def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> ( def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( - x + x, ) -> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: ... def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( - x + x, ) -> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: ... @@ -457,7 +457,7 @@ def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> ( def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( - x + x, ) -> X and Y and foooooooooooooooooooooooooooooooooooo(): ... @@ -477,7 +477,7 @@ def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> ( def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( - x + x, ) -> ( X | Y | foooooooooooooooooooooooooooooooooooo() # comment ): @@ -495,7 +495,7 @@ def double() -> ( # Dangling comments on return annotations. def double( - a: int + a: int, ) -> ( int # Hello ): @@ -503,7 +503,7 @@ def double( def double( - a: int + a: int, ) -> ( foo.bar # Hello ): @@ -511,7 +511,7 @@ def double( def double( - a: int + a: int, ) -> ( [int] # Hello ): @@ -519,7 +519,7 @@ def double( def double( - a: int + a: int, ) -> ( int | list[int] # Hello ): @@ -527,7 +527,7 @@ def double( def double( - a: int + a: int, ) -> ( int | list[ @@ -608,7 +608,7 @@ def process_board_action( @@ -95,50 +89,44 @@ # function arguments break here with a single argument; we do not.) def f( - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, -) -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: - ... +) -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: ... @@ -622,14 +622,14 @@ def process_board_action( def f( - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, -) -> a: - ... +) -> a: ... def f( - a + a, -) -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: - ... +) -> ( @@ -652,14 +652,14 @@ def process_board_action( def f[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]( - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, -) -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: - ... +) -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: ... def f[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]( - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, -) -> a: - ... +) -> a: ... @@ -703,7 +703,7 @@ def process_board_action( def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( - x + x, ) -> Set[ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -]: @@ -712,7 +712,7 @@ def process_board_action( def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( - x + x, ) -> Set[ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -]: @@ -721,7 +721,7 @@ def process_board_action( def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( - *args + *args, ) -> Set[ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -]: @@ -761,14 +761,14 @@ def process_board_action( def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( - x + x, -) -> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: - ... +) -> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: ... def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( - x + x, -) -> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: - ... +) -> ( @@ -786,7 +786,7 @@ def process_board_action( -def xxxxxxxxxxxxxxxxxxxxxxxxxxxx(x) -> X + Y + foooooooooooooooooooooooooooooooooooo(): - ... +def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( -+ x ++ x, +) -> X + Y + foooooooooooooooooooooooooooooooooooo(): ... @@ -798,7 +798,7 @@ def process_board_action( def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( - x + x, -) -> X and Y and foooooooooooooooooooooooooooooooooooo(): - ... +) -> X and Y and foooooooooooooooooooooooooooooooooooo(): ... @@ -814,7 +814,7 @@ def process_board_action( -def xxxxxxxxxxxxxxxxxxxxxxxxxxxx(x) -> X | Y | foooooooooooooooooooooooooooooooooooo(): - ... +def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( -+ x ++ x, +) -> X | Y | foooooooooooooooooooooooooooooooooooo(): ... @@ -826,7 +826,7 @@ def process_board_action( def xxxxxxxxxxxxxxxxxxxxxxxxxxxx( - x + x, ) -> ( X | Y | foooooooooooooooooooooooooooooooooooo() # comment -): From b2638c62a56678a357a19a1c4e94e4f6a8f0c31a Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 30 Nov 2023 21:57:05 -0500 Subject: [PATCH 075/197] Update formatter fixtures (#8935) I merged a branch that wasn't up-to-date, which left us with test failures on `main`. --- ...ns_with_braces_and_square_brackets.py.snap | 774 +++++++----------- ...__preview_long_strings__regression.py.snap | 127 ++- 2 files changed, 322 insertions(+), 579 deletions(-) diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_hug_parens_with_braces_and_square_brackets.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_hug_parens_with_braces_and_square_brackets.py.snap index d9a87a05c5987..e28ce63ff0fea 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_hug_parens_with_braces_and_square_brackets.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_hug_parens_with_braces_and_square_brackets.py.snap @@ -197,94 +197,7 @@ for foo in ["a", "b"]: ```diff --- Black +++ Ruff -@@ -1,43 +1,55 @@ - def foo_brackets(request): -- return JsonResponse({ -- "var_1": foo, -- "var_2": bar, -- }) -+ return JsonResponse( -+ { -+ "var_1": foo, -+ "var_2": bar, -+ } -+ ) - - - def foo_square_brackets(request): -- return JsonResponse([ -- "var_1", -- "var_2", -- ]) -+ return JsonResponse( -+ [ -+ "var_1", -+ "var_2", -+ ] -+ ) - - --func({ -- "a": 37, -- "b": 42, -- "c": 927, -- "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111, --}) -+func( -+ { -+ "a": 37, -+ "b": 42, -+ "c": 927, -+ "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111, -+ } -+) - --func([ -- "random_string_number_one", -- "random_string_number_two", -- "random_string_number_three", -- "random_string_number_four", --]) -+func( -+ [ -+ "random_string_number_one", -+ "random_string_number_two", -+ "random_string_number_three", -+ "random_string_number_four", -+ ] -+) - --func({ -- # expand me -- "a": 37, -- "b": 42, -- "c": 927, --}) -+func( -+ { -+ # expand me -+ "a": 37, -+ "b": 42, -+ "c": 927, -+ } -+) - --func([ -- "a", -- "b", -- "c", --]) -+func( -+ [ -+ "a", -+ "b", -+ "c", -+ ] -+) - - func( - [ -@@ -47,17 +59,21 @@ +@@ -47,17 +47,21 @@ ], ) @@ -316,67 +229,9 @@ for foo in ["a", "b"]: func( # preserve me -@@ -68,38 +84,48 @@ - ] - ) - --func([ # preserve me but hug brackets -- "c", -- "d", -- "e", --]) -+func( -+ [ # preserve me but hug brackets -+ "c", -+ "d", -+ "e", -+ ] -+) - --func([ -- # preserve me but hug brackets -- "c", -- "d", -- "e", --]) -+func( -+ [ -+ # preserve me but hug brackets -+ "c", -+ "d", -+ "e", -+ ] -+) - --func([ -- "c", -- # preserve me but hug brackets -- "d", -- "e", --]) -+func( -+ [ -+ "c", -+ # preserve me but hug brackets -+ "d", -+ "e", -+ ] -+) - --func([ -- "c", -- "d", -- "e", -- # preserve me but hug brackets --]) -+func( -+ [ -+ "c", -+ "d", -+ "e", -+ # preserve me but hug brackets -+ ] -+) +@@ -95,11 +99,13 @@ + # preserve me but hug brackets + ]) -func([ - "c", @@ -393,33 +248,24 @@ for foo in ["a", "b"]: func( [ -@@ -114,50 +140,68 @@ - func( - [x for x in "long line long line long line long line long line long line long line"] +@@ -111,10 +117,10 @@ ) --func([ -- x -- for x in [ -+func( -+ [ - x -- for x in "long line long line long line long line long line long line long line" -+ for x in [ -+ x -+ for x in "long line long line long line long line long line long line long line" -+ ] - ] --]) -+) - func({"short line"}) --func({ -- "long line", -- "long long line", -- "long long long line", -- "long long long long line", -- "long long long long long line", --}) + func([x for x in "short line"]) +-func( +- [x for x in "long line long line long line long line long line long line long line"] +-) + func([ ++ x for x in "long line long line long line long line long line long line long line" ++]) ++func([ + x + for x in [ + x +@@ -130,13 +136,15 @@ + "long long long long line", + "long long long long long line", + }) -func({{ - "long line", - "long long line", @@ -427,28 +273,7 @@ for foo in ["a", "b"]: - "long long long long line", - "long long long long long line", -}}) --func(( -- "long line", -- "long long line", -- "long long long line", -- "long long long long line", -- "long long long long long line", --)) --func((( -- "long line", -- "long long line", -- "long long long line", -- "long long long long line", -- "long long long long long line", --))) --func([[ -- "long line", -- "long long line", -- "long long long line", -- "long long long long line", -- "long long long long long line", --]]) -+func( ++func({ + { + "long line", + "long long line", @@ -456,53 +281,96 @@ for foo in ["a", "b"]: + "long long long long line", + "long long long long long line", + } -+) -+func( -+ { -+ { -+ "long line", -+ "long long line", -+ "long long long line", -+ "long long long long line", -+ "long long long long long line", -+ } -+ } -+) -+func( -+ ( ++}) + func(( + "long line", + "long long line", +@@ -151,30 +159,62 @@ + "long long long long line", + "long long long long long line", + ))) +-func([[ +- "long line", +- "long long line", +- "long long long line", +- "long long long long line", +- "long long long long long line", +-]]) ++func([ ++ [ + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", -+ ) -+) -+func( -+ ( -+ ( -+ "long line", -+ "long long line", -+ "long long long line", -+ "long long long long line", -+ "long long long long long line", -+ ) -+ ) -+) -+func( -+ [ -+ [ -+ "long line", -+ "long long line", -+ "long long long line", -+ "long long long long line", -+ "long long long long long line", -+ ] + ] -+) ++]) # Do not hug if the argument fits on a single line. - func( -@@ -194,18 +238,24 @@ +-func( +- {"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"} +-) +-func( +- ("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line") +-) +-func( +- ["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"] +-) +-func( +- **{"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit---"} +-) +-func( +- *("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit----") +-) ++func({ ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++}) ++func(( ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++)) ++func([ ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++]) ++func(**{ ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit---", ++}) ++func(*( ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit line", ++ "fit----", ++)) + array = [ + {"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"} + ] +@@ -194,18 +234,24 @@ ) nested_mapping = { @@ -538,148 +406,64 @@ for foo in ["a", "b"]: explicit_exploding = [ [ [ -@@ -214,30 +264,42 @@ - ], - ], - ] --single_item_do_not_explode = Context({ -- "version": get_docs_version(), --}) -+single_item_do_not_explode = Context( -+ { -+ "version": get_docs_version(), -+ } -+) - --foo(*[ -- "long long long long long line", -- "long long long long long line", -- "long long long long long line", --]) -+foo( -+ *[ -+ "long long long long long line", -+ "long long long long long line", -+ "long long long long long line", -+ ] -+) - --foo(*[ -- str(i) for i in range(100000000000000000000000000000000000000000000000000000000000) --]) -+foo( -+ *[ -+ str(i) -+ for i in range(100000000000000000000000000000000000000000000000000000000000) -+ ] -+) - --foo(**{ -- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": 1, -- "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb": 2, -- "ccccccccccccccccccccccccccccccccc": 3, -- **other, --}) -+foo( -+ **{ -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": 1, -+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb": 2, -+ "ccccccccccccccccccccccccccccccccc": 3, -+ **other, -+ } -+) - --foo(**{ -- x: y for x, y in enumerate(["long long long long line", "long long long long line"]) --}) -+foo( -+ **{ -+ x: y -+ for x, y in enumerate(["long long long long line", "long long long long line"]) -+ } -+) +@@ -240,9 +286,9 @@ + }) # Edge case when deciding whether to hug the brackets without inner content. - very_very_very_long_variable = very_very_very_long_module.VeryVeryVeryVeryLongClassName( -@@ -245,11 +307,13 @@ - ) +-very_very_very_long_variable = very_very_very_long_module.VeryVeryVeryVeryLongClassName( +- [[]] +-) ++very_very_very_long_variable = very_very_very_long_module.VeryVeryVeryVeryLongClassName([ ++ [] ++]) for foo in ["a", "b"]: -- output.extend([ -- individual -- for -- # Foobar -- container in xs_by_y[foo] -- # Foobar -- for individual in container["nested"] -- ]) -+ output.extend( -+ [ -+ individual -+ for -+ # Foobar -+ container in xs_by_y[foo] -+ # Foobar -+ for individual in container["nested"] -+ ] -+ ) + output.extend([ ``` ## Ruff Output ```python def foo_brackets(request): - return JsonResponse( - { - "var_1": foo, - "var_2": bar, - } - ) + return JsonResponse({ + "var_1": foo, + "var_2": bar, + }) def foo_square_brackets(request): - return JsonResponse( - [ - "var_1", - "var_2", - ] - ) + return JsonResponse([ + "var_1", + "var_2", + ]) -func( - { - "a": 37, - "b": 42, - "c": 927, - "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111, - } -) +func({ + "a": 37, + "b": 42, + "c": 927, + "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111, +}) -func( - [ - "random_string_number_one", - "random_string_number_two", - "random_string_number_three", - "random_string_number_four", - ] -) +func([ + "random_string_number_one", + "random_string_number_two", + "random_string_number_three", + "random_string_number_four", +]) -func( - { - # expand me - "a": 37, - "b": 42, - "c": 927, - } -) +func({ + # expand me + "a": 37, + "b": 42, + "c": 927, +}) -func( - [ - "a", - "b", - "c", - ] -) +func([ + "a", + "b", + "c", +]) func( [ @@ -714,40 +498,32 @@ func( ] ) -func( - [ # preserve me but hug brackets - "c", - "d", - "e", - ] -) +func([ # preserve me but hug brackets + "c", + "d", + "e", +]) -func( - [ - # preserve me but hug brackets - "c", - "d", - "e", - ] -) +func([ + # preserve me but hug brackets + "c", + "d", + "e", +]) -func( - [ - "c", - # preserve me but hug brackets - "d", - "e", - ] -) +func([ + "c", + # preserve me but hug brackets + "d", + "e", +]) -func( - [ - "c", - "d", - "e", - # preserve me but hug brackets - ] -) +func([ + "c", + "d", + "e", + # preserve me but hug brackets +]) func( [ @@ -767,21 +543,26 @@ func( ) func([x for x in "short line"]) -func( - [x for x in "long line long line long line long line long line long line long line"] -) -func( - [ +func([ + x for x in "long line long line long line long line long line long line long line" +]) +func([ + x + for x in [ x - for x in [ - x - for x in "long line long line long line long line long line long line long line" - ] + for x in "long line long line long line long line long line long line long line" ] -) +]) func({"short line"}) -func( +func({ + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +}) +func({ { "long line", "long long line", @@ -789,66 +570,77 @@ func( "long long long long line", "long long long long long line", } -) -func( - { - { - "long line", - "long long line", - "long long long line", - "long long long long line", - "long long long long long line", - } - } -) -func( - ( +}) +func(( + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +)) +func((( + "long line", + "long long line", + "long long long line", + "long long long long line", + "long long long long long line", +))) +func([ + [ "long line", "long long line", "long long long line", "long long long long line", "long long long long long line", - ) -) -func( - ( - ( - "long line", - "long long line", - "long long long line", - "long long long long line", - "long long long long long line", - ) - ) -) -func( - [ - [ - "long line", - "long long line", - "long long long line", - "long long long long line", - "long long long long long line", - ] ] -) +]) # Do not hug if the argument fits on a single line. -func( - {"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"} -) -func( - ("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line") -) -func( - ["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"] -) -func( - **{"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit---"} -) -func( - *("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit----") -) +func({ + "fit line", + "fit line", + "fit line", + "fit line", + "fit line", + "fit line", + "fit line", +}) +func(( + "fit line", + "fit line", + "fit line", + "fit line", + "fit line", + "fit line", + "fit line", +)) +func([ + "fit line", + "fit line", + "fit line", + "fit line", + "fit line", + "fit line", + "fit line", +]) +func(**{ + "fit line", + "fit line", + "fit line", + "fit line", + "fit line", + "fit line", + "fit---", +}) +func(*( + "fit line", + "fit line", + "fit line", + "fit line", + "fit line", + "fit line", + "fit----", +)) array = [ {"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"} ] @@ -894,59 +686,45 @@ explicit_exploding = [ ], ], ] -single_item_do_not_explode = Context( - { - "version": get_docs_version(), - } -) +single_item_do_not_explode = Context({ + "version": get_docs_version(), +}) -foo( - *[ - "long long long long long line", - "long long long long long line", - "long long long long long line", - ] -) +foo(*[ + "long long long long long line", + "long long long long long line", + "long long long long long line", +]) -foo( - *[ - str(i) - for i in range(100000000000000000000000000000000000000000000000000000000000) - ] -) +foo(*[ + str(i) for i in range(100000000000000000000000000000000000000000000000000000000000) +]) -foo( - **{ - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": 1, - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb": 2, - "ccccccccccccccccccccccccccccccccc": 3, - **other, - } -) +foo(**{ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": 1, + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb": 2, + "ccccccccccccccccccccccccccccccccc": 3, + **other, +}) -foo( - **{ - x: y - for x, y in enumerate(["long long long long line", "long long long long line"]) - } -) +foo(**{ + x: y for x, y in enumerate(["long long long long line", "long long long long line"]) +}) # Edge case when deciding whether to hug the brackets without inner content. -very_very_very_long_variable = very_very_very_long_module.VeryVeryVeryVeryLongClassName( - [[]] -) +very_very_very_long_variable = very_very_very_long_module.VeryVeryVeryVeryLongClassName([ + [] +]) for foo in ["a", "b"]: - output.extend( - [ - individual - for - # Foobar - container in xs_by_y[foo] - # Foobar - for individual in container["nested"] - ] - ) + output.extend([ + individual + for + # Foobar + container in xs_by_y[foo] + # Foobar + for individual in container["nested"] + ]) ``` ## Black Output diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__regression.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__regression.py.snap index e05940e360ce9..1cde924609d48 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__regression.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__regression.py.snap @@ -573,7 +573,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: ```diff --- Black +++ Ruff -@@ -25,41 +25,42 @@ +@@ -25,20 +25,17 @@ "Jaguar", ) @@ -599,27 +599,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: ) - class A: - def foo(): -- XXXXXXXXXXXX.append(( -- "xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx, xxxx_xxxx_xxxxxxxxxx={})".format( -- xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx -- ), -- my_var, -- my_other_var, -- )) -+ XXXXXXXXXXXX.append( -+ ( -+ "xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx, xxxx_xxxx_xxxxxxxxxx={})".format( -+ xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx -+ ), -+ my_var, -+ my_other_var, -+ ) -+ ) - - - class A: +@@ -57,9 +54,11 @@ class B: def foo(): bar( @@ -634,7 +614,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: ), varX, varY, -@@ -70,9 +71,10 @@ +@@ -70,9 +69,10 @@ def foo(xxxx): for xxx_xxxx, _xxx_xxx, _xxx_xxxxx, xxx_xxxx in xxxx: for xxx in xxx_xxxx: @@ -648,7 +628,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: ) -@@ -80,10 +82,11 @@ +@@ -80,10 +80,11 @@ def disappearing_comment(): return ( ( # xx -x xxxxxxx xx xxx xxxxxxx. @@ -662,7 +642,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: "--xxxxxxx --xxxxxx=x --xxxxxx-xxxxx=xxxxxx" " --xxxxxx-xxxx=xxxxxxxxxxx.xxx" ) -@@ -113,18 +116,25 @@ +@@ -113,18 +114,25 @@ func_call_where_string_arg_has_method_call_and_bad_parens( @@ -694,7 +674,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: ) -@@ -132,52 +142,60 @@ +@@ -132,52 +140,60 @@ def append(self): if True: xxxx.xxxxxxx.xxxxx( @@ -788,7 +768,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: } -@@ -185,10 +203,10 @@ +@@ -185,10 +201,10 @@ def foo(self): if True: xxxxx_xxxxxxxxxxxx( @@ -803,7 +783,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: ) -@@ -232,39 +250,24 @@ +@@ -232,39 +248,24 @@ some_dictionary = { "xxxxx006": [ @@ -852,7 +832,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: some_commented_string = ( # This comment stays at the top. "This string is long but not so long that it needs hahahah toooooo be so greatttt" -@@ -279,36 +282,25 @@ +@@ -279,38 +280,27 @@ ) lpar_and_rpar_have_comments = func_call( # LPAR Comment @@ -892,12 +872,14 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: - f" certainly, absolutely {does}." + f"We have to remember to escape {braces}." " Like {these}." f" But not {this}." ) -- --fstring = f"We have to remember to escape {braces}. Like {{these}}. But not {this}." +-fstring = f"We have to remember to escape {braces}. Like {{these}}. But not {this}." +- class A: -@@ -364,10 +356,7 @@ + class B: + def foo(): +@@ -364,10 +354,7 @@ def foo(): if not hasattr(module, name): raise ValueError( @@ -909,7 +891,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: % (name, module_name, get_docs_version()) ) -@@ -382,35 +371,33 @@ +@@ -382,23 +369,19 @@ class Step(StepBase): def who(self): @@ -931,29 +913,16 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: ) --xxxxxxx_xxxxxx_xxxxxxx = xxx([ -- xxxxxxxxxxxx( -- xxxxxx_xxxxxxx=( + xxxxxxx_xxxxxx_xxxxxxx = xxx([ + xxxxxxxxxxxx( + xxxxxx_xxxxxxx=( - '((x.aaaaaaaaa = "xxxxxx.xxxxxxxxxxxxxxxxxxxxx") || (x.xxxxxxxxx =' - ' "xxxxxxxxxxxx")) && ' -- # xxxxx xxxxxxxxxxxx xxxx xxx (xxxxxxxxxxxxxxxx) xx x xxxxxxxxx xx xxxxxx. -- "(x.bbbbbbbbbbbb.xxx != " -- '"xxx:xxx:xxx::cccccccccccc:xxxxxxx-xxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxxxx") && ' -+xxxxxxx_xxxxxx_xxxxxxx = xxx( -+ [ -+ xxxxxxxxxxxx( -+ xxxxxx_xxxxxxx=( -+ '((x.aaaaaaaaa = "xxxxxx.xxxxxxxxxxxxxxxxxxxxx") || (x.xxxxxxxxx = "xxxxxxxxxxxx")) && ' -+ # xxxxx xxxxxxxxxxxx xxxx xxx (xxxxxxxxxxxxxxxx) xx x xxxxxxxxx xx xxxxxx. -+ "(x.bbbbbbbbbbbb.xxx != " -+ '"xxx:xxx:xxx::cccccccccccc:xxxxxxx-xxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxxxx") && ' -+ ) - ) -- ) --]) -+ ] -+) - ++ '((x.aaaaaaaaa = "xxxxxx.xxxxxxxxxxxxxxxxxxxxx") || (x.xxxxxxxxx = "xxxxxxxxxxxx")) && ' + # xxxxx xxxxxxxxxxxx xxxx xxx (xxxxxxxxxxxxxxxx) xx x xxxxxxxxx xx xxxxxx. + "(x.bbbbbbbbbbbb.xxx != " + '"xxx:xxx:xxx::cccccccccccc:xxxxxxx-xxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxxxx") && ' +@@ -409,8 +392,8 @@ if __name__ == "__main__": for i in range(4, 8): cmd = ( @@ -964,7 +933,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: ) -@@ -432,14 +419,12 @@ +@@ -432,14 +415,12 @@ assert xxxxxxx_xxxx in [ x.xxxxx.xxxxxx.xxxxx.xxxxxx, x.xxxxx.xxxxxx.xxxxx.xxxx, @@ -983,7 +952,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: RE_ONE_BACKSLASH = { "asdf_hjkl_jkl": re.compile( -@@ -449,8 +434,7 @@ +@@ -449,8 +430,7 @@ RE_TWO_BACKSLASHES = { "asdf_hjkl_jkl": re.compile( @@ -993,7 +962,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: ), } -@@ -462,13 +446,9 @@ +@@ -462,13 +442,9 @@ # We do NOT split on f-string expressions. print( @@ -1009,7 +978,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: # The parens should NOT be removed in this case. ( -@@ -478,8 +458,8 @@ +@@ -478,8 +454,8 @@ # The parens should NOT be removed in this case. ( @@ -1020,7 +989,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: ) # The parens should NOT be removed in this case. -@@ -518,88 +498,78 @@ +@@ -518,88 +494,78 @@ f"<<{author.display_name}>>\n" ) @@ -1144,7 +1113,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: "6. Click on Create Credential at the top." '7. At the top click the link for "API key".' "8. No application restrictions are needed. Click Create at the bottom." -@@ -613,55 +583,40 @@ +@@ -613,55 +579,40 @@ f"<<{author.display_name}>>\n" ) @@ -1217,7 +1186,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: ) # Regression test for https://github.com/psf/black/issues/3455. -@@ -672,9 +627,11 @@ +@@ -672,9 +623,11 @@ } # Regression test for https://github.com/psf/black/issues/3506. @@ -1281,15 +1250,13 @@ class A: class A: def foo(): - XXXXXXXXXXXX.append( - ( - "xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx, xxxx_xxxx_xxxxxxxxxx={})".format( - xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx - ), - my_var, - my_other_var, - ) - ) + XXXXXXXXXXXX.append(( + "xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx, xxxx_xxxx_xxxxxxxxxx={})".format( + xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx + ), + my_var, + my_other_var, + )) class A: @@ -1620,18 +1587,16 @@ class Step(StepBase): ) -xxxxxxx_xxxxxx_xxxxxxx = xxx( - [ - xxxxxxxxxxxx( - xxxxxx_xxxxxxx=( - '((x.aaaaaaaaa = "xxxxxx.xxxxxxxxxxxxxxxxxxxxx") || (x.xxxxxxxxx = "xxxxxxxxxxxx")) && ' - # xxxxx xxxxxxxxxxxx xxxx xxx (xxxxxxxxxxxxxxxx) xx x xxxxxxxxx xx xxxxxx. - "(x.bbbbbbbbbbbb.xxx != " - '"xxx:xxx:xxx::cccccccccccc:xxxxxxx-xxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxxxx") && ' - ) +xxxxxxx_xxxxxx_xxxxxxx = xxx([ + xxxxxxxxxxxx( + xxxxxx_xxxxxxx=( + '((x.aaaaaaaaa = "xxxxxx.xxxxxxxxxxxxxxxxxxxxx") || (x.xxxxxxxxx = "xxxxxxxxxxxx")) && ' + # xxxxx xxxxxxxxxxxx xxxx xxx (xxxxxxxxxxxxxxxx) xx x xxxxxxxxx xx xxxxxx. + "(x.bbbbbbbbbbbb.xxx != " + '"xxx:xxx:xxx::cccccccccccc:xxxxxxx-xxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxxxx") && ' ) - ] -) + ) +]) if __name__ == "__main__": for i in range(4, 8): From 912c39ce2a540d52a435df907409b5660ba9d049 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 30 Nov 2023 22:04:58 -0500 Subject: [PATCH 076/197] Add support for `@functools.singledispatch` (#8934) ## Summary When a function uses `@functools.singledispatch`, we need to treat the first argument of any implementations as runtime-required. Closes https://github.com/astral-sh/ruff/issues/6849. --- .../flake8_type_checking/singledispatch.py | 34 +++++ crates/ruff_linter/src/checkers/ast/mod.rs | 45 ++++--- .../src/rules/flake8_type_checking/helpers.rs | 116 ++++++++++++++---- .../src/rules/flake8_type_checking/mod.rs | 1 + ...-third-party-import_singledispatch.py.snap | 27 ++++ 5 files changed, 183 insertions(+), 40 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_type_checking/singledispatch.py create mode 100644 crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__typing-only-third-party-import_singledispatch.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/singledispatch.py b/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/singledispatch.py new file mode 100644 index 0000000000000..a519a58b4f15b --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/singledispatch.py @@ -0,0 +1,34 @@ +"""Test module.""" +from __future__ import annotations + +from functools import singledispatch +from typing import TYPE_CHECKING + +from numpy import asarray +from numpy.typing import ArrayLike +from scipy.sparse import spmatrix +from pandas import DataFrame + +if TYPE_CHECKING: + from numpy import ndarray + + +@singledispatch +def to_array_or_mat(a: ArrayLike | spmatrix) -> ndarray | spmatrix: + """Convert arg to array or leaves it as sparse matrix.""" + msg = f"Unhandled type {type(a)}" + raise NotImplementedError(msg) + + +@to_array_or_mat.register +def _(a: ArrayLike) -> ndarray: + return asarray(a) + + +@to_array_or_mat.register +def _(a: spmatrix) -> spmatrix: + return a + + +def _(a: DataFrame) -> DataFrame: + return a diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index d24154badb6f7..11e8e704aa02f 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -492,6 +492,13 @@ where // are enabled. let runtime_annotation = !self.semantic.future_annotations(); + // The first parameter may be a single dispatch. + let mut singledispatch = + flake8_type_checking::helpers::is_singledispatch_implementation( + function_def, + self.semantic(), + ); + self.semantic.push_scope(ScopeKind::Type); if let Some(type_params) = type_params { @@ -505,7 +512,7 @@ where .chain(¶meters.kwonlyargs) { if let Some(expr) = ¶meter_with_default.parameter.annotation { - if runtime_annotation { + if runtime_annotation || singledispatch { self.visit_runtime_annotation(expr); } else { self.visit_annotation(expr); @@ -514,6 +521,7 @@ where if let Some(expr) = ¶meter_with_default.default { self.visit_expr(expr); } + singledispatch = false; } if let Some(arg) = ¶meters.vararg { if let Some(expr) = &arg.annotation { @@ -670,23 +678,24 @@ where // available at runtime. // See: https://docs.python.org/3/reference/simple_stmts.html#annotated-assignment-statements let runtime_annotation = if self.semantic.future_annotations() { - if self.semantic.current_scope().kind.is_class() { - let baseclasses = &self - .settings - .flake8_type_checking - .runtime_evaluated_base_classes; - let decorators = &self - .settings - .flake8_type_checking - .runtime_evaluated_decorators; - flake8_type_checking::helpers::runtime_evaluated( - baseclasses, - decorators, - &self.semantic, - ) - } else { - false - } + self.semantic + .current_scope() + .kind + .as_class() + .is_some_and(|class_def| { + flake8_type_checking::helpers::runtime_evaluated_class( + class_def, + &self + .settings + .flake8_type_checking + .runtime_evaluated_base_classes, + &self + .settings + .flake8_type_checking + .runtime_evaluated_decorators, + &self.semantic, + ) + }) } else { matches!( self.semantic.current_scope().kind, diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs b/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs index d07fe2d6cb1f2..0a51e151f4703 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs @@ -1,7 +1,7 @@ use ruff_python_ast::call_path::from_qualified_name; use ruff_python_ast::helpers::{map_callable, map_subscript}; -use ruff_python_ast::{self as ast}; -use ruff_python_semantic::{Binding, BindingId, BindingKind, ScopeKind, SemanticModel}; +use ruff_python_ast::{self as ast, Expr}; +use ruff_python_semantic::{Binding, BindingId, BindingKind, SemanticModel}; use rustc_hash::FxHashSet; pub(crate) fn is_valid_runtime_import(binding: &Binding, semantic: &SemanticModel) -> bool { @@ -18,25 +18,26 @@ pub(crate) fn is_valid_runtime_import(binding: &Binding, semantic: &SemanticMode } } -pub(crate) fn runtime_evaluated( +pub(crate) fn runtime_evaluated_class( + class_def: &ast::StmtClassDef, base_classes: &[String], decorators: &[String], semantic: &SemanticModel, ) -> bool { - if !base_classes.is_empty() { - if runtime_evaluated_base_class(base_classes, semantic) { - return true; - } + if runtime_evaluated_base_class(class_def, base_classes, semantic) { + return true; } - if !decorators.is_empty() { - if runtime_evaluated_decorators(decorators, semantic) { - return true; - } + if runtime_evaluated_decorators(class_def, decorators, semantic) { + return true; } false } -fn runtime_evaluated_base_class(base_classes: &[String], semantic: &SemanticModel) -> bool { +fn runtime_evaluated_base_class( + class_def: &ast::StmtClassDef, + base_classes: &[String], + semantic: &SemanticModel, +) -> bool { fn inner( class_def: &ast::StmtClassDef, base_classes: &[String], @@ -78,19 +79,21 @@ fn runtime_evaluated_base_class(base_classes: &[String], semantic: &SemanticMode }) } - semantic - .current_scope() - .kind - .as_class() - .is_some_and(|class_def| { - inner(class_def, base_classes, semantic, &mut FxHashSet::default()) - }) + if base_classes.is_empty() { + return false; + } + + inner(class_def, base_classes, semantic, &mut FxHashSet::default()) } -fn runtime_evaluated_decorators(decorators: &[String], semantic: &SemanticModel) -> bool { - let ScopeKind::Class(class_def) = &semantic.current_scope().kind else { +fn runtime_evaluated_decorators( + class_def: &ast::StmtClassDef, + decorators: &[String], + semantic: &SemanticModel, +) -> bool { + if decorators.is_empty() { return false; - }; + } class_def.decorator_list.iter().any(|decorator| { semantic @@ -102,3 +105,72 @@ fn runtime_evaluated_decorators(decorators: &[String], semantic: &SemanticModel) }) }) } + +/// Returns `true` if a function is registered as a `singledispatch` interface. +/// +/// For example, `fun` below is a `singledispatch` interface: +/// ```python +/// from functools import singledispatch +/// +/// @singledispatch +/// def fun(arg, verbose=False): +/// ... +/// ``` +pub(crate) fn is_singledispatch_interface( + function_def: &ast::StmtFunctionDef, + semantic: &SemanticModel, +) -> bool { + function_def.decorator_list.iter().any(|decorator| { + semantic + .resolve_call_path(&decorator.expression) + .is_some_and(|call_path| { + matches!(call_path.as_slice(), ["functools", "singledispatch"]) + }) + }) +} + +/// Returns `true` if a function is registered as a `singledispatch` implementation. +/// +/// For example, `_` below is a `singledispatch` implementation: +/// For example: +/// ```python +/// from functools import singledispatch +/// +/// @singledispatch +/// def fun(arg, verbose=False): +/// ... +/// +/// @fun.register +/// def _(arg: int, verbose=False): +/// ... +/// ``` +pub(crate) fn is_singledispatch_implementation( + function_def: &ast::StmtFunctionDef, + semantic: &SemanticModel, +) -> bool { + function_def.decorator_list.iter().any(|decorator| { + let Expr::Attribute(attribute) = &decorator.expression else { + return false; + }; + + if attribute.attr.as_str() != "register" { + return false; + }; + + let Some(id) = semantic.lookup_attribute(attribute.value.as_ref()) else { + return false; + }; + + let binding = semantic.binding(id); + let Some(function_def) = binding + .kind + .as_function_definition() + .map(|id| &semantic.scopes[*id]) + .and_then(|scope| scope.kind.as_function()) + else { + return false; + }; + + is_singledispatch_interface(function_def, semantic) + }) +} diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/mod.rs b/crates/ruff_linter/src/rules/flake8_type_checking/mod.rs index 97e9ad7cd4af0..82b24755f4277 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/mod.rs @@ -37,6 +37,7 @@ mod tests { #[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("TCH003.py"))] #[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("snapshot.py"))] #[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("TCH002.py"))] + #[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("singledispatch.py"))] #[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("strict.py"))] #[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("typing_modules_1.py"))] #[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("typing_modules_2.py"))] diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__typing-only-third-party-import_singledispatch.py.snap b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__typing-only-third-party-import_singledispatch.py.snap new file mode 100644 index 0000000000000..5b646c6b34011 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__typing-only-third-party-import_singledispatch.py.snap @@ -0,0 +1,27 @@ +--- +source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs +--- +singledispatch.py:10:20: TCH002 [*] Move third-party import `pandas.DataFrame` into a type-checking block + | + 8 | from numpy.typing import ArrayLike + 9 | from scipy.sparse import spmatrix +10 | from pandas import DataFrame + | ^^^^^^^^^ TCH002 +11 | +12 | if TYPE_CHECKING: + | + = help: Move into type-checking block + +ℹ Unsafe fix +7 7 | from numpy import asarray +8 8 | from numpy.typing import ArrayLike +9 9 | from scipy.sparse import spmatrix +10 |-from pandas import DataFrame +11 10 | +12 11 | if TYPE_CHECKING: + 12 |+ from pandas import DataFrame +13 13 | from numpy import ndarray +14 14 | +15 15 | + + From 46a174a22efedd5b8d97942a0f304b01c7e28ccd Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 30 Nov 2023 22:09:18 -0500 Subject: [PATCH 077/197] Use full arguments range for zero-sleep-call (#8936) --- .../test/fixtures/flake8_trio/TRIO115.py | 5 +++ .../flake8_trio/rules/zero_sleep_call.rs | 6 ++- ...lake8_trio__tests__TRIO115_TRIO115.py.snap | 40 ++++++++++++++++--- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO115.py b/crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO115.py index 410408576acc6..aa25cb8e5a3ae 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO115.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO115.py @@ -26,5 +26,10 @@ def func(): from trio import Event, sleep + def func(): sleep(0) # TRIO115 + + +async def func(): + await sleep(seconds=0) # TRIO115 diff --git a/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs b/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs index 6ddd3d572d053..38470abbf99ae 100644 --- a/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs +++ b/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs @@ -16,12 +16,16 @@ use crate::importer::ImportRequest; /// /// ## Example /// ```python +/// import trio +/// /// async def func(): /// await trio.sleep(0) /// ``` /// /// Use instead: /// ```python +/// import trio +/// /// async def func(): /// await trio.lowlevel.checkpoint() /// ``` @@ -103,7 +107,7 @@ pub(crate) fn zero_sleep_call(checker: &mut Checker, call: &ExprCall) { )?; let reference_edit = Edit::range_replacement(format!("{binding}.checkpoint"), call.func.range()); - let arg_edit = Edit::range_deletion(arg.range()); + let arg_edit = Edit::range_replacement("()".to_string(), call.arguments.range()); Ok(Fix::safe_edits(import_edit, [reference_edit, arg_edit])) }); checker.diagnostics.push(diagnostic); diff --git a/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap b/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap index 6b4c34efd1197..0dfeef7c653fb 100644 --- a/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap +++ b/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap @@ -85,10 +85,10 @@ TRIO115.py:17:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.s 19 19 | bar = "bar" 20 20 | trio.sleep(bar) -TRIO115.py:30:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` +TRIO115.py:31:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` | -29 | def func(): -30 | sleep(0) # TRIO115 +30 | def func(): +31 | sleep(0) # TRIO115 | ^^^^^^^^ TRIO115 | = help: Replace with `trio.lowlevel.checkpoint()` @@ -100,8 +100,36 @@ TRIO115.py:30:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.s 27 |-from trio import Event, sleep 27 |+from trio import Event, sleep, lowlevel 28 28 | -29 29 | def func(): -30 |- sleep(0) # TRIO115 - 30 |+ lowlevel.checkpoint() # TRIO115 +29 29 | +30 30 | def func(): +31 |- sleep(0) # TRIO115 + 31 |+ lowlevel.checkpoint() # TRIO115 +32 32 | +33 33 | +34 34 | async def func(): + +TRIO115.py:35:11: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` + | +34 | async def func(): +35 | await sleep(seconds=0) # TRIO115 + | ^^^^^^^^^^^^^^^^ TRIO115 + | + = help: Replace with `trio.lowlevel.checkpoint()` + +ℹ Safe fix +24 24 | trio.run(trio.sleep(0)) # TRIO115 +25 25 | +26 26 | +27 |-from trio import Event, sleep + 27 |+from trio import Event, sleep, lowlevel +28 28 | +29 29 | +30 30 | def func(): +-------------------------------------------------------------------------------- +32 32 | +33 33 | +34 34 | async def func(): +35 |- await sleep(seconds=0) # TRIO115 + 35 |+ await lowlevel.checkpoint() # TRIO115 From 69dfe0a207a2462a71df87dc87eb19fe8018a17a Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 30 Nov 2023 22:34:09 -0500 Subject: [PATCH 078/197] Fix doc formatting for zero-sleep-call (#8937) --- .../ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs b/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs index 38470abbf99ae..6b0e57569c443 100644 --- a/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs +++ b/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs @@ -18,6 +18,7 @@ use crate::importer::ImportRequest; /// ```python /// import trio /// +/// /// async def func(): /// await trio.sleep(0) /// ``` @@ -26,6 +27,7 @@ use crate::importer::ImportRequest; /// ```python /// import trio /// +/// /// async def func(): /// await trio.lowlevel.checkpoint() /// ``` From cb1d3df08509965f96c4d87dc6694ceafb5394ba Mon Sep 17 00:00:00 2001 From: Steve C Date: Fri, 1 Dec 2023 00:09:50 -0500 Subject: [PATCH 079/197] [`pylint`] Implement `unnecessary-dict-index-lookup` (`PLR1733`) (#8036) ## Summary Add [R1733](https://pylint.readthedocs.io/en/latest/user_guide/messages/refactor/unnecessary-dict-index-lookup.html) and autofix! See #970 ## Test Plan `cargo test` and manually --- .../pylint/unnecessary_dict_index_lookup.py | 29 ++ .../src/checkers/ast/analyze/expression.rs | 12 + .../src/checkers/ast/analyze/statement.rs | 3 + crates/ruff_linter/src/codes.rs | 1 + crates/ruff_linter/src/rules/pylint/mod.rs | 4 + .../ruff_linter/src/rules/pylint/rules/mod.rs | 2 + .../rules/unnecessary_dict_index_lookup.rs | 254 ++++++++++++++++++ ...1733_unnecessary_dict_index_lookup.py.snap | 124 +++++++++ ruff.schema.json | 1 + 9 files changed, 430 insertions(+) create mode 100644 crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_dict_index_lookup.py create mode 100644 crates/ruff_linter/src/rules/pylint/rules/unnecessary_dict_index_lookup.rs create mode 100644 crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1733_unnecessary_dict_index_lookup.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_dict_index_lookup.py b/crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_dict_index_lookup.py new file mode 100644 index 0000000000000..cfdd9fc42ae04 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_dict_index_lookup.py @@ -0,0 +1,29 @@ +FRUITS = {"apple": 1, "orange": 10, "berry": 22} + +def fix_these(): + [FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()] # PLR1733 + {FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733 + {fruit_name: FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733 + + for fruit_name, fruit_count in FRUITS.items(): + print(FRUITS[fruit_name]) # PLR1733 + blah = FRUITS[fruit_name] # PLR1733 + assert FRUITS[fruit_name] == "pear" # PLR1733 + + +def dont_fix_these(): + # once there is an assignment to the dict[index], we stop emitting diagnostics + for fruit_name, fruit_count in FRUITS.items(): + FRUITS[fruit_name] = 0 # Ok + assert FRUITS[fruit_name] == 0 # Ok + + +def value_intentionally_unused(): + [FRUITS[fruit_name] for fruit_name, _ in FRUITS.items()] # Ok + {FRUITS[fruit_name] for fruit_name, _ in FRUITS.items()} # Ok + {fruit_name: FRUITS[fruit_name] for fruit_name, _ in FRUITS.items()} # Ok + + for fruit_name, _ in FRUITS.items(): + print(FRUITS[fruit_name]) # Ok + blah = FRUITS[fruit_name] # Ok + assert FRUITS[fruit_name] == "pear" # Ok diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 0f5a7c3b60643..87a354b9641f3 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -1333,6 +1333,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::UnnecessaryListIndexLookup) { pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr); } + if checker.enabled(Rule::UnnecessaryDictIndexLookup) { + pylint::rules::unnecessary_dict_index_lookup_comprehension(checker, expr); + } if checker.enabled(Rule::UnnecessaryComprehension) { flake8_comprehensions::rules::unnecessary_list_set_comprehension( checker, expr, elt, generators, @@ -1360,6 +1363,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::UnnecessaryListIndexLookup) { pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr); } + if checker.enabled(Rule::UnnecessaryDictIndexLookup) { + pylint::rules::unnecessary_dict_index_lookup_comprehension(checker, expr); + } if checker.enabled(Rule::UnnecessaryComprehension) { flake8_comprehensions::rules::unnecessary_list_set_comprehension( checker, expr, elt, generators, @@ -1386,6 +1392,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::UnnecessaryListIndexLookup) { pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr); } + if checker.enabled(Rule::UnnecessaryDictIndexLookup) { + pylint::rules::unnecessary_dict_index_lookup_comprehension(checker, expr); + } if checker.enabled(Rule::UnnecessaryComprehension) { flake8_comprehensions::rules::unnecessary_dict_comprehension( checker, expr, key, value, generators, @@ -1413,6 +1422,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::UnnecessaryListIndexLookup) { pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr); } + if checker.enabled(Rule::UnnecessaryDictIndexLookup) { + pylint::rules::unnecessary_dict_index_lookup_comprehension(checker, expr); + } if checker.enabled(Rule::FunctionUsesLoopVariable) { flake8_bugbear::rules::function_uses_loop_variable(checker, &Node::Expr(expr)); } diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 2208db8779b7d..d4e6162221938 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -1280,6 +1280,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if checker.enabled(Rule::UnnecessaryListIndexLookup) { pylint::rules::unnecessary_list_index_lookup(checker, for_stmt); } + if checker.enabled(Rule::UnnecessaryDictIndexLookup) { + pylint::rules::unnecessary_dict_index_lookup(checker, for_stmt); + } if !is_async { if checker.enabled(Rule::ReimplementedBuiltin) { flake8_simplify::rules::convert_for_loop_to_any_all(checker, stmt); diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index 8ee01e94a1f39..cb1f907b658e0 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -260,6 +260,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Pylint, "R1714") => (RuleGroup::Stable, rules::pylint::rules::RepeatedEqualityComparison), (Pylint, "R1706") => (RuleGroup::Preview, rules::pylint::rules::AndOrTernary), (Pylint, "R1722") => (RuleGroup::Stable, rules::pylint::rules::SysExitAlias), + (Pylint, "R1733") => (RuleGroup::Preview, rules::pylint::rules::UnnecessaryDictIndexLookup), (Pylint, "R1736") => (RuleGroup::Preview, rules::pylint::rules::UnnecessaryListIndexLookup), (Pylint, "R2004") => (RuleGroup::Stable, rules::pylint::rules::MagicValueComparison), (Pylint, "R5501") => (RuleGroup::Stable, rules::pylint::rules::CollapsibleElseIf), diff --git a/crates/ruff_linter/src/rules/pylint/mod.rs b/crates/ruff_linter/src/rules/pylint/mod.rs index f8417646232ea..ba4536eaf9f49 100644 --- a/crates/ruff_linter/src/rules/pylint/mod.rs +++ b/crates/ruff_linter/src/rules/pylint/mod.rs @@ -160,6 +160,10 @@ mod tests { )] #[test_case(Rule::NoClassmethodDecorator, Path::new("no_method_decorator.py"))] #[test_case(Rule::NoStaticmethodDecorator, Path::new("no_method_decorator.py"))] + #[test_case( + Rule::UnnecessaryDictIndexLookup, + Path::new("unnecessary_dict_index_lookup.py") + )] fn rules(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/pylint/rules/mod.rs b/crates/ruff_linter/src/rules/pylint/rules/mod.rs index 6497f9dcb7e27..02ae6796a5dfb 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/mod.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/mod.rs @@ -62,6 +62,7 @@ pub(crate) use type_bivariance::*; pub(crate) use type_name_incorrect_variance::*; pub(crate) use type_param_name_mismatch::*; pub(crate) use unexpected_special_method_signature::*; +pub(crate) use unnecessary_dict_index_lookup::*; pub(crate) use unnecessary_direct_lambda_call::*; pub(crate) use unnecessary_lambda::*; pub(crate) use unnecessary_list_index_lookup::*; @@ -137,6 +138,7 @@ mod type_bivariance; mod type_name_incorrect_variance; mod type_param_name_mismatch; mod unexpected_special_method_signature; +mod unnecessary_dict_index_lookup; mod unnecessary_direct_lambda_call; mod unnecessary_lambda; mod unnecessary_list_index_lookup; diff --git a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dict_index_lookup.rs b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dict_index_lookup.rs new file mode 100644 index 0000000000000..16dc733d61d80 --- /dev/null +++ b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dict_index_lookup.rs @@ -0,0 +1,254 @@ +use ast::Stmt; +use ruff_python_ast::{self as ast, Expr, StmtFor}; + +use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; +use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::visitor; +use ruff_python_ast::visitor::Visitor; +use ruff_text_size::TextRange; + +use crate::checkers::ast::Checker; + +/// ## What it does +/// Checks for key-based dict accesses during `.items()` iterations. +/// +/// ## Why is this bad? +/// When iterating over a dict via `.items()`, the current value is already +/// available alongside its key. Using the key to look up the value is +/// unnecessary. +/// +/// ## Example +/// ```python +/// FRUITS = {"apple": 1, "orange": 10, "berry": 22} +/// +/// for fruit_name, fruit_count in FRUITS.items(): +/// print(FRUITS[fruit_name]) +/// ``` +/// +/// Use instead: +/// ```python +/// FRUITS = {"apple": 1, "orange": 10, "berry": 22} +/// +/// for fruit_name, fruit_count in FRUITS.items(): +/// print(fruit_count) +/// ``` +#[violation] +pub struct UnnecessaryDictIndexLookup; + +impl AlwaysFixableViolation for UnnecessaryDictIndexLookup { + #[derive_message_formats] + fn message(&self) -> String { + format!("Unnecessary lookup of dictionary value by key") + } + + fn fix_title(&self) -> String { + format!("Use existing variable") + } +} + +/// PLR1733 +pub(crate) fn unnecessary_dict_index_lookup(checker: &mut Checker, stmt_for: &StmtFor) { + let Some((dict_name, index_name, value_name)) = dict_items(&stmt_for.iter, &stmt_for.target) + else { + return; + }; + + let ranges = { + let mut visitor = SubscriptVisitor::new(dict_name, index_name); + visitor.visit_body(&stmt_for.body); + visitor.visit_body(&stmt_for.orelse); + visitor.diagnostic_ranges + }; + + for range in ranges { + let mut diagnostic = Diagnostic::new(UnnecessaryDictIndexLookup, range); + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + value_name.to_string(), + range, + ))); + checker.diagnostics.push(diagnostic); + } +} + +/// PLR1733 +pub(crate) fn unnecessary_dict_index_lookup_comprehension(checker: &mut Checker, expr: &Expr) { + let (Expr::GeneratorExp(ast::ExprGeneratorExp { + elt, generators, .. + }) + | Expr::DictComp(ast::ExprDictComp { + value: elt, + generators, + .. + }) + | Expr::SetComp(ast::ExprSetComp { + elt, generators, .. + }) + | Expr::ListComp(ast::ExprListComp { + elt, generators, .. + })) = expr + else { + return; + }; + + for comp in generators { + let Some((dict_name, index_name, value_name)) = dict_items(&comp.iter, &comp.target) else { + continue; + }; + + let ranges = { + let mut visitor = SubscriptVisitor::new(dict_name, index_name); + visitor.visit_expr(elt.as_ref()); + for expr in &comp.ifs { + visitor.visit_expr(expr); + } + visitor.diagnostic_ranges + }; + + for range in ranges { + let mut diagnostic = Diagnostic::new(UnnecessaryDictIndexLookup, range); + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + value_name.to_string(), + range, + ))); + checker.diagnostics.push(diagnostic); + } + } +} + +fn dict_items<'a>( + call_expr: &'a Expr, + tuple_expr: &'a Expr, +) -> Option<(&'a str, &'a str, &'a str)> { + let ast::ExprCall { + func, arguments, .. + } = call_expr.as_call_expr()?; + + if !arguments.is_empty() { + return None; + } + let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() else { + return None; + }; + if attr != "items" { + return None; + } + + let Expr::Name(ast::ExprName { id: dict_name, .. }) = value.as_ref() else { + return None; + }; + + let Expr::Tuple(ast::ExprTuple { elts, .. }) = tuple_expr else { + return None; + }; + let [index, value] = elts.as_slice() else { + return None; + }; + + // Grab the variable names. + let Expr::Name(ast::ExprName { id: index_name, .. }) = index else { + return None; + }; + + let Expr::Name(ast::ExprName { id: value_name, .. }) = value else { + return None; + }; + + // If either of the variable names are intentionally ignored by naming them `_`, then don't + // emit. + if index_name == "_" || value_name == "_" { + return None; + } + + Some((dict_name, index_name, value_name)) +} + +#[derive(Debug)] +struct SubscriptVisitor<'a> { + dict_name: &'a str, + index_name: &'a str, + diagnostic_ranges: Vec, + modified: bool, +} + +impl<'a> SubscriptVisitor<'a> { + fn new(dict_name: &'a str, index_name: &'a str) -> Self { + Self { + dict_name, + index_name, + diagnostic_ranges: Vec::new(), + modified: false, + } + } +} + +impl SubscriptVisitor<'_> { + fn is_assignment(&self, expr: &Expr) -> bool { + let Expr::Subscript(ast::ExprSubscript { value, slice, .. }) = expr else { + return false; + }; + let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { + return false; + }; + if id == self.dict_name { + let Expr::Name(ast::ExprName { id, .. }) = slice.as_ref() else { + return false; + }; + if id == self.index_name { + return true; + } + } + false + } +} + +impl<'a> Visitor<'_> for SubscriptVisitor<'a> { + fn visit_stmt(&mut self, stmt: &Stmt) { + if self.modified { + return; + } + match stmt { + Stmt::Assign(ast::StmtAssign { targets, value, .. }) => { + self.modified = targets.iter().any(|target| self.is_assignment(target)); + self.visit_expr(value); + } + Stmt::AnnAssign(ast::StmtAnnAssign { target, value, .. }) => { + if let Some(value) = value { + self.modified = self.is_assignment(target); + self.visit_expr(value); + } + } + Stmt::AugAssign(ast::StmtAugAssign { target, value, .. }) => { + self.modified = self.is_assignment(target); + self.visit_expr(value); + } + _ => visitor::walk_stmt(self, stmt), + } + } + + fn visit_expr(&mut self, expr: &Expr) { + if self.modified { + return; + } + match expr { + Expr::Subscript(ast::ExprSubscript { + value, + slice, + range, + .. + }) => { + let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { + return; + }; + if id == self.dict_name { + let Expr::Name(ast::ExprName { id, .. }) = slice.as_ref() else { + return; + }; + if id == self.index_name { + self.diagnostic_ranges.push(*range); + } + } + } + _ => visitor::walk_expr(self, expr), + } + } +} diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1733_unnecessary_dict_index_lookup.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1733_unnecessary_dict_index_lookup.py.snap new file mode 100644 index 0000000000000..1f52c2ffe1329 --- /dev/null +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1733_unnecessary_dict_index_lookup.py.snap @@ -0,0 +1,124 @@ +--- +source: crates/ruff_linter/src/rules/pylint/mod.rs +--- +unnecessary_dict_index_lookup.py:4:6: PLR1733 [*] Unnecessary lookup of dictionary value by key + | +3 | def fix_these(): +4 | [FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()] # PLR1733 + | ^^^^^^^^^^^^^^^^^^ PLR1733 +5 | {FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733 +6 | {fruit_name: FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733 + | + = help: Use existing variable + +ℹ Safe fix +1 1 | FRUITS = {"apple": 1, "orange": 10, "berry": 22} +2 2 | +3 3 | def fix_these(): +4 |- [FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()] # PLR1733 + 4 |+ [fruit_count for fruit_name, fruit_count in FRUITS.items()] # PLR1733 +5 5 | {FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733 +6 6 | {fruit_name: FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733 +7 7 | + +unnecessary_dict_index_lookup.py:5:6: PLR1733 [*] Unnecessary lookup of dictionary value by key + | +3 | def fix_these(): +4 | [FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()] # PLR1733 +5 | {FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733 + | ^^^^^^^^^^^^^^^^^^ PLR1733 +6 | {fruit_name: FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733 + | + = help: Use existing variable + +ℹ Safe fix +2 2 | +3 3 | def fix_these(): +4 4 | [FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()] # PLR1733 +5 |- {FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733 + 5 |+ {fruit_count for fruit_name, fruit_count in FRUITS.items()} # PLR1733 +6 6 | {fruit_name: FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733 +7 7 | +8 8 | for fruit_name, fruit_count in FRUITS.items(): + +unnecessary_dict_index_lookup.py:6:18: PLR1733 [*] Unnecessary lookup of dictionary value by key + | +4 | [FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()] # PLR1733 +5 | {FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733 +6 | {fruit_name: FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733 + | ^^^^^^^^^^^^^^^^^^ PLR1733 +7 | +8 | for fruit_name, fruit_count in FRUITS.items(): + | + = help: Use existing variable + +ℹ Safe fix +3 3 | def fix_these(): +4 4 | [FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()] # PLR1733 +5 5 | {FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733 +6 |- {fruit_name: FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733 + 6 |+ {fruit_name: fruit_count for fruit_name, fruit_count in FRUITS.items()} # PLR1733 +7 7 | +8 8 | for fruit_name, fruit_count in FRUITS.items(): +9 9 | print(FRUITS[fruit_name]) # PLR1733 + +unnecessary_dict_index_lookup.py:9:15: PLR1733 [*] Unnecessary lookup of dictionary value by key + | + 8 | for fruit_name, fruit_count in FRUITS.items(): + 9 | print(FRUITS[fruit_name]) # PLR1733 + | ^^^^^^^^^^^^^^^^^^ PLR1733 +10 | blah = FRUITS[fruit_name] # PLR1733 +11 | assert FRUITS[fruit_name] == "pear" # PLR1733 + | + = help: Use existing variable + +ℹ Safe fix +6 6 | {fruit_name: FRUITS[fruit_name] for fruit_name, fruit_count in FRUITS.items()} # PLR1733 +7 7 | +8 8 | for fruit_name, fruit_count in FRUITS.items(): +9 |- print(FRUITS[fruit_name]) # PLR1733 + 9 |+ print(fruit_count) # PLR1733 +10 10 | blah = FRUITS[fruit_name] # PLR1733 +11 11 | assert FRUITS[fruit_name] == "pear" # PLR1733 +12 12 | + +unnecessary_dict_index_lookup.py:10:16: PLR1733 [*] Unnecessary lookup of dictionary value by key + | + 8 | for fruit_name, fruit_count in FRUITS.items(): + 9 | print(FRUITS[fruit_name]) # PLR1733 +10 | blah = FRUITS[fruit_name] # PLR1733 + | ^^^^^^^^^^^^^^^^^^ PLR1733 +11 | assert FRUITS[fruit_name] == "pear" # PLR1733 + | + = help: Use existing variable + +ℹ Safe fix +7 7 | +8 8 | for fruit_name, fruit_count in FRUITS.items(): +9 9 | print(FRUITS[fruit_name]) # PLR1733 +10 |- blah = FRUITS[fruit_name] # PLR1733 + 10 |+ blah = fruit_count # PLR1733 +11 11 | assert FRUITS[fruit_name] == "pear" # PLR1733 +12 12 | +13 13 | + +unnecessary_dict_index_lookup.py:11:16: PLR1733 [*] Unnecessary lookup of dictionary value by key + | + 9 | print(FRUITS[fruit_name]) # PLR1733 +10 | blah = FRUITS[fruit_name] # PLR1733 +11 | assert FRUITS[fruit_name] == "pear" # PLR1733 + | ^^^^^^^^^^^^^^^^^^ PLR1733 + | + = help: Use existing variable + +ℹ Safe fix +8 8 | for fruit_name, fruit_count in FRUITS.items(): +9 9 | print(FRUITS[fruit_name]) # PLR1733 +10 10 | blah = FRUITS[fruit_name] # PLR1733 +11 |- assert FRUITS[fruit_name] == "pear" # PLR1733 + 11 |+ assert fruit_count == "pear" # PLR1733 +12 12 | +13 13 | +14 14 | def dont_fix_these(): + + diff --git a/ruff.schema.json b/ruff.schema.json index 4f39eaeb420e0..b0584cad84735 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -3129,6 +3129,7 @@ "PLR172", "PLR1722", "PLR173", + "PLR1733", "PLR1736", "PLR2", "PLR20", From 506be687825ce315613c51ad917d8053e48eac92 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Fri, 1 Dec 2023 19:02:59 +0900 Subject: [PATCH 080/197] Enable Preview mode for formatter benchmarks (#8944) --- crates/ruff_benchmark/benches/formatter.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/ruff_benchmark/benches/formatter.rs b/crates/ruff_benchmark/benches/formatter.rs index e89b47a102aee..17e6e2d3844e2 100644 --- a/crates/ruff_benchmark/benches/formatter.rs +++ b/crates/ruff_benchmark/benches/formatter.rs @@ -4,7 +4,7 @@ use ruff_benchmark::criterion::{ criterion_group, criterion_main, BenchmarkId, Criterion, Throughput, }; use ruff_benchmark::{TestCase, TestFile, TestFileDownloadError}; -use ruff_python_formatter::{format_module_ast, PyFormatOptions}; +use ruff_python_formatter::{format_module_ast, PreviewMode, PyFormatOptions}; use ruff_python_index::CommentRangesBuilder; use ruff_python_parser::lexer::lex; use ruff_python_parser::{parse_tokens, Mode}; @@ -69,7 +69,8 @@ fn benchmark_formatter(criterion: &mut Criterion) { .expect("Input to be a valid python program"); b.iter(|| { - let options = PyFormatOptions::from_extension(Path::new(case.name())); + let options = PyFormatOptions::from_extension(Path::new(case.name())) + .with_preview(PreviewMode::Enabled); let formatted = format_module_ast(&module, &comment_ranges, case.code(), options) .expect("Formatting to succeed"); From d66063bb33b15da4bf1ca432c4356110c48b4880 Mon Sep 17 00:00:00 2001 From: Tom Kuson Date: Fri, 1 Dec 2023 17:18:52 +0000 Subject: [PATCH 081/197] [`flake8-pyi`] Check for kwarg and vararg `NoReturn` type annotations (#8948) ## Summary Triggers `no-return-argument-annotation-in-stub` (`PYI050`) for vararg and kwarg `NoReturn` type annotations. Related to #8771. ## Test Plan `cargo test` --- .../test/fixtures/flake8_pyi/PYI050.pyi | 11 ++++ .../rules/no_return_argument_annotation.rs | 45 ++++++++++---- ..._flake8_pyi__tests__PYI050_PYI050.pyi.snap | 61 +++++++++++++++++++ 3 files changed, 105 insertions(+), 12 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI050.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI050.pyi index 4720ee7756b6a..583c96e71b59b 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI050.pyi +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI050.pyi @@ -10,3 +10,14 @@ def foo_no_return_typing_extensions( def foo_no_return_kwarg(arg: int, *, arg2: NoReturn): ... # Error: PYI050 def foo_no_return_pos_only(arg: int, /, arg2: NoReturn): ... # Error: PYI050 def foo_never(arg: Never): ... +def foo_args(*args: NoReturn): ... # Error: PYI050 +def foo_kwargs(**kwargs: NoReturn): ... # Error: PYI050 +def foo_args_kwargs(*args: NoReturn, **kwargs: NoReturn): ... # Error: PYI050 +def foo_int_args(*args: int): ... +def foo_int_kwargs(**kwargs: int): ... +def foo_int_args_kwargs(*args: int, **kwargs: int): ... +def foo_int_args_no_return(*args: int, **kwargs: NoReturn): ... # Error: PYI050 +def foo_int_kwargs_no_return(*args: NoReturn, **kwargs: int): ... # Error: PYI050 +def foo_args_never(*args: Never): ... +def foo_kwargs_never(**kwargs: Never): ... +def foo_args_kwargs_never(*args: Never, **kwargs: Never): ... diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/no_return_argument_annotation.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/no_return_argument_annotation.rs index f10946236be2d..01350b9501cc0 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/no_return_argument_annotation.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/no_return_argument_annotation.rs @@ -2,7 +2,7 @@ use std::fmt; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::Parameters; +use ruff_python_ast::{Expr, Parameters}; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -51,6 +51,9 @@ impl Violation for NoReturnArgumentAnnotationInStub { /// PYI050 pub(crate) fn no_return_argument_annotation(checker: &mut Checker, parameters: &Parameters) { + // Ex) def func(arg: NoReturn): ... + // Ex) def func(arg: NoReturn, /): ... + // Ex) def func(*, arg: NoReturn): ... for annotation in parameters .posonlyargs .iter() @@ -58,21 +61,39 @@ pub(crate) fn no_return_argument_annotation(checker: &mut Checker, parameters: & .chain(¶meters.kwonlyargs) .filter_map(|arg| arg.parameter.annotation.as_ref()) { - if checker.semantic().match_typing_expr(annotation, "NoReturn") { - checker.diagnostics.push(Diagnostic::new( - NoReturnArgumentAnnotationInStub { - module: if checker.settings.target_version >= Py311 { - TypingModule::Typing - } else { - TypingModule::TypingExtensions - }, - }, - annotation.range(), - )); + check_no_return_argument_annotation(checker, annotation); + } + + // Ex) def func(*args: NoReturn): ... + if let Some(arg) = ¶meters.vararg { + if let Some(annotation) = &arg.annotation { + check_no_return_argument_annotation(checker, annotation); + } + } + + // Ex) def func(**kwargs: NoReturn): ... + if let Some(arg) = ¶meters.kwarg { + if let Some(annotation) = &arg.annotation { + check_no_return_argument_annotation(checker, annotation); } } } +fn check_no_return_argument_annotation(checker: &mut Checker, annotation: &Expr) { + if checker.semantic().match_typing_expr(annotation, "NoReturn") { + checker.diagnostics.push(Diagnostic::new( + NoReturnArgumentAnnotationInStub { + module: if checker.settings.target_version >= Py311 { + TypingModule::Typing + } else { + TypingModule::TypingExtensions + }, + }, + annotation.range(), + )); + } +} + #[derive(Debug, PartialEq, Eq)] enum TypingModule { Typing, diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI050_PYI050.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI050_PYI050.pyi.snap index a0cb503548fca..caafc0254ea8c 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI050_PYI050.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI050_PYI050.pyi.snap @@ -28,6 +28,67 @@ PYI050.pyi:11:47: PYI050 Prefer `typing.Never` over `NoReturn` for argument anno 11 | def foo_no_return_pos_only(arg: int, /, arg2: NoReturn): ... # Error: PYI050 | ^^^^^^^^ PYI050 12 | def foo_never(arg: Never): ... +13 | def foo_args(*args: NoReturn): ... # Error: PYI050 + | + +PYI050.pyi:13:21: PYI050 Prefer `typing.Never` over `NoReturn` for argument annotations + | +11 | def foo_no_return_pos_only(arg: int, /, arg2: NoReturn): ... # Error: PYI050 +12 | def foo_never(arg: Never): ... +13 | def foo_args(*args: NoReturn): ... # Error: PYI050 + | ^^^^^^^^ PYI050 +14 | def foo_kwargs(**kwargs: NoReturn): ... # Error: PYI050 +15 | def foo_args_kwargs(*args: NoReturn, **kwargs: NoReturn): ... # Error: PYI050 + | + +PYI050.pyi:14:26: PYI050 Prefer `typing.Never` over `NoReturn` for argument annotations + | +12 | def foo_never(arg: Never): ... +13 | def foo_args(*args: NoReturn): ... # Error: PYI050 +14 | def foo_kwargs(**kwargs: NoReturn): ... # Error: PYI050 + | ^^^^^^^^ PYI050 +15 | def foo_args_kwargs(*args: NoReturn, **kwargs: NoReturn): ... # Error: PYI050 +16 | def foo_int_args(*args: int): ... + | + +PYI050.pyi:15:28: PYI050 Prefer `typing.Never` over `NoReturn` for argument annotations + | +13 | def foo_args(*args: NoReturn): ... # Error: PYI050 +14 | def foo_kwargs(**kwargs: NoReturn): ... # Error: PYI050 +15 | def foo_args_kwargs(*args: NoReturn, **kwargs: NoReturn): ... # Error: PYI050 + | ^^^^^^^^ PYI050 +16 | def foo_int_args(*args: int): ... +17 | def foo_int_kwargs(**kwargs: int): ... + | + +PYI050.pyi:15:48: PYI050 Prefer `typing.Never` over `NoReturn` for argument annotations + | +13 | def foo_args(*args: NoReturn): ... # Error: PYI050 +14 | def foo_kwargs(**kwargs: NoReturn): ... # Error: PYI050 +15 | def foo_args_kwargs(*args: NoReturn, **kwargs: NoReturn): ... # Error: PYI050 + | ^^^^^^^^ PYI050 +16 | def foo_int_args(*args: int): ... +17 | def foo_int_kwargs(**kwargs: int): ... + | + +PYI050.pyi:19:50: PYI050 Prefer `typing.Never` over `NoReturn` for argument annotations + | +17 | def foo_int_kwargs(**kwargs: int): ... +18 | def foo_int_args_kwargs(*args: int, **kwargs: int): ... +19 | def foo_int_args_no_return(*args: int, **kwargs: NoReturn): ... # Error: PYI050 + | ^^^^^^^^ PYI050 +20 | def foo_int_kwargs_no_return(*args: NoReturn, **kwargs: int): ... # Error: PYI050 +21 | def foo_args_never(*args: Never): ... + | + +PYI050.pyi:20:37: PYI050 Prefer `typing.Never` over `NoReturn` for argument annotations + | +18 | def foo_int_args_kwargs(*args: int, **kwargs: int): ... +19 | def foo_int_args_no_return(*args: int, **kwargs: NoReturn): ... # Error: PYI050 +20 | def foo_int_kwargs_no_return(*args: NoReturn, **kwargs: int): ... # Error: PYI050 + | ^^^^^^^^ PYI050 +21 | def foo_args_never(*args: Never): ... +22 | def foo_kwargs_never(**kwargs: Never): ... | From e5db72459e1ee9c2f83aaf0e4653b33e4a85bed3 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 1 Dec 2023 12:35:01 -0500 Subject: [PATCH 082/197] Detect implicit returns in auto-return-types (#8952) ## Summary Adds detection for branches without a `return` or `raise`, so that we can properly `Optional` the return types. I'd like to remove this and replace it with our code graph analysis from the `unreachable.rs` rule, but it at least fixes the worst offenders. Closes #8942. --- .../flake8_annotations/auto_return_type.py | 84 ++++++ .../src/rules/flake8_annotations/helpers.rs | 23 +- ..._annotations__tests__auto_return_type.snap | 227 +++++++++++++++ ...tations__tests__auto_return_type_py38.snap | 262 ++++++++++++++++++ ...__flake8_annotations__tests__defaults.snap | 56 +++- ...otations__tests__ignore_fully_untyped.snap | 40 ++- ..._annotations__tests__mypy_init_return.snap | 14 +- crates/ruff_python_ast/src/helpers.rs | 174 ++++++++++++ 8 files changed, 860 insertions(+), 20 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py b/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py index 81ce953ed11e0..ab75a50da712c 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py @@ -63,3 +63,87 @@ def func(x: int): return "str" else: return None + + +def func(x: int): + if x: + return 1 + + +def func(): + x = 1 + + +def func(x: int): + if x > 0: + return 1 + + +def func(x: int): + match x: + case [1, 2, 3]: + return 1 + case 4 as y: + return "foo" + + +def func(x: int): + for i in range(5): + if i > 0: + return 1 + + +def func(x: int): + for i in range(5): + if i > 0: + return 1 + else: + return 4 + + +def func(x: int): + for i in range(5): + if i > 0: + break + else: + return 4 + + +def func(x: int): + try: + pass + except: + return 1 + + +def func(x: int): + try: + pass + except: + return 1 + finally: + return 2 + + +def func(x: int): + try: + pass + except: + return 1 + else: + return 2 + + +def func(x: int): + try: + return 1 + except: + return 2 + else: + pass + + +def func(x: int): + while x > 0: + break + return 1 diff --git a/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs b/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs index 9dc7e896dd106..41cff286d79c5 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs @@ -1,10 +1,9 @@ use itertools::Itertools; -use ruff_diagnostics::Edit; use rustc_hash::FxHashSet; -use crate::importer::{ImportRequest, Importer}; +use ruff_diagnostics::Edit; use ruff_python_ast::helpers::{ - pep_604_union, typing_optional, typing_union, ReturnStatementVisitor, + implicit_return, pep_604_union, typing_optional, typing_union, ReturnStatementVisitor, }; use ruff_python_ast::visitor::Visitor; use ruff_python_ast::{self as ast, Expr, ExprContext}; @@ -13,6 +12,7 @@ use ruff_python_semantic::analyze::visibility; use ruff_python_semantic::{Definition, SemanticModel}; use ruff_text_size::{TextRange, TextSize}; +use crate::importer::{ImportRequest, Importer}; use crate::settings::types::PythonVersion; /// Return the name of the function, if it's overloaded. @@ -48,14 +48,19 @@ pub(crate) fn auto_return_type(function: &ast::StmtFunctionDef) -> Option Option 0: + // return 1 + // ``` + if implicit_return(function) { + return_type = return_type.union(ResolvedPythonType::Atom(PythonType::None)); + } + match return_type { ResolvedPythonType::Atom(python_type) => Some(AutoPythonType::Atom(python_type)), ResolvedPythonType::Union(python_types) => Some(AutoPythonType::Union(python_types)), diff --git a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap index 021e1b520766a..6fcbb95d029f6 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap +++ b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap @@ -200,4 +200,231 @@ auto_return_type.py:59:5: ANN201 [*] Missing return type annotation for public f 61 61 | return 1 62 62 | elif x > 5: +auto_return_type.py:68:5: ANN201 [*] Missing return type annotation for public function `func` + | +68 | def func(x: int): + | ^^^^ ANN201 +69 | if x: +70 | return 1 + | + = help: Add return type annotation: `int | None` + +ℹ Unsafe fix +65 65 | return None +66 66 | +67 67 | +68 |-def func(x: int): + 68 |+def func(x: int) -> int | None: +69 69 | if x: +70 70 | return 1 +71 71 | + +auto_return_type.py:73:5: ANN201 [*] Missing return type annotation for public function `func` + | +73 | def func(): + | ^^^^ ANN201 +74 | x = 1 + | + = help: Add return type annotation: `None` + +ℹ Unsafe fix +70 70 | return 1 +71 71 | +72 72 | +73 |-def func(): + 73 |+def func() -> None: +74 74 | x = 1 +75 75 | +76 76 | + +auto_return_type.py:77:5: ANN201 [*] Missing return type annotation for public function `func` + | +77 | def func(x: int): + | ^^^^ ANN201 +78 | if x > 0: +79 | return 1 + | + = help: Add return type annotation: `int | None` + +ℹ Unsafe fix +74 74 | x = 1 +75 75 | +76 76 | +77 |-def func(x: int): + 77 |+def func(x: int) -> int | None: +78 78 | if x > 0: +79 79 | return 1 +80 80 | + +auto_return_type.py:82:5: ANN201 [*] Missing return type annotation for public function `func` + | +82 | def func(x: int): + | ^^^^ ANN201 +83 | match x: +84 | case [1, 2, 3]: + | + = help: Add return type annotation: `str | int` + +ℹ Unsafe fix +79 79 | return 1 +80 80 | +81 81 | +82 |-def func(x: int): + 82 |+def func(x: int) -> str | int: +83 83 | match x: +84 84 | case [1, 2, 3]: +85 85 | return 1 + +auto_return_type.py:90:5: ANN201 [*] Missing return type annotation for public function `func` + | +90 | def func(x: int): + | ^^^^ ANN201 +91 | for i in range(5): +92 | if i > 0: + | + = help: Add return type annotation: `int | None` + +ℹ Unsafe fix +87 87 | return "foo" +88 88 | +89 89 | +90 |-def func(x: int): + 90 |+def func(x: int) -> int | None: +91 91 | for i in range(5): +92 92 | if i > 0: +93 93 | return 1 + +auto_return_type.py:96:5: ANN201 [*] Missing return type annotation for public function `func` + | +96 | def func(x: int): + | ^^^^ ANN201 +97 | for i in range(5): +98 | if i > 0: + | + = help: Add return type annotation: `int` + +ℹ Unsafe fix +93 93 | return 1 +94 94 | +95 95 | +96 |-def func(x: int): + 96 |+def func(x: int) -> int: +97 97 | for i in range(5): +98 98 | if i > 0: +99 99 | return 1 + +auto_return_type.py:104:5: ANN201 [*] Missing return type annotation for public function `func` + | +104 | def func(x: int): + | ^^^^ ANN201 +105 | for i in range(5): +106 | if i > 0: + | + = help: Add return type annotation: `int | None` + +ℹ Unsafe fix +101 101 | return 4 +102 102 | +103 103 | +104 |-def func(x: int): + 104 |+def func(x: int) -> int | None: +105 105 | for i in range(5): +106 106 | if i > 0: +107 107 | break + +auto_return_type.py:112:5: ANN201 [*] Missing return type annotation for public function `func` + | +112 | def func(x: int): + | ^^^^ ANN201 +113 | try: +114 | pass + | + = help: Add return type annotation: `int | None` + +ℹ Unsafe fix +109 109 | return 4 +110 110 | +111 111 | +112 |-def func(x: int): + 112 |+def func(x: int) -> int | None: +113 113 | try: +114 114 | pass +115 115 | except: + +auto_return_type.py:119:5: ANN201 [*] Missing return type annotation for public function `func` + | +119 | def func(x: int): + | ^^^^ ANN201 +120 | try: +121 | pass + | + = help: Add return type annotation: `int` + +ℹ Unsafe fix +116 116 | return 1 +117 117 | +118 118 | +119 |-def func(x: int): + 119 |+def func(x: int) -> int: +120 120 | try: +121 121 | pass +122 122 | except: + +auto_return_type.py:128:5: ANN201 [*] Missing return type annotation for public function `func` + | +128 | def func(x: int): + | ^^^^ ANN201 +129 | try: +130 | pass + | + = help: Add return type annotation: `int` + +ℹ Unsafe fix +125 125 | return 2 +126 126 | +127 127 | +128 |-def func(x: int): + 128 |+def func(x: int) -> int: +129 129 | try: +130 130 | pass +131 131 | except: + +auto_return_type.py:137:5: ANN201 [*] Missing return type annotation for public function `func` + | +137 | def func(x: int): + | ^^^^ ANN201 +138 | try: +139 | return 1 + | + = help: Add return type annotation: `int` + +ℹ Unsafe fix +134 134 | return 2 +135 135 | +136 136 | +137 |-def func(x: int): + 137 |+def func(x: int) -> int: +138 138 | try: +139 139 | return 1 +140 140 | except: + +auto_return_type.py:146:5: ANN201 [*] Missing return type annotation for public function `func` + | +146 | def func(x: int): + | ^^^^ ANN201 +147 | while x > 0: +148 | break + | + = help: Add return type annotation: `int | None` + +ℹ Unsafe fix +143 143 | pass +144 144 | +145 145 | +146 |-def func(x: int): + 146 |+def func(x: int) -> int | None: +147 147 | while x > 0: +148 148 | break +149 149 | return 1 + diff --git a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type_py38.snap b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type_py38.snap index 0831fcffa3e09..d91484ca3fe71 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type_py38.snap +++ b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type_py38.snap @@ -220,4 +220,266 @@ auto_return_type.py:59:5: ANN201 [*] Missing return type annotation for public f 61 62 | return 1 62 63 | elif x > 5: +auto_return_type.py:68:5: ANN201 [*] Missing return type annotation for public function `func` + | +68 | def func(x: int): + | ^^^^ ANN201 +69 | if x: +70 | return 1 + | + = help: Add return type annotation: `Optional[int]` + +ℹ Unsafe fix + 1 |+from typing import Optional +1 2 | def func(): +2 3 | return 1 +3 4 | +-------------------------------------------------------------------------------- +65 66 | return None +66 67 | +67 68 | +68 |-def func(x: int): + 69 |+def func(x: int) -> Optional[int]: +69 70 | if x: +70 71 | return 1 +71 72 | + +auto_return_type.py:73:5: ANN201 [*] Missing return type annotation for public function `func` + | +73 | def func(): + | ^^^^ ANN201 +74 | x = 1 + | + = help: Add return type annotation: `None` + +ℹ Unsafe fix +70 70 | return 1 +71 71 | +72 72 | +73 |-def func(): + 73 |+def func() -> None: +74 74 | x = 1 +75 75 | +76 76 | + +auto_return_type.py:77:5: ANN201 [*] Missing return type annotation for public function `func` + | +77 | def func(x: int): + | ^^^^ ANN201 +78 | if x > 0: +79 | return 1 + | + = help: Add return type annotation: `Optional[int]` + +ℹ Unsafe fix + 1 |+from typing import Optional +1 2 | def func(): +2 3 | return 1 +3 4 | +-------------------------------------------------------------------------------- +74 75 | x = 1 +75 76 | +76 77 | +77 |-def func(x: int): + 78 |+def func(x: int) -> Optional[int]: +78 79 | if x > 0: +79 80 | return 1 +80 81 | + +auto_return_type.py:82:5: ANN201 [*] Missing return type annotation for public function `func` + | +82 | def func(x: int): + | ^^^^ ANN201 +83 | match x: +84 | case [1, 2, 3]: + | + = help: Add return type annotation: `Union[str | int]` + +ℹ Unsafe fix + 1 |+from typing import Union +1 2 | def func(): +2 3 | return 1 +3 4 | +-------------------------------------------------------------------------------- +79 80 | return 1 +80 81 | +81 82 | +82 |-def func(x: int): + 83 |+def func(x: int) -> Union[str | int]: +83 84 | match x: +84 85 | case [1, 2, 3]: +85 86 | return 1 + +auto_return_type.py:90:5: ANN201 [*] Missing return type annotation for public function `func` + | +90 | def func(x: int): + | ^^^^ ANN201 +91 | for i in range(5): +92 | if i > 0: + | + = help: Add return type annotation: `Optional[int]` + +ℹ Unsafe fix + 1 |+from typing import Optional +1 2 | def func(): +2 3 | return 1 +3 4 | +-------------------------------------------------------------------------------- +87 88 | return "foo" +88 89 | +89 90 | +90 |-def func(x: int): + 91 |+def func(x: int) -> Optional[int]: +91 92 | for i in range(5): +92 93 | if i > 0: +93 94 | return 1 + +auto_return_type.py:96:5: ANN201 [*] Missing return type annotation for public function `func` + | +96 | def func(x: int): + | ^^^^ ANN201 +97 | for i in range(5): +98 | if i > 0: + | + = help: Add return type annotation: `int` + +ℹ Unsafe fix +93 93 | return 1 +94 94 | +95 95 | +96 |-def func(x: int): + 96 |+def func(x: int) -> int: +97 97 | for i in range(5): +98 98 | if i > 0: +99 99 | return 1 + +auto_return_type.py:104:5: ANN201 [*] Missing return type annotation for public function `func` + | +104 | def func(x: int): + | ^^^^ ANN201 +105 | for i in range(5): +106 | if i > 0: + | + = help: Add return type annotation: `Optional[int]` + +ℹ Unsafe fix + 1 |+from typing import Optional +1 2 | def func(): +2 3 | return 1 +3 4 | +-------------------------------------------------------------------------------- +101 102 | return 4 +102 103 | +103 104 | +104 |-def func(x: int): + 105 |+def func(x: int) -> Optional[int]: +105 106 | for i in range(5): +106 107 | if i > 0: +107 108 | break + +auto_return_type.py:112:5: ANN201 [*] Missing return type annotation for public function `func` + | +112 | def func(x: int): + | ^^^^ ANN201 +113 | try: +114 | pass + | + = help: Add return type annotation: `Optional[int]` + +ℹ Unsafe fix + 1 |+from typing import Optional +1 2 | def func(): +2 3 | return 1 +3 4 | +-------------------------------------------------------------------------------- +109 110 | return 4 +110 111 | +111 112 | +112 |-def func(x: int): + 113 |+def func(x: int) -> Optional[int]: +113 114 | try: +114 115 | pass +115 116 | except: + +auto_return_type.py:119:5: ANN201 [*] Missing return type annotation for public function `func` + | +119 | def func(x: int): + | ^^^^ ANN201 +120 | try: +121 | pass + | + = help: Add return type annotation: `int` + +ℹ Unsafe fix +116 116 | return 1 +117 117 | +118 118 | +119 |-def func(x: int): + 119 |+def func(x: int) -> int: +120 120 | try: +121 121 | pass +122 122 | except: + +auto_return_type.py:128:5: ANN201 [*] Missing return type annotation for public function `func` + | +128 | def func(x: int): + | ^^^^ ANN201 +129 | try: +130 | pass + | + = help: Add return type annotation: `int` + +ℹ Unsafe fix +125 125 | return 2 +126 126 | +127 127 | +128 |-def func(x: int): + 128 |+def func(x: int) -> int: +129 129 | try: +130 130 | pass +131 131 | except: + +auto_return_type.py:137:5: ANN201 [*] Missing return type annotation for public function `func` + | +137 | def func(x: int): + | ^^^^ ANN201 +138 | try: +139 | return 1 + | + = help: Add return type annotation: `int` + +ℹ Unsafe fix +134 134 | return 2 +135 135 | +136 136 | +137 |-def func(x: int): + 137 |+def func(x: int) -> int: +138 138 | try: +139 139 | return 1 +140 140 | except: + +auto_return_type.py:146:5: ANN201 [*] Missing return type annotation for public function `func` + | +146 | def func(x: int): + | ^^^^ ANN201 +147 | while x > 0: +148 | break + | + = help: Add return type annotation: `Optional[int]` + +ℹ Unsafe fix + 1 |+from typing import Optional +1 2 | def func(): +2 3 | return 1 +3 4 | +-------------------------------------------------------------------------------- +143 144 | pass +144 145 | +145 146 | +146 |-def func(x: int): + 147 |+def func(x: int) -> Optional[int]: +147 148 | while x > 0: +148 149 | break +149 150 | return 1 + diff --git a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__defaults.snap b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__defaults.snap index 8665fb92ce192..9be33117659ce 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__defaults.snap +++ b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__defaults.snap @@ -1,14 +1,24 @@ --- source: crates/ruff_linter/src/rules/flake8_annotations/mod.rs --- -annotation_presence.py:5:5: ANN201 Missing return type annotation for public function `foo` +annotation_presence.py:5:5: ANN201 [*] Missing return type annotation for public function `foo` | 4 | # Error 5 | def foo(a, b): | ^^^ ANN201 6 | pass | - = help: Add return type annotation + = help: Add return type annotation: `None` + +ℹ Unsafe fix +2 2 | from typing_extensions import override +3 3 | +4 4 | # Error +5 |-def foo(a, b): + 5 |+def foo(a, b) -> None: +6 6 | pass +7 7 | +8 8 | annotation_presence.py:5:9: ANN001 Missing type annotation for function argument `a` | @@ -26,14 +36,24 @@ annotation_presence.py:5:12: ANN001 Missing type annotation for function argumen 6 | pass | -annotation_presence.py:10:5: ANN201 Missing return type annotation for public function `foo` +annotation_presence.py:10:5: ANN201 [*] Missing return type annotation for public function `foo` | 9 | # Error 10 | def foo(a: int, b): | ^^^ ANN201 11 | pass | - = help: Add return type annotation + = help: Add return type annotation: `None` + +ℹ Unsafe fix +7 7 | +8 8 | +9 9 | # Error +10 |-def foo(a: int, b): + 10 |+def foo(a: int, b) -> None: +11 11 | pass +12 12 | +13 13 | annotation_presence.py:10:17: ANN001 Missing type annotation for function argument `b` | @@ -51,23 +71,43 @@ annotation_presence.py:15:17: ANN001 Missing type annotation for function argume 16 | pass | -annotation_presence.py:20:5: ANN201 Missing return type annotation for public function `foo` +annotation_presence.py:20:5: ANN201 [*] Missing return type annotation for public function `foo` | 19 | # Error 20 | def foo(a: int, b: int): | ^^^ ANN201 21 | pass | - = help: Add return type annotation + = help: Add return type annotation: `None` -annotation_presence.py:25:5: ANN201 Missing return type annotation for public function `foo` +ℹ Unsafe fix +17 17 | +18 18 | +19 19 | # Error +20 |-def foo(a: int, b: int): + 20 |+def foo(a: int, b: int) -> None: +21 21 | pass +22 22 | +23 23 | + +annotation_presence.py:25:5: ANN201 [*] Missing return type annotation for public function `foo` | 24 | # Error 25 | def foo(): | ^^^ ANN201 26 | pass | - = help: Add return type annotation + = help: Add return type annotation: `None` + +ℹ Unsafe fix +22 22 | +23 23 | +24 24 | # Error +25 |-def foo(): + 25 |+def foo() -> None: +26 26 | pass +27 27 | +28 28 | annotation_presence.py:45:12: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a` | diff --git a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__ignore_fully_untyped.snap b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__ignore_fully_untyped.snap index a93908081cec1..d806d641b4caa 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__ignore_fully_untyped.snap +++ b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__ignore_fully_untyped.snap @@ -1,13 +1,23 @@ --- source: crates/ruff_linter/src/rules/flake8_annotations/mod.rs --- -ignore_fully_untyped.py:24:5: ANN201 Missing return type annotation for public function `error_partially_typed_1` +ignore_fully_untyped.py:24:5: ANN201 [*] Missing return type annotation for public function `error_partially_typed_1` | 24 | def error_partially_typed_1(a: int, b): | ^^^^^^^^^^^^^^^^^^^^^^^ ANN201 25 | pass | - = help: Add return type annotation + = help: Add return type annotation: `None` + +ℹ Unsafe fix +21 21 | pass +22 22 | +23 23 | +24 |-def error_partially_typed_1(a: int, b): + 24 |+def error_partially_typed_1(a: int, b) -> None: +25 25 | pass +26 26 | +27 27 | ignore_fully_untyped.py:24:37: ANN001 Missing type annotation for function argument `b` | @@ -23,15 +33,25 @@ ignore_fully_untyped.py:28:37: ANN001 Missing type annotation for function argum 29 | pass | -ignore_fully_untyped.py:32:5: ANN201 Missing return type annotation for public function `error_partially_typed_3` +ignore_fully_untyped.py:32:5: ANN201 [*] Missing return type annotation for public function `error_partially_typed_3` | 32 | def error_partially_typed_3(a: int, b: int): | ^^^^^^^^^^^^^^^^^^^^^^^ ANN201 33 | pass | - = help: Add return type annotation + = help: Add return type annotation: `None` + +ℹ Unsafe fix +29 29 | pass +30 30 | +31 31 | +32 |-def error_partially_typed_3(a: int, b: int): + 32 |+def error_partially_typed_3(a: int, b: int) -> None: +33 33 | pass +34 34 | +35 35 | -ignore_fully_untyped.py:43:9: ANN201 Missing return type annotation for public function `error_typed_self` +ignore_fully_untyped.py:43:9: ANN201 [*] Missing return type annotation for public function `error_typed_self` | 41 | pass 42 | @@ -39,6 +59,14 @@ ignore_fully_untyped.py:43:9: ANN201 Missing return type annotation for public f | ^^^^^^^^^^^^^^^^ ANN201 44 | pass | - = help: Add return type annotation + = help: Add return type annotation: `None` + +ℹ Unsafe fix +40 40 | def ok_untyped_method(self): +41 41 | pass +42 42 | +43 |- def error_typed_self(self: X): + 43 |+ def error_typed_self(self: X) -> None: +44 44 | pass diff --git a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__mypy_init_return.snap b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__mypy_init_return.snap index 2ce0c94524eb4..f25fc530bc8cf 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__mypy_init_return.snap +++ b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__mypy_init_return.snap @@ -41,14 +41,24 @@ mypy_init_return.py:11:9: ANN204 [*] Missing return type annotation for special 13 13 | 14 14 | -mypy_init_return.py:40:5: ANN202 Missing return type annotation for private function `__init__` +mypy_init_return.py:40:5: ANN202 [*] Missing return type annotation for private function `__init__` | 39 | # Error 40 | def __init__(self, foo: int): | ^^^^^^^^ ANN202 41 | ... | - = help: Add return type annotation + = help: Add return type annotation: `None` + +ℹ Unsafe fix +37 37 | +38 38 | +39 39 | # Error +40 |-def __init__(self, foo: int): + 40 |+def __init__(self, foo: int) -> None: +41 41 | ... +42 42 | +43 43 | mypy_init_return.py:47:9: ANN204 [*] Missing return type annotation for special method `__init__` | diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index 5d065fa30fc11..cca590903244b 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -911,6 +911,180 @@ where } } +/// Returns `true` if the function has an implicit return. +pub fn implicit_return(function: &ast::StmtFunctionDef) -> bool { + /// Returns `true` if the body may break via a `break` statement. + fn sometimes_breaks(stmts: &[Stmt]) -> bool { + for stmt in stmts { + match stmt { + Stmt::For(ast::StmtFor { body, orelse, .. }) => { + if returns(body) { + return false; + } + if sometimes_breaks(orelse) { + return true; + } + } + Stmt::While(ast::StmtWhile { body, orelse, .. }) => { + if returns(body) { + return false; + } + if sometimes_breaks(orelse) { + return true; + } + } + Stmt::If(ast::StmtIf { + body, + elif_else_clauses, + .. + }) => { + if std::iter::once(body) + .chain(elif_else_clauses.iter().map(|clause| &clause.body)) + .any(|body| sometimes_breaks(body)) + { + return true; + } + } + Stmt::Match(ast::StmtMatch { cases, .. }) => { + if cases.iter().any(|case| sometimes_breaks(&case.body)) { + return true; + } + } + Stmt::Try(ast::StmtTry { + body, + handlers, + orelse, + finalbody, + .. + }) => { + if sometimes_breaks(body) + || handlers.iter().any(|handler| { + let ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler { + body, + .. + }) = handler; + sometimes_breaks(body) + }) + || sometimes_breaks(orelse) + || sometimes_breaks(finalbody) + { + return true; + } + } + Stmt::With(ast::StmtWith { body, .. }) => { + if sometimes_breaks(body) { + return true; + } + } + Stmt::Break(_) => return true, + Stmt::Return(_) => return false, + Stmt::Raise(_) => return false, + _ => {} + } + } + false + } + + /// Returns `true` if the body may break via a `break` statement. + fn always_breaks(stmts: &[Stmt]) -> bool { + for stmt in stmts { + match stmt { + Stmt::Break(_) => return true, + Stmt::Return(_) => return false, + Stmt::Raise(_) => return false, + _ => {} + } + } + false + } + + /// Returns `true` if the body contains a branch that ends without an explicit `return` or + /// `raise` statement. + fn returns(stmts: &[Stmt]) -> bool { + for stmt in stmts.iter().rev() { + match stmt { + Stmt::For(ast::StmtFor { body, orelse, .. }) => { + if always_breaks(body) { + return false; + } + if returns(body) { + return true; + } + if returns(orelse) && !sometimes_breaks(body) { + return true; + } + } + Stmt::While(ast::StmtWhile { body, orelse, .. }) => { + if always_breaks(body) { + return false; + } + if returns(body) { + return true; + } + if returns(orelse) && !sometimes_breaks(body) { + return true; + } + } + Stmt::If(ast::StmtIf { + body, + elif_else_clauses, + .. + }) => { + if elif_else_clauses.iter().any(|clause| clause.test.is_none()) + && std::iter::once(body) + .chain(elif_else_clauses.iter().map(|clause| &clause.body)) + .all(|body| returns(body)) + { + return true; + } + } + Stmt::Match(ast::StmtMatch { cases, .. }) => { + // Note: we assume the `match` is exhaustive. + if cases.iter().all(|case| returns(&case.body)) { + return true; + } + } + Stmt::Try(ast::StmtTry { + body, + handlers, + orelse, + finalbody, + .. + }) => { + // If the `finally` block returns, the `try` block must also return. + if returns(finalbody) { + return true; + } + + // If the `body` or the `else` block returns, the `try` block must also return. + if (returns(body) || returns(orelse)) + && handlers.iter().all(|handler| { + let ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler { + body, + .. + }) = handler; + returns(body) + }) + { + return true; + } + } + Stmt::With(ast::StmtWith { body, .. }) => { + if returns(body) { + return true; + } + } + Stmt::Return(_) => return true, + Stmt::Raise(_) => return true, + _ => {} + } + } + false + } + + !returns(&function.body) +} + /// A [`StatementVisitor`] that collects all `raise` statements in a function or method. #[derive(Default)] pub struct RaiseStatementVisitor<'a> { From 5510a6131e56346957064ccf41e4e83a3bf46647 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 1 Dec 2023 13:22:53 -0500 Subject: [PATCH 083/197] Ignore `@overload` and `@override` methods for too-many-arguments checks (#8954) Closes https://github.com/astral-sh/ruff/issues/8945. --- .../fixtures/pylint/too_many_arguments.py | 13 ++++++++++ .../src/checkers/ast/analyze/statement.rs | 2 +- .../rules/pylint/rules/too_many_arguments.rs | 24 +++++++++++++------ 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/too_many_arguments.py b/crates/ruff_linter/resources/test/fixtures/pylint/too_many_arguments.py index 5271910cc53a4..43b2b178c04e0 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/too_many_arguments.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/too_many_arguments.py @@ -32,3 +32,16 @@ def f(x, y, z, *, u, v, w): # Too many arguments (6/5) def f(x, y, z, a, b, c, *, u, v, w): # Too many arguments (9/5) pass + + +from typing import override, overload + + +@override +def f(x, y, z, a, b, c, *, u, v, w): # OK + pass + + +@overload +def f(x, y, z, a, b, c, *, u, v, w): # OK + pass diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index d4e6162221938..99ea30595f0a6 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -248,7 +248,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { pylint::rules::property_with_parameters(checker, stmt, decorator_list, parameters); } if checker.enabled(Rule::TooManyArguments) { - pylint::rules::too_many_arguments(checker, parameters, stmt); + pylint::rules::too_many_arguments(checker, function_def); } if checker.enabled(Rule::TooManyReturnStatements) { if let Some(diagnostic) = pylint::rules::too_many_return_statements( diff --git a/crates/ruff_linter/src/rules/pylint/rules/too_many_arguments.rs b/crates/ruff_linter/src/rules/pylint/rules/too_many_arguments.rs index 5ddd80ecbc37c..84e5740f6d987 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/too_many_arguments.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/too_many_arguments.rs @@ -1,8 +1,8 @@ -use ruff_python_ast::{Parameters, Stmt}; - use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast as ast; use ruff_python_ast::identifier::Identifier; +use ruff_python_semantic::analyze::visibility; use crate::checkers::ast::Checker; @@ -58,12 +58,13 @@ impl Violation for TooManyArguments { } /// PLR0913 -pub(crate) fn too_many_arguments(checker: &mut Checker, parameters: &Parameters, stmt: &Stmt) { - let num_arguments = parameters +pub(crate) fn too_many_arguments(checker: &mut Checker, function_def: &ast::StmtFunctionDef) { + let num_arguments = function_def + .parameters .args .iter() - .chain(¶meters.kwonlyargs) - .chain(¶meters.posonlyargs) + .chain(&function_def.parameters.kwonlyargs) + .chain(&function_def.parameters.posonlyargs) .filter(|arg| { !checker .settings @@ -71,13 +72,22 @@ pub(crate) fn too_many_arguments(checker: &mut Checker, parameters: &Parameters, .is_match(&arg.parameter.name) }) .count(); + if num_arguments > checker.settings.pylint.max_args { + // Allow excessive arguments in `@override` or `@overload` methods, since they're required + // to adhere to the parent signature. + if visibility::is_override(&function_def.decorator_list, checker.semantic()) + || visibility::is_overload(&function_def.decorator_list, checker.semantic()) + { + return; + } + checker.diagnostics.push(Diagnostic::new( TooManyArguments { c_args: num_arguments, max_args: checker.settings.pylint.max_args, }, - stmt.identifier(), + function_def.identifier(), )); } } From 64c2535e28a121d67ad0f162ef35d31b7b3c2290 Mon Sep 17 00:00:00 2001 From: qdegraaf <34540841+qdegraaf@users.noreply.github.com> Date: Fri, 1 Dec 2023 19:23:56 +0100 Subject: [PATCH 084/197] [`pylint`] Add `add_argument` utility and autofix for `PLW1514` (#8928) ## Summary - Adds `add_argument` similar to existing `remove_argument` utility to safely add arguments to functions. - Adds autofix for `PLW1514` as per specs requested in https://github.com/astral-sh/ruff/issues/8883 as a test ## Test Plan Checks on existing fixtures as well as additional test and fixture for Python 3.9 and lower fix ## Issue Link Closes: https://github.com/astral-sh/ruff/issues/8883 --- .../fixtures/pylint/unspecified_encoding.py | 27 + crates/ruff_linter/src/fix/edits.rs | 32 +- crates/ruff_linter/src/rules/pylint/mod.rs | 11 + .../pylint/rules/unspecified_encoding.rs | 81 ++- ...ests__PLW1514_unspecified_encoding.py.snap | 298 ++++++++++- ...nspecified_encoding_python39_or_lower.snap | 477 ++++++++++++++++++ 6 files changed, 904 insertions(+), 22 deletions(-) create mode 100644 crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__unspecified_encoding_python39_or_lower.snap diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/unspecified_encoding.py b/crates/ruff_linter/resources/test/fixtures/pylint/unspecified_encoding.py index 216fd83513a9c..01c12c9fc4c77 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/unspecified_encoding.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/unspecified_encoding.py @@ -42,3 +42,30 @@ def func(*args, **kwargs): tempfile.SpooledTemporaryFile(0, "w", -1, "utf-8") tempfile.SpooledTemporaryFile(0, "wb") tempfile.SpooledTemporaryFile(0, ) + +open("test.txt",) +open() +open( + "test.txt", # comment +) +open( + "test.txt", + # comment +) +open(("test.txt"),) +open( + ("test.txt"), # comment +) +open( + ("test.txt"), + # comment +) + +open((("test.txt")),) +open( + (("test.txt")), # comment +) +open( + (("test.txt")), + # comment +) diff --git a/crates/ruff_linter/src/fix/edits.rs b/crates/ruff_linter/src/fix/edits.rs index 76257f7f5967b..89d6db3f39d38 100644 --- a/crates/ruff_linter/src/fix/edits.rs +++ b/crates/ruff_linter/src/fix/edits.rs @@ -3,12 +3,14 @@ use anyhow::{Context, Result}; use ruff_diagnostics::Edit; -use ruff_python_ast::AnyNodeRef; +use ruff_python_ast::parenthesize::parenthesized_range; use ruff_python_ast::{self as ast, Arguments, ExceptHandler, Stmt}; +use ruff_python_ast::{AnyNodeRef, ArgOrKeyword}; use ruff_python_codegen::Stylist; use ruff_python_index::Indexer; use ruff_python_trivia::{ - has_leading_content, is_python_whitespace, PythonWhitespace, SimpleTokenKind, SimpleTokenizer, + has_leading_content, is_python_whitespace, CommentRanges, PythonWhitespace, SimpleTokenKind, + SimpleTokenizer, }; use ruff_source_file::{Locator, NewlineWithTrailingNewline, UniversalNewlines}; use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; @@ -138,6 +140,32 @@ pub(crate) fn remove_argument( } } +/// Generic function to add arguments or keyword arguments to function calls. +pub(crate) fn add_argument( + argument: &str, + arguments: &Arguments, + comment_ranges: &CommentRanges, + source: &str, +) -> Edit { + if let Some(last) = arguments.arguments_source_order().last() { + // Case 1: existing arguments, so append after the last argument. + let last = parenthesized_range( + match last { + ArgOrKeyword::Arg(arg) => arg.into(), + ArgOrKeyword::Keyword(keyword) => (&keyword.value).into(), + }, + arguments.into(), + comment_ranges, + source, + ) + .unwrap_or(last.range()); + Edit::insertion(format!(", {argument}"), last.end()) + } else { + // Case 2: no arguments. Add argument, without any trailing comma. + Edit::insertion(argument.to_string(), arguments.start() + TextSize::from(1)) + } +} + /// Determine if a vector contains only one, specific element. fn is_only(vec: &[T], value: &T) -> bool { vec.len() == 1 && vec[0] == *value diff --git a/crates/ruff_linter/src/rules/pylint/mod.rs b/crates/ruff_linter/src/rules/pylint/mod.rs index ba4536eaf9f49..20920043f97b6 100644 --- a/crates/ruff_linter/src/rules/pylint/mod.rs +++ b/crates/ruff_linter/src/rules/pylint/mod.rs @@ -328,4 +328,15 @@ mod tests { assert_messages!(diagnostics); Ok(()) } + + #[test] + fn unspecified_encoding_python39_or_lower() -> Result<()> { + let diagnostics = test_path( + Path::new("pylint/unspecified_encoding.py"), + &LinterSettings::for_rule(Rule::UnspecifiedEncoding) + .with_target_version(PythonVersion::Py39), + )?; + assert_messages!(diagnostics); + Ok(()) + } } diff --git a/crates/ruff_linter/src/rules/pylint/rules/unspecified_encoding.rs b/crates/ruff_linter/src/rules/pylint/rules/unspecified_encoding.rs index 0559919d8e905..b6728df692415 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/unspecified_encoding.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/unspecified_encoding.rs @@ -1,10 +1,16 @@ -use ruff_diagnostics::{Diagnostic, Violation}; +use anyhow::Result; + +use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast as ast; use ruff_python_ast::call_path::{format_call_path, CallPath}; -use ruff_text_size::Ranged; +use ruff_python_ast::Expr; +use ruff_text_size::{Ranged, TextRange}; use crate::checkers::ast::Checker; +use crate::fix::edits::add_argument; +use crate::importer::ImportRequest; +use crate::settings::types::PythonVersion; /// ## What it does /// Checks for uses of `open` and related calls without an explicit `encoding` @@ -15,7 +21,9 @@ use crate::checkers::ast::Checker; /// non-portable code, with differing behavior across platforms. /// /// Instead, consider using the `encoding` parameter to enforce a specific -/// encoding. +/// encoding. [PEP 597] recommends using `locale.getpreferredencoding(False)` +/// as the default encoding on versions earlier than Python 3.10, and +/// `encoding="locale"` on Python 3.10 and later. /// /// ## Example /// ```python @@ -29,13 +37,15 @@ use crate::checkers::ast::Checker; /// /// ## References /// - [Python documentation: `open`](https://docs.python.org/3/library/functions.html#open) +/// +/// [PEP 597]: https://peps.python.org/pep-0597/ #[violation] pub struct UnspecifiedEncoding { function_name: String, mode: Mode, } -impl Violation for UnspecifiedEncoding { +impl AlwaysFixableViolation for UnspecifiedEncoding { #[derive_message_formats] fn message(&self) -> String { let UnspecifiedEncoding { @@ -52,6 +62,10 @@ impl Violation for UnspecifiedEncoding { } } } + + fn fix_title(&self) -> String { + format!("Add explicit `encoding` argument") + } } /// PLW1514 @@ -70,17 +84,63 @@ pub(crate) fn unspecified_encoding(checker: &mut Checker, call: &ast::ExprCall) return; }; - checker.diagnostics.push(Diagnostic::new( + let mut diagnostic = Diagnostic::new( UnspecifiedEncoding { function_name, mode, }, call.func.range(), - )); + ); + + if checker.settings.target_version >= PythonVersion::Py310 { + diagnostic.set_fix(generate_keyword_fix(checker, call)); + } else { + diagnostic.try_set_fix(|| generate_import_fix(checker, call)); + } + + checker.diagnostics.push(diagnostic); +} + +/// Generate an [`Edit`] for Python 3.10 and later. +fn generate_keyword_fix(checker: &Checker, call: &ast::ExprCall) -> Fix { + Fix::unsafe_edit(add_argument( + &format!( + "encoding={}", + checker + .generator() + .expr(&Expr::StringLiteral(ast::ExprStringLiteral { + value: ast::StringLiteralValue::single(ast::StringLiteral { + value: "locale".to_string(), + unicode: false, + range: TextRange::default(), + }), + range: TextRange::default(), + })) + ), + &call.arguments, + checker.indexer().comment_ranges(), + checker.locator().contents(), + )) +} + +/// Generate an [`Edit`] for Python 3.9 and earlier. +fn generate_import_fix(checker: &Checker, call: &ast::ExprCall) -> Result { + let (import_edit, binding) = checker.importer().get_or_import_symbol( + &ImportRequest::import("locale", "getpreferredencoding"), + call.start(), + checker.semantic(), + )?; + let argument_edit = add_argument( + &format!("encoding={binding}(False)"), + &call.arguments, + checker.indexer().comment_ranges(), + checker.locator().contents(), + ); + Ok(Fix::unsafe_edits(import_edit, [argument_edit])) } /// Returns `true` if the given expression is a string literal containing a `b` character. -fn is_binary_mode(expr: &ast::Expr) -> Option { +fn is_binary_mode(expr: &Expr) -> Option { Some( expr.as_string_literal_expr()? .value @@ -92,12 +152,7 @@ fn is_binary_mode(expr: &ast::Expr) -> Option { /// Returns `true` if the given call lacks an explicit `encoding`. fn is_violation(call: &ast::ExprCall, call_path: &CallPath) -> bool { // If we have something like `*args`, which might contain the encoding argument, abort. - if call - .arguments - .args - .iter() - .any(ruff_python_ast::Expr::is_starred_expr) - { + if call.arguments.args.iter().any(Expr::is_starred_expr) { return false; } // If we have something like `**kwargs`, which might contain the encoding argument, abort. diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW1514_unspecified_encoding.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW1514_unspecified_encoding.py.snap index d10f3d3b633fd..9ceaf09daf820 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW1514_unspecified_encoding.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW1514_unspecified_encoding.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/pylint/mod.rs --- -unspecified_encoding.py:8:1: PLW1514 `open` in text mode without explicit `encoding` argument +unspecified_encoding.py:8:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument | 7 | # Errors. 8 | open("test.txt") @@ -9,8 +9,19 @@ unspecified_encoding.py:8:1: PLW1514 `open` in text mode without explicit `encod 9 | io.TextIOWrapper(io.FileIO("test.txt")) 10 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) | + = help: Add explicit `encoding` argument -unspecified_encoding.py:9:1: PLW1514 `io.TextIOWrapper` without explicit `encoding` argument +ℹ Unsafe fix +5 5 | import codecs +6 6 | +7 7 | # Errors. +8 |-open("test.txt") + 8 |+open("test.txt", encoding="locale") +9 9 | io.TextIOWrapper(io.FileIO("test.txt")) +10 10 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) +11 11 | tempfile.NamedTemporaryFile("w") + +unspecified_encoding.py:9:1: PLW1514 [*] `io.TextIOWrapper` without explicit `encoding` argument | 7 | # Errors. 8 | open("test.txt") @@ -19,8 +30,19 @@ unspecified_encoding.py:9:1: PLW1514 `io.TextIOWrapper` without explicit `encodi 10 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) 11 | tempfile.NamedTemporaryFile("w") | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +6 6 | +7 7 | # Errors. +8 8 | open("test.txt") +9 |-io.TextIOWrapper(io.FileIO("test.txt")) + 9 |+io.TextIOWrapper(io.FileIO("test.txt"), encoding="locale") +10 10 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) +11 11 | tempfile.NamedTemporaryFile("w") +12 12 | tempfile.TemporaryFile("w") -unspecified_encoding.py:10:1: PLW1514 `io.TextIOWrapper` without explicit `encoding` argument +unspecified_encoding.py:10:1: PLW1514 [*] `io.TextIOWrapper` without explicit `encoding` argument | 8 | open("test.txt") 9 | io.TextIOWrapper(io.FileIO("test.txt")) @@ -29,8 +51,19 @@ unspecified_encoding.py:10:1: PLW1514 `io.TextIOWrapper` without explicit `encod 11 | tempfile.NamedTemporaryFile("w") 12 | tempfile.TemporaryFile("w") | + = help: Add explicit `encoding` argument -unspecified_encoding.py:11:1: PLW1514 `tempfile.NamedTemporaryFile` in text mode without explicit `encoding` argument +ℹ Unsafe fix +7 7 | # Errors. +8 8 | open("test.txt") +9 9 | io.TextIOWrapper(io.FileIO("test.txt")) +10 |-hugo.TextIOWrapper(hugo.FileIO("test.txt")) + 10 |+hugo.TextIOWrapper(hugo.FileIO("test.txt"), encoding="locale") +11 11 | tempfile.NamedTemporaryFile("w") +12 12 | tempfile.TemporaryFile("w") +13 13 | codecs.open("test.txt") + +unspecified_encoding.py:11:1: PLW1514 [*] `tempfile.NamedTemporaryFile` in text mode without explicit `encoding` argument | 9 | io.TextIOWrapper(io.FileIO("test.txt")) 10 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) @@ -39,8 +72,19 @@ unspecified_encoding.py:11:1: PLW1514 `tempfile.NamedTemporaryFile` in text mode 12 | tempfile.TemporaryFile("w") 13 | codecs.open("test.txt") | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +8 8 | open("test.txt") +9 9 | io.TextIOWrapper(io.FileIO("test.txt")) +10 10 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) +11 |-tempfile.NamedTemporaryFile("w") + 11 |+tempfile.NamedTemporaryFile("w", encoding="locale") +12 12 | tempfile.TemporaryFile("w") +13 13 | codecs.open("test.txt") +14 14 | tempfile.SpooledTemporaryFile(0, "w") -unspecified_encoding.py:12:1: PLW1514 `tempfile.TemporaryFile` in text mode without explicit `encoding` argument +unspecified_encoding.py:12:1: PLW1514 [*] `tempfile.TemporaryFile` in text mode without explicit `encoding` argument | 10 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) 11 | tempfile.NamedTemporaryFile("w") @@ -49,8 +93,19 @@ unspecified_encoding.py:12:1: PLW1514 `tempfile.TemporaryFile` in text mode with 13 | codecs.open("test.txt") 14 | tempfile.SpooledTemporaryFile(0, "w") | + = help: Add explicit `encoding` argument -unspecified_encoding.py:13:1: PLW1514 `codecs.open` in text mode without explicit `encoding` argument +ℹ Unsafe fix +9 9 | io.TextIOWrapper(io.FileIO("test.txt")) +10 10 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) +11 11 | tempfile.NamedTemporaryFile("w") +12 |-tempfile.TemporaryFile("w") + 12 |+tempfile.TemporaryFile("w", encoding="locale") +13 13 | codecs.open("test.txt") +14 14 | tempfile.SpooledTemporaryFile(0, "w") +15 15 | + +unspecified_encoding.py:13:1: PLW1514 [*] `codecs.open` in text mode without explicit `encoding` argument | 11 | tempfile.NamedTemporaryFile("w") 12 | tempfile.TemporaryFile("w") @@ -58,8 +113,19 @@ unspecified_encoding.py:13:1: PLW1514 `codecs.open` in text mode without explici | ^^^^^^^^^^^ PLW1514 14 | tempfile.SpooledTemporaryFile(0, "w") | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +10 10 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) +11 11 | tempfile.NamedTemporaryFile("w") +12 12 | tempfile.TemporaryFile("w") +13 |-codecs.open("test.txt") + 13 |+codecs.open("test.txt", encoding="locale") +14 14 | tempfile.SpooledTemporaryFile(0, "w") +15 15 | +16 16 | # Non-errors. -unspecified_encoding.py:14:1: PLW1514 `tempfile.SpooledTemporaryFile` in text mode without explicit `encoding` argument +unspecified_encoding.py:14:1: PLW1514 [*] `tempfile.SpooledTemporaryFile` in text mode without explicit `encoding` argument | 12 | tempfile.TemporaryFile("w") 13 | codecs.open("test.txt") @@ -68,5 +134,223 @@ unspecified_encoding.py:14:1: PLW1514 `tempfile.SpooledTemporaryFile` in text mo 15 | 16 | # Non-errors. | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +11 11 | tempfile.NamedTemporaryFile("w") +12 12 | tempfile.TemporaryFile("w") +13 13 | codecs.open("test.txt") +14 |-tempfile.SpooledTemporaryFile(0, "w") + 14 |+tempfile.SpooledTemporaryFile(0, "w", encoding="locale") +15 15 | +16 16 | # Non-errors. +17 17 | open("test.txt", encoding="utf-8") + +unspecified_encoding.py:46:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +44 | tempfile.SpooledTemporaryFile(0, ) +45 | +46 | open("test.txt",) + | ^^^^ PLW1514 +47 | open() +48 | open( + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +43 43 | tempfile.SpooledTemporaryFile(0, "wb") +44 44 | tempfile.SpooledTemporaryFile(0, ) +45 45 | +46 |-open("test.txt",) + 46 |+open("test.txt", encoding="locale",) +47 47 | open() +48 48 | open( +49 49 | "test.txt", # comment + +unspecified_encoding.py:47:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +46 | open("test.txt",) +47 | open() + | ^^^^ PLW1514 +48 | open( +49 | "test.txt", # comment + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +44 44 | tempfile.SpooledTemporaryFile(0, ) +45 45 | +46 46 | open("test.txt",) +47 |-open() + 47 |+open(encoding="locale") +48 48 | open( +49 49 | "test.txt", # comment +50 50 | ) + +unspecified_encoding.py:48:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +46 | open("test.txt",) +47 | open() +48 | open( + | ^^^^ PLW1514 +49 | "test.txt", # comment +50 | ) + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +46 46 | open("test.txt",) +47 47 | open() +48 48 | open( +49 |- "test.txt", # comment + 49 |+ "test.txt", encoding="locale", # comment +50 50 | ) +51 51 | open( +52 52 | "test.txt", + +unspecified_encoding.py:51:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +49 | "test.txt", # comment +50 | ) +51 | open( + | ^^^^ PLW1514 +52 | "test.txt", +53 | # comment + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +49 49 | "test.txt", # comment +50 50 | ) +51 51 | open( +52 |- "test.txt", + 52 |+ "test.txt", encoding="locale", +53 53 | # comment +54 54 | ) +55 55 | open(("test.txt"),) + +unspecified_encoding.py:55:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +53 | # comment +54 | ) +55 | open(("test.txt"),) + | ^^^^ PLW1514 +56 | open( +57 | ("test.txt"), # comment + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +52 52 | "test.txt", +53 53 | # comment +54 54 | ) +55 |-open(("test.txt"),) + 55 |+open(("test.txt"), encoding="locale",) +56 56 | open( +57 57 | ("test.txt"), # comment +58 58 | ) + +unspecified_encoding.py:56:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +54 | ) +55 | open(("test.txt"),) +56 | open( + | ^^^^ PLW1514 +57 | ("test.txt"), # comment +58 | ) + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +54 54 | ) +55 55 | open(("test.txt"),) +56 56 | open( +57 |- ("test.txt"), # comment + 57 |+ ("test.txt"), encoding="locale", # comment +58 58 | ) +59 59 | open( +60 60 | ("test.txt"), + +unspecified_encoding.py:59:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +57 | ("test.txt"), # comment +58 | ) +59 | open( + | ^^^^ PLW1514 +60 | ("test.txt"), +61 | # comment + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +57 57 | ("test.txt"), # comment +58 58 | ) +59 59 | open( +60 |- ("test.txt"), + 60 |+ ("test.txt"), encoding="locale", +61 61 | # comment +62 62 | ) +63 63 | + +unspecified_encoding.py:64:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +62 | ) +63 | +64 | open((("test.txt")),) + | ^^^^ PLW1514 +65 | open( +66 | (("test.txt")), # comment + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +61 61 | # comment +62 62 | ) +63 63 | +64 |-open((("test.txt")),) + 64 |+open((("test.txt")), encoding="locale",) +65 65 | open( +66 66 | (("test.txt")), # comment +67 67 | ) + +unspecified_encoding.py:65:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +64 | open((("test.txt")),) +65 | open( + | ^^^^ PLW1514 +66 | (("test.txt")), # comment +67 | ) + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +63 63 | +64 64 | open((("test.txt")),) +65 65 | open( +66 |- (("test.txt")), # comment + 66 |+ (("test.txt")), encoding="locale", # comment +67 67 | ) +68 68 | open( +69 69 | (("test.txt")), + +unspecified_encoding.py:68:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +66 | (("test.txt")), # comment +67 | ) +68 | open( + | ^^^^ PLW1514 +69 | (("test.txt")), +70 | # comment + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +66 66 | (("test.txt")), # comment +67 67 | ) +68 68 | open( +69 |- (("test.txt")), + 69 |+ (("test.txt")), encoding="locale", +70 70 | # comment +71 71 | ) diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__unspecified_encoding_python39_or_lower.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__unspecified_encoding_python39_or_lower.snap new file mode 100644 index 0000000000000..1390eeede0cf3 --- /dev/null +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__unspecified_encoding_python39_or_lower.snap @@ -0,0 +1,477 @@ +--- +source: crates/ruff_linter/src/rules/pylint/mod.rs +--- +unspecified_encoding.py:8:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | + 7 | # Errors. + 8 | open("test.txt") + | ^^^^ PLW1514 + 9 | io.TextIOWrapper(io.FileIO("test.txt")) +10 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 |-open("test.txt") + 9 |+open("test.txt", encoding=locale.getpreferredencoding(False)) +9 10 | io.TextIOWrapper(io.FileIO("test.txt")) +10 11 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) +11 12 | tempfile.NamedTemporaryFile("w") + +unspecified_encoding.py:9:1: PLW1514 [*] `io.TextIOWrapper` without explicit `encoding` argument + | + 7 | # Errors. + 8 | open("test.txt") + 9 | io.TextIOWrapper(io.FileIO("test.txt")) + | ^^^^^^^^^^^^^^^^ PLW1514 +10 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) +11 | tempfile.NamedTemporaryFile("w") + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +9 |-io.TextIOWrapper(io.FileIO("test.txt")) + 10 |+io.TextIOWrapper(io.FileIO("test.txt"), encoding=locale.getpreferredencoding(False)) +10 11 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) +11 12 | tempfile.NamedTemporaryFile("w") +12 13 | tempfile.TemporaryFile("w") + +unspecified_encoding.py:10:1: PLW1514 [*] `io.TextIOWrapper` without explicit `encoding` argument + | + 8 | open("test.txt") + 9 | io.TextIOWrapper(io.FileIO("test.txt")) +10 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) + | ^^^^^^^^^^^^^^^^^^ PLW1514 +11 | tempfile.NamedTemporaryFile("w") +12 | tempfile.TemporaryFile("w") + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +9 10 | io.TextIOWrapper(io.FileIO("test.txt")) +10 |-hugo.TextIOWrapper(hugo.FileIO("test.txt")) + 11 |+hugo.TextIOWrapper(hugo.FileIO("test.txt"), encoding=locale.getpreferredencoding(False)) +11 12 | tempfile.NamedTemporaryFile("w") +12 13 | tempfile.TemporaryFile("w") +13 14 | codecs.open("test.txt") + +unspecified_encoding.py:11:1: PLW1514 [*] `tempfile.NamedTemporaryFile` in text mode without explicit `encoding` argument + | + 9 | io.TextIOWrapper(io.FileIO("test.txt")) +10 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) +11 | tempfile.NamedTemporaryFile("w") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLW1514 +12 | tempfile.TemporaryFile("w") +13 | codecs.open("test.txt") + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +9 10 | io.TextIOWrapper(io.FileIO("test.txt")) +10 11 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) +11 |-tempfile.NamedTemporaryFile("w") + 12 |+tempfile.NamedTemporaryFile("w", encoding=locale.getpreferredencoding(False)) +12 13 | tempfile.TemporaryFile("w") +13 14 | codecs.open("test.txt") +14 15 | tempfile.SpooledTemporaryFile(0, "w") + +unspecified_encoding.py:12:1: PLW1514 [*] `tempfile.TemporaryFile` in text mode without explicit `encoding` argument + | +10 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) +11 | tempfile.NamedTemporaryFile("w") +12 | tempfile.TemporaryFile("w") + | ^^^^^^^^^^^^^^^^^^^^^^ PLW1514 +13 | codecs.open("test.txt") +14 | tempfile.SpooledTemporaryFile(0, "w") + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +9 10 | io.TextIOWrapper(io.FileIO("test.txt")) +10 11 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) +11 12 | tempfile.NamedTemporaryFile("w") +12 |-tempfile.TemporaryFile("w") + 13 |+tempfile.TemporaryFile("w", encoding=locale.getpreferredencoding(False)) +13 14 | codecs.open("test.txt") +14 15 | tempfile.SpooledTemporaryFile(0, "w") +15 16 | + +unspecified_encoding.py:13:1: PLW1514 [*] `codecs.open` in text mode without explicit `encoding` argument + | +11 | tempfile.NamedTemporaryFile("w") +12 | tempfile.TemporaryFile("w") +13 | codecs.open("test.txt") + | ^^^^^^^^^^^ PLW1514 +14 | tempfile.SpooledTemporaryFile(0, "w") + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +-------------------------------------------------------------------------------- +10 11 | hugo.TextIOWrapper(hugo.FileIO("test.txt")) +11 12 | tempfile.NamedTemporaryFile("w") +12 13 | tempfile.TemporaryFile("w") +13 |-codecs.open("test.txt") + 14 |+codecs.open("test.txt", encoding=locale.getpreferredencoding(False)) +14 15 | tempfile.SpooledTemporaryFile(0, "w") +15 16 | +16 17 | # Non-errors. + +unspecified_encoding.py:14:1: PLW1514 [*] `tempfile.SpooledTemporaryFile` in text mode without explicit `encoding` argument + | +12 | tempfile.TemporaryFile("w") +13 | codecs.open("test.txt") +14 | tempfile.SpooledTemporaryFile(0, "w") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLW1514 +15 | +16 | # Non-errors. + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +-------------------------------------------------------------------------------- +11 12 | tempfile.NamedTemporaryFile("w") +12 13 | tempfile.TemporaryFile("w") +13 14 | codecs.open("test.txt") +14 |-tempfile.SpooledTemporaryFile(0, "w") + 15 |+tempfile.SpooledTemporaryFile(0, "w", encoding=locale.getpreferredencoding(False)) +15 16 | +16 17 | # Non-errors. +17 18 | open("test.txt", encoding="utf-8") + +unspecified_encoding.py:46:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +44 | tempfile.SpooledTemporaryFile(0, ) +45 | +46 | open("test.txt",) + | ^^^^ PLW1514 +47 | open() +48 | open( + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +-------------------------------------------------------------------------------- +43 44 | tempfile.SpooledTemporaryFile(0, "wb") +44 45 | tempfile.SpooledTemporaryFile(0, ) +45 46 | +46 |-open("test.txt",) + 47 |+open("test.txt", encoding=locale.getpreferredencoding(False),) +47 48 | open() +48 49 | open( +49 50 | "test.txt", # comment + +unspecified_encoding.py:47:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +46 | open("test.txt",) +47 | open() + | ^^^^ PLW1514 +48 | open( +49 | "test.txt", # comment + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +-------------------------------------------------------------------------------- +44 45 | tempfile.SpooledTemporaryFile(0, ) +45 46 | +46 47 | open("test.txt",) +47 |-open() + 48 |+open(encoding=locale.getpreferredencoding(False)) +48 49 | open( +49 50 | "test.txt", # comment +50 51 | ) + +unspecified_encoding.py:48:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +46 | open("test.txt",) +47 | open() +48 | open( + | ^^^^ PLW1514 +49 | "test.txt", # comment +50 | ) + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +-------------------------------------------------------------------------------- +46 47 | open("test.txt",) +47 48 | open() +48 49 | open( +49 |- "test.txt", # comment + 50 |+ "test.txt", encoding=locale.getpreferredencoding(False), # comment +50 51 | ) +51 52 | open( +52 53 | "test.txt", + +unspecified_encoding.py:51:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +49 | "test.txt", # comment +50 | ) +51 | open( + | ^^^^ PLW1514 +52 | "test.txt", +53 | # comment + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +-------------------------------------------------------------------------------- +49 50 | "test.txt", # comment +50 51 | ) +51 52 | open( +52 |- "test.txt", + 53 |+ "test.txt", encoding=locale.getpreferredencoding(False), +53 54 | # comment +54 55 | ) +55 56 | open(("test.txt"),) + +unspecified_encoding.py:55:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +53 | # comment +54 | ) +55 | open(("test.txt"),) + | ^^^^ PLW1514 +56 | open( +57 | ("test.txt"), # comment + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +-------------------------------------------------------------------------------- +52 53 | "test.txt", +53 54 | # comment +54 55 | ) +55 |-open(("test.txt"),) + 56 |+open(("test.txt"), encoding=locale.getpreferredencoding(False),) +56 57 | open( +57 58 | ("test.txt"), # comment +58 59 | ) + +unspecified_encoding.py:56:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +54 | ) +55 | open(("test.txt"),) +56 | open( + | ^^^^ PLW1514 +57 | ("test.txt"), # comment +58 | ) + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +-------------------------------------------------------------------------------- +54 55 | ) +55 56 | open(("test.txt"),) +56 57 | open( +57 |- ("test.txt"), # comment + 58 |+ ("test.txt"), encoding=locale.getpreferredencoding(False), # comment +58 59 | ) +59 60 | open( +60 61 | ("test.txt"), + +unspecified_encoding.py:59:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +57 | ("test.txt"), # comment +58 | ) +59 | open( + | ^^^^ PLW1514 +60 | ("test.txt"), +61 | # comment + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +-------------------------------------------------------------------------------- +57 58 | ("test.txt"), # comment +58 59 | ) +59 60 | open( +60 |- ("test.txt"), + 61 |+ ("test.txt"), encoding=locale.getpreferredencoding(False), +61 62 | # comment +62 63 | ) +63 64 | + +unspecified_encoding.py:64:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +62 | ) +63 | +64 | open((("test.txt")),) + | ^^^^ PLW1514 +65 | open( +66 | (("test.txt")), # comment + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +-------------------------------------------------------------------------------- +61 62 | # comment +62 63 | ) +63 64 | +64 |-open((("test.txt")),) + 65 |+open((("test.txt")), encoding=locale.getpreferredencoding(False),) +65 66 | open( +66 67 | (("test.txt")), # comment +67 68 | ) + +unspecified_encoding.py:65:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +64 | open((("test.txt")),) +65 | open( + | ^^^^ PLW1514 +66 | (("test.txt")), # comment +67 | ) + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +-------------------------------------------------------------------------------- +63 64 | +64 65 | open((("test.txt")),) +65 66 | open( +66 |- (("test.txt")), # comment + 67 |+ (("test.txt")), encoding=locale.getpreferredencoding(False), # comment +67 68 | ) +68 69 | open( +69 70 | (("test.txt")), + +unspecified_encoding.py:68:1: PLW1514 [*] `open` in text mode without explicit `encoding` argument + | +66 | (("test.txt")), # comment +67 | ) +68 | open( + | ^^^^ PLW1514 +69 | (("test.txt")), +70 | # comment + | + = help: Add explicit `encoding` argument + +ℹ Unsafe fix +3 3 | import tempfile +4 4 | import io as hugo +5 5 | import codecs + 6 |+import locale +6 7 | +7 8 | # Errors. +8 9 | open("test.txt") +-------------------------------------------------------------------------------- +66 67 | (("test.txt")), # comment +67 68 | ) +68 69 | open( +69 |- (("test.txt")), + 70 |+ (("test.txt")), encoding=locale.getpreferredencoding(False), +70 71 | # comment +71 72 | ) + + From 0b1a36f8c8a26549beadeae90e8f65781b1a6240 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Fri, 1 Dec 2023 14:46:39 -0500 Subject: [PATCH 085/197] ruff_python_formatter: light refactoring of code snippet formatting in docstrings (#8950) In the source of working on #8859, I made a number of smallish refactors to how code snippet formatting works. Most or all of these were motivated by writing in support for reStructuredText blocks. They have some fundamentally different requirements than doctests, and there are a lot more ways for reStructuredText blocks to become invalid. (Commit-by-commit review is recommended as the commit messages provide further context on each change. I split this off from ongoing work to make review more manageable.) --- .../fixtures/ruff/docstring_code_examples.py | 9 + .../src/expression/string/docstring.rs | 320 +++++++++++------- .../format@docstring_code_examples.py.snap | 81 +++++ 3 files changed, 291 insertions(+), 119 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py index 1050c71a31847..6f5fc0b30bb61 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py @@ -1,3 +1,12 @@ +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + # The simplest doctest to ensure basic formatting works. def doctest_simple(): """ diff --git a/crates/ruff_python_formatter/src/expression/string/docstring.rs b/crates/ruff_python_formatter/src/expression/string/docstring.rs index 3155fa1a0f532..bed24c34191c0 100644 --- a/crates/ruff_python_formatter/src/expression/string/docstring.rs +++ b/crates/ruff_python_formatter/src/expression/string/docstring.rs @@ -244,10 +244,10 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { mut lines: std::iter::Peekable>, ) -> FormatResult<()> { while let Some(line) = lines.next() { - let line = DocstringLine { - line: Cow::Borrowed(line), + let line = InputDocstringLine { + line, offset: self.offset, - is_last: lines.peek().is_none(), + next: lines.peek().copied(), }; // We know that the normalized string has \n line endings. self.offset += line.line.text_len() + "\n".text_len(); @@ -262,7 +262,7 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { /// immediately to the underlying buffer. If the line starts or is part /// of an existing code snippet, then the lines will get buffered until /// the code snippet is complete. - fn add_one(&mut self, line: DocstringLine<'src>) -> FormatResult<()> { + fn add_one(&mut self, line: InputDocstringLine<'src>) -> FormatResult<()> { // Just pass through the line as-is without looking for a code snippet // when docstring code formatting is disabled. And also when we are // formatting a code snippet so as to avoid arbitrarily nested code @@ -271,45 +271,49 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { // not clear that it's worth the effort to support. if !self.f.options().docstring_code().is_enabled() || self.f.context().docstring().is_some() { - return self.print_one(&line); + return self.print_one(&line.as_output()); } match self.code_example.add(line) { - CodeExampleAddAction::Print { original } => self.print_one(&original)?, + CodeExampleAddAction::Print { original } => self.print_one(&original.as_output())?, CodeExampleAddAction::Kept => {} - CodeExampleAddAction::Format { - kind, - code, - original, - } => { - let Some(formatted_lines) = self.format(&code)? else { + CodeExampleAddAction::Reset { code, original } => { + for codeline in code { + self.print_one(&codeline.original.as_output())?; + } + self.print_one(&original.as_output())?; + } + CodeExampleAddAction::Format { mut kind, original } => { + let Some(formatted_lines) = self.format(kind.code())? else { // If formatting failed in a way that should not be // allowed, we back out what we're doing and print the // original lines we found as-is as if we did nothing. - for codeline in code { - self.print_one(&codeline.original)?; + for codeline in kind.code() { + self.print_one(&codeline.original.as_output())?; } if let Some(original) = original { - self.print_one(&original)?; + self.print_one(&original.as_output())?; } return Ok(()); }; self.already_normalized = false; match kind { - CodeExampleKind::Doctest(CodeExampleDoctest { indent }) => { + CodeExampleKind::Doctest(CodeExampleDoctest { ps1_indent, .. }) => { let mut lines = formatted_lines.into_iter(); if let Some(first) = lines.next() { - self.print_one(&first.map(|line| std::format!("{indent}>>> {line}")))?; + self.print_one( + &first.map(|line| std::format!("{ps1_indent}>>> {line}")), + )?; for docline in lines { self.print_one( - &docline.map(|line| std::format!("{indent}... {line}")), + &docline.map(|line| std::format!("{ps1_indent}... {line}")), )?; } } } } if let Some(original) = original { - self.print_one(&original)?; + self.print_one(&original.as_output())?; } } } @@ -321,7 +325,7 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { /// This mostly just handles indentation and ensuring line breaks are /// inserted as appropriate before passing it on to the formatter to /// print to the buffer. - fn print_one(&mut self, line: &DocstringLine<'_>) -> FormatResult<()> { + fn print_one(&mut self, line: &OutputDocstringLine<'_>) -> FormatResult<()> { let trim_end = line.line.trim_end(); if trim_end.is_empty() { return if line.is_last { @@ -391,10 +395,14 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { /// routine is silent about it. So from the user's perspective, this will /// fail silently. Ideally, this would at least emit a warning message, /// but at time of writing, it wasn't clear to me how to best do that. + /// + /// # Panics + /// + /// This panics when the given slice is empty. fn format( &mut self, - code: &[CodeExampleLine<'src>], - ) -> FormatResult>>> { + code: &[CodeExampleLine<'_>], + ) -> FormatResult>>> { use ruff_python_parser::AsMode; let offset = code @@ -406,10 +414,10 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { .last() .expect("code blob must be non-empty") .original - .is_last; + .is_last(); let codeblob = code .iter() - .map(|line| &*line.code) + .map(|line| line.code) .collect::>() .join("\n"); let printed = match docstring_format_source(self.f.options(), self.quote_style, &codeblob) { @@ -451,8 +459,8 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { let mut lines = printed .as_code() .lines() - .map(|line| DocstringLine { - line: Cow::Owned(line.into()), + .map(|line| OutputDocstringLine { + line: Cow::Owned(line.to_string()), offset, is_last: false, }) @@ -466,29 +474,72 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { /// Represents a single line in a docstring. /// -/// This type is used to both represent the original lines in a docstring -/// (the line will be borrowed) and also the newly formatted lines from code -/// snippets (the line will be owned). -#[derive(Clone, Debug)] -struct DocstringLine<'src> { +/// This type is only used to represent the original lines in a docstring. +/// Specifically, the line contained in this type has no changes from the input +/// source. +#[derive(Clone, Copy, Debug)] +struct InputDocstringLine<'src> { /// The actual text of the line, not including the line terminator. /// /// In practice, this line is borrowed when it corresponds to an original /// unformatted line in a docstring, and owned when it corresponds to a /// reformatted line (e.g., from a code snippet) in a docstring. + line: &'src str, + /// The offset into the source document which this line corresponds to. + offset: TextSize, + /// For any input line that isn't the last line, this contains a reference + /// to the line immediately following this one. + /// + /// This is `None` if and only if this is the last line in the docstring. + next: Option<&'src str>, +} + +impl<'src> InputDocstringLine<'src> { + /// Borrow this input docstring line as an output docstring line. + fn as_output(&self) -> OutputDocstringLine<'src> { + OutputDocstringLine { + line: Cow::Borrowed(self.line), + offset: self.offset, + is_last: self.is_last(), + } + } + + /// Whether this is the last line in the docstring or not. + fn is_last(&self) -> bool { + self.next.is_none() + } +} + +/// Represents a single reformatted code line in a docstring. +/// +/// An input source line may be cheaply converted to an output source line. +/// This is the common case: an input source line is printed pretty much as it +/// is, with perhaps some whitespace normalization applied. The less common +/// case is that the output docstring line owns its `line` because it was +/// produced by reformatting a code snippet. +#[derive(Clone, Debug)] +struct OutputDocstringLine<'src> { + /// The output line. + /// + /// This is an owned variant in precisely the cases where it corresponds to + /// a line from a reformatted code snippet. In other cases, it is borrowed + /// from the input docstring line as-is. line: Cow<'src, str>, /// The offset into the source document which this line corresponds to. + /// Currently, this is an estimate. offset: TextSize, - /// Whether this is the last line in a docstring or not. "Last" lines have - /// some special treatment when printing. + /// Whether this is the last line in a docstring or not. This is determined + /// by whether the last line in the code snippet was also the last line in + /// the docstring. If it was, then it follows that the last line in the + /// reformatted code snippet is also the last line in the docstring. is_last: bool, } -impl<'src> DocstringLine<'src> { - /// Return this line, but with the given function applied to the text of - /// the line. - fn map(self, mut map: impl FnMut(&str) -> String) -> DocstringLine<'static> { - DocstringLine { +impl<'src> OutputDocstringLine<'src> { + /// Return this reformatted line, but with the given function applied to + /// the text of the line. + fn map(self, mut map: impl FnMut(&str) -> String) -> OutputDocstringLine<'static> { + OutputDocstringLine { line: Cow::Owned(map(&self.line)), ..self } @@ -507,9 +558,10 @@ impl<'src> DocstringLine<'src> { struct CodeExample<'src> { /// The kind of code example being collected, or `None` if no code example /// has been observed. - kind: Option, - /// The lines that have been seen so far that make up the code example. - lines: Vec>, + /// + /// The kind is split out into a separate type so that we can pass it + /// around and have a guarantee that a code example actually exists. + kind: Option>, } impl<'src> CodeExample<'src> { @@ -520,7 +572,7 @@ impl<'src> CodeExample<'src> { /// the caller to perform. The typical case is a "print" action, which /// instructs the caller to just print the line as though it were not part /// of a code snippet. - fn add(&mut self, original: DocstringLine<'src>) -> CodeExampleAddAction<'src> { + fn add(&mut self, original: InputDocstringLine<'src>) -> CodeExampleAddAction<'src> { match self.kind.take() { // There's no existing code example being built, so we look for // the start of one or otherwise tell the caller we couldn't find @@ -529,19 +581,15 @@ impl<'src> CodeExample<'src> { None => CodeExampleAddAction::Kept, Some(original) => CodeExampleAddAction::Print { original }, }, - Some(CodeExampleKind::Doctest(doctest)) => { - if let Some(code) = doctest_find_ps2_prompt(&doctest.indent, &original.line) { - let code = code.to_string(); - self.lines.push(CodeExampleLine { original, code }); + Some(CodeExampleKind::Doctest(mut doctest)) => { + if doctest.add_code_line(original) { // Stay with the doctest kind while we accumulate all // PS2 prompts. self.kind = Some(CodeExampleKind::Doctest(doctest)); return CodeExampleAddAction::Kept; } - let code = std::mem::take(&mut self.lines); let original = self.add_start(original); CodeExampleAddAction::Format { - code, kind: CodeExampleKind::Doctest(doctest), original, } @@ -558,13 +606,13 @@ impl<'src> CodeExample<'src> { /// This panics when the existing code-example is any non-None value. That /// is, this routine assumes that there is no ongoing code example being /// collected and looks for the beginning of another code example. - fn add_start(&mut self, original: DocstringLine<'src>) -> Option> { - assert_eq!(None, self.kind, "expected no existing code example"); - if let Some((indent, code)) = doctest_find_ps1_prompt(&original.line) { - let indent = indent.to_string(); - let code = code.to_string(); - self.lines.push(CodeExampleLine { original, code }); - self.kind = Some(CodeExampleKind::Doctest(CodeExampleDoctest { indent })); + fn add_start( + &mut self, + original: InputDocstringLine<'src>, + ) -> Option> { + assert!(self.kind.is_none(), "expected no existing code example"); + if let Some(doctest) = CodeExampleDoctest::new(original) { + self.kind = Some(CodeExampleKind::Doctest(doctest)); return None; } Some(original) @@ -572,8 +620,8 @@ impl<'src> CodeExample<'src> { } /// The kind of code example observed in a docstring. -#[derive(Clone, Debug, Eq, PartialEq)] -enum CodeExampleKind { +#[derive(Debug)] +enum CodeExampleKind<'src> { /// Code found in Python "doctests." /// /// Documentation describing doctests and how they're recognized can be @@ -584,17 +632,90 @@ enum CodeExampleKind { /// doctest module to determine more precisely how it works.) /// /// [regex matching]: https://github.com/python/cpython/blob/0ff6368519ed7542ad8b443de01108690102420a/Lib/doctest.py#L611-L622 - Doctest(CodeExampleDoctest), + Doctest(CodeExampleDoctest<'src>), +} + +impl<'src> CodeExampleKind<'src> { + /// Return the lines of code collected so far for this example. + /// + /// This is borrowed mutably because it may need to mutate the code lines + /// based on the state accrued so far. + fn code(&mut self) -> &[CodeExampleLine<'src>] { + match *self { + CodeExampleKind::Doctest(ref doctest) => &doctest.lines, + } + } } /// State corresponding to a single doctest code example found in a docstring. -#[derive(Clone, Debug, Eq, PartialEq)] -struct CodeExampleDoctest { +#[derive(Debug)] +struct CodeExampleDoctest<'src> { + /// The lines that have been seen so far that make up the doctest. + lines: Vec>, /// The indent observed in the first doctest line. /// /// More precisely, this corresponds to the whitespace observed before /// the starting `>>> ` (the "PS1 prompt"). - indent: String, + ps1_indent: &'src str, +} + +impl<'src> CodeExampleDoctest<'src> { + /// Looks for a valid doctest PS1 prompt in the line given. + /// + /// If one was found, then state for a new doctest code example is + /// returned, along with the code example line. + fn new(original: InputDocstringLine<'src>) -> Option> { + let trim_start = original.line.trim_start(); + // Prompts must be followed by an ASCII space character[1]. + // + // [1]: https://github.com/python/cpython/blob/0ff6368519ed7542ad8b443de01108690102420a/Lib/doctest.py#L809-L812 + let code = trim_start.strip_prefix(">>> ")?; + let indent_len = original + .line + .len() + .checked_sub(trim_start.len()) + .expect("suffix is <= original"); + let lines = vec![CodeExampleLine { original, code }]; + let ps1_indent = &original.line[..indent_len]; + let doctest = CodeExampleDoctest { lines, ps1_indent }; + Some(doctest) + } + + /// Looks for a valid doctest PS2 prompt in the line given. + /// + /// If one is found, then the code portion of the line following the PS2 prompt + /// is returned. + /// + /// Callers must provide a string containing the original indentation of the + /// PS1 prompt that started the doctest containing the potential PS2 prompt + /// in the line given. If the line contains a PS2 prompt, its indentation must + /// match the indentation used for the corresponding PS1 prompt (otherwise + /// `None` will be returned). + fn add_code_line(&mut self, original: InputDocstringLine<'src>) -> bool { + let Some((ps2_indent, ps2_after)) = original.line.split_once("...") else { + return false; + }; + // PS2 prompts must have the same indentation as their + // corresponding PS1 prompt.[1] While the 'doctest' Python + // module will error in this case, we just treat this line as a + // non-doctest line. + // + // [1]: https://github.com/python/cpython/blob/0ff6368519ed7542ad8b443de01108690102420a/Lib/doctest.py#L733 + if self.ps1_indent != ps2_indent { + return false; + } + // PS2 prompts must be followed by an ASCII space character unless + // it's an otherwise empty line[1]. + // + // [1]: https://github.com/python/cpython/blob/0ff6368519ed7542ad8b443de01108690102420a/Lib/doctest.py#L809-L812 + let code = match ps2_after.strip_prefix(' ') { + None if ps2_after.is_empty() => "", + None => return false, + Some(code) => code, + }; + self.lines.push(CodeExampleLine { original, code }); + true + } } /// A single line in a code example found in a docstring. @@ -615,9 +736,9 @@ struct CodeExampleLine<'src> { /// The normalized (but original) line from the doc string. This might, for /// example, contain a `>>> ` or `... ` prefix if this code example is a /// doctest. - original: DocstringLine<'src>, + original: InputDocstringLine<'src>, /// The code extracted from the line. - code: String, + code: &'src str, } /// An action that a caller should perform after attempting to add a line from @@ -633,7 +754,7 @@ enum CodeExampleAddAction<'src> { /// /// This is the common case. That is, most lines in most docstrings are not /// part of a code example. - Print { original: DocstringLine<'src> }, + Print { original: InputDocstringLine<'src> }, /// The line added was kept by `CodeExample` as part of a new or existing /// code example. /// @@ -647,68 +768,29 @@ enum CodeExampleAddAction<'src> { /// callers should pass it through to the formatter as-is. Format { /// The kind of code example that was found. - kind: CodeExampleKind, - /// The Python code that should be formatted, indented and printed. /// - /// This is guaranteed to be non-empty. - code: Vec>, + /// This is guaranteed to have a non-empty code snippet. + kind: CodeExampleKind<'src>, /// When set, the line is considered not part of any code example and /// should be formatted as if the [`Print`] action were returned. /// Otherwise, if there is no line, then either one does not exist /// or it is part of another code example and should be treated as a /// [`Kept`] action. - original: Option>, + original: Option>, + }, + /// This occurs when adding a line to an existing code example + /// results in that code example becoming invalid. In this case, + /// we don't want to treat it as a code example, but instead write + /// back the lines to the docstring unchanged. + #[allow(dead_code)] // FIXME: remove when reStructuredText support is added + Reset { + /// The lines of code that we collected but should be printed back to + /// the docstring as-is and not formatted. + code: Vec>, + /// The line that was added and triggered this reset to occur. It + /// should be written back to the docstring as-is after the code lines. + original: InputDocstringLine<'src>, }, -} - -/// Looks for a valid doctest PS1 prompt in the line given. -/// -/// If one was found, then the indentation prior to the prompt is returned -/// along with the code portion of the line. -fn doctest_find_ps1_prompt(line: &str) -> Option<(&str, &str)> { - let trim_start = line.trim_start(); - // Prompts must be followed by an ASCII space character[1]. - // - // [1]: https://github.com/python/cpython/blob/0ff6368519ed7542ad8b443de01108690102420a/Lib/doctest.py#L809-L812 - let code = trim_start.strip_prefix(">>> ")?; - let indent_len = line - .len() - .checked_sub(trim_start.len()) - .expect("suffix is <= original"); - let indent = &line[..indent_len]; - Some((indent, code)) -} - -/// Looks for a valid doctest PS2 prompt in the line given. -/// -/// If one is found, then the code portion of the line following the PS2 prompt -/// is returned. -/// -/// Callers must provide a string containing the original indentation of the -/// PS1 prompt that started the doctest containing the potential PS2 prompt -/// in the line given. If the line contains a PS2 prompt, its indentation must -/// match the indentation used for the corresponding PS1 prompt (otherwise -/// `None` will be returned). -fn doctest_find_ps2_prompt<'src>(ps1_indent: &str, line: &'src str) -> Option<&'src str> { - let (ps2_indent, ps2_after) = line.split_once("...")?; - // PS2 prompts must have the same indentation as their - // corresponding PS1 prompt.[1] While the 'doctest' Python - // module will error in this case, we just treat this line as a - // non-doctest line. - // - // [1]: https://github.com/python/cpython/blob/0ff6368519ed7542ad8b443de01108690102420a/Lib/doctest.py#L733 - if ps1_indent != ps2_indent { - return None; - } - // PS2 prompts must be followed by an ASCII space character unless - // it's an otherwise empty line[1]. - // - // [1]: https://github.com/python/cpython/blob/0ff6368519ed7542ad8b443de01108690102420a/Lib/doctest.py#L809-L812 - match ps2_after.strip_prefix(' ') { - None if ps2_after.is_empty() => Some(""), - None => None, - Some(code) => Some(code), - } } /// Formats the given source code using the given options. diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap index 3a83075f29975..5eeafa914fb93 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap @@ -4,6 +4,15 @@ input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_ --- ## Input ```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + # The simplest doctest to ensure basic formatting works. def doctest_simple(): """ @@ -336,6 +345,15 @@ preview = Disabled ``` ```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + # The simplest doctest to ensure basic formatting works. def doctest_simple(): """ @@ -671,6 +689,15 @@ preview = Disabled ``` ```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + # The simplest doctest to ensure basic formatting works. def doctest_simple(): """ @@ -1006,6 +1033,15 @@ preview = Disabled ``` ```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + # The simplest doctest to ensure basic formatting works. def doctest_simple(): """ @@ -1341,6 +1377,15 @@ preview = Disabled ``` ```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + # The simplest doctest to ensure basic formatting works. def doctest_simple(): """ @@ -1676,6 +1721,15 @@ preview = Disabled ``` ```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + # The simplest doctest to ensure basic formatting works. def doctest_simple(): """ @@ -2011,6 +2065,15 @@ preview = Disabled ``` ```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + # The simplest doctest to ensure basic formatting works. def doctest_simple(): """ @@ -2346,6 +2409,15 @@ preview = Disabled ``` ```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + # The simplest doctest to ensure basic formatting works. def doctest_simple(): """ @@ -2681,6 +2753,15 @@ preview = Disabled ``` ```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + # The simplest doctest to ensure basic formatting works. def doctest_simple(): """ From 4af3f43e5ec63a1a246d3acb2f04ed5e5195fb6a Mon Sep 17 00:00:00 2001 From: Michael Essiet Date: Fri, 1 Dec 2023 21:43:01 +0100 Subject: [PATCH 086/197] Added the command to run ruff using pkgx to the installation.md (#8955) ## Summary This PR adds the command to run ruff using [pkgx](https://pkgx.sh). It's just showing that ruff is supported in one more package manager. ## Test Plan You can run `pkgx ruff` if you have pkgx installed or run `sh <(curl https://pkgx.sh) +github.com/charliermarsh/ruff sh ` --- docs/installation.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/installation.md b/docs/installation.md index a822bdf4b0230..e0a1e882e93f9 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -27,6 +27,13 @@ For **Conda** users, Ruff is also available as [`ruff`](https://anaconda.org/con conda install -c conda-forge ruff ``` +For **pkgx** users, Ruff is also available as [`ruff`](https://pkgx.dev/pkgs/github.com/charliermarsh/ruff/) +on the `pkgx` registry: + +```shell +pkgx install ruff +``` + For **Arch Linux** users, Ruff is also available as [`ruff`](https://archlinux.org/packages/extra/x86_64/ruff/) on the official repositories: From 20a40771a51658f1b7d90a8e8595be8e60c41c97 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 1 Dec 2023 17:58:32 -0500 Subject: [PATCH 087/197] Consider more wildcards in control flow graph matches (#8956) --- .../test/fixtures/control-flow-graph/match.py | 8 + ...ules__unreachable__tests__match.py.md.snap | 39 + ...__unreachable__tests__match.py.md.snap.new | 816 ++++++++++++++++++ .../src/rules/ruff/rules/unreachable.rs | 32 +- 4 files changed, 883 insertions(+), 12 deletions(-) create mode 100644 crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__match.py.md.snap.new diff --git a/crates/ruff_linter/resources/test/fixtures/control-flow-graph/match.py b/crates/ruff_linter/resources/test/fixtures/control-flow-graph/match.py index cce019e3085e9..d83726268991f 100644 --- a/crates/ruff_linter/resources/test/fixtures/control-flow-graph/match.py +++ b/crates/ruff_linter/resources/test/fixtures/control-flow-graph/match.py @@ -129,3 +129,11 @@ class Color(Enum): print("Grass is green") case Color.BLUE: print("I'm feeling the blues :(") + + +def func(point): + match point: + case (0, 0): + print("Origin") + case foo: + raise ValueError("oops") diff --git a/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__match.py.md.snap b/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__match.py.md.snap index 54cb336e95510..d74b08116f936 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__match.py.md.snap +++ b/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__match.py.md.snap @@ -773,4 +773,43 @@ flowchart TD block0 --> return ``` +## Function 14 +### Source +```python +def func(point): + match point: + case (0, 0): + print("Origin") + case foo: + raise ValueError("oops") +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0[["`*(empty)*`"]] + block1["raise ValueError(#quot;oops#quot;)\n"] + block2["match point: + case (0, 0): + print(#quot;Origin#quot;) + case foo: + raise ValueError(#quot;oops#quot;)\n"] + block3["print(#quot;Origin#quot;)\n"] + block4["match point: + case (0, 0): + print(#quot;Origin#quot;) + case foo: + raise ValueError(#quot;oops#quot;)\n"] + + start --> block4 + block4 -- "case (0, 0)" --> block3 + block4 -- "else" --> block2 + block3 --> block0 + block2 --> block1 + block1 --> return + block0 --> return +``` + diff --git a/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__match.py.md.snap.new b/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__match.py.md.snap.new new file mode 100644 index 0000000000000..2dfe0793d895d --- /dev/null +++ b/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__match.py.md.snap.new @@ -0,0 +1,816 @@ +--- +source: crates/ruff_linter/src/rules/ruff/rules/unreachable.rs +assertion_line: 1112 +description: "This is a Mermaid graph. You can use https://mermaid.live to visualize it as a diagram." +--- +## Function 0 +### Source +```python +def func(status): + match status: + case _: + return 0 + return "unreachable" +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0["return #quot;unreachable#quot;\n"] + block1["return 0\n"] + block2["match status: + case _: + return 0\n"] + + start --> block2 + block2 --> block1 + block1 --> return + block0 --> return +``` + +## Function 1 +### Source +```python +def func(status): + match status: + case 1: + return 1 + return 0 +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0["return 0\n"] + block1["return 1\n"] + block2["match status: + case 1: + return 1\n"] + + start --> block2 + block2 -- "case 1" --> block1 + block2 -- "else" --> block0 + block1 --> return + block0 --> return +``` + +## Function 2 +### Source +```python +def func(status): + match status: + case 1: + return 1 + case _: + return 0 +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0["return 0\n"] + block1["match status: + case 1: + return 1 + case _: + return 0\n"] + block2["return 1\n"] + block3["match status: + case 1: + return 1 + case _: + return 0\n"] + + start --> block3 + block3 -- "case 1" --> block2 + block3 -- "else" --> block1 + block2 --> return + block1 --> block0 + block0 --> return +``` + +## Function 3 +### Source +```python +def func(status): + match status: + case 1 | 2 | 3: + return 5 + return 6 +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0["return 6\n"] + block1["return 5\n"] + block2["match status: + case 1 | 2 | 3: + return 5\n"] + + start --> block2 + block2 -- "case 1 | 2 | 3" --> block1 + block2 -- "else" --> block0 + block1 --> return + block0 --> return +``` + +## Function 4 +### Source +```python +def func(status): + match status: + case 1 | 2 | 3: + return 5 + case _: + return 10 + return 0 +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0["return 0\n"] + block1["return 10\n"] + block2["match status: + case 1 | 2 | 3: + return 5 + case _: + return 10\n"] + block3["return 5\n"] + block4["match status: + case 1 | 2 | 3: + return 5 + case _: + return 10\n"] + + start --> block4 + block4 -- "case 1 | 2 | 3" --> block3 + block4 -- "else" --> block2 + block3 --> return + block2 --> block1 + block1 --> return + block0 --> return +``` + +## Function 5 +### Source +```python +def func(status): + match status: + case 0: + return 0 + case 1: + return 1 + case 1: + return "1 again" + case _: + return 3 +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0["return 3\n"] + block1["match status: + case 0: + return 0 + case 1: + return 1 + case 1: + return #quot;1 again#quot; + case _: + return 3\n"] + block2["return #quot;1 again#quot;\n"] + block3["match status: + case 0: + return 0 + case 1: + return 1 + case 1: + return #quot;1 again#quot; + case _: + return 3\n"] + block4["return 1\n"] + block5["match status: + case 0: + return 0 + case 1: + return 1 + case 1: + return #quot;1 again#quot; + case _: + return 3\n"] + block6["return 0\n"] + block7["match status: + case 0: + return 0 + case 1: + return 1 + case 1: + return #quot;1 again#quot; + case _: + return 3\n"] + + start --> block7 + block7 -- "case 0" --> block6 + block7 -- "else" --> block5 + block6 --> return + block5 -- "case 1" --> block4 + block5 -- "else" --> block3 + block4 --> return + block3 -- "case 1" --> block2 + block3 -- "else" --> block1 + block2 --> return + block1 --> block0 + block0 --> return +``` + +## Function 6 +### Source +```python +def func(status): + i = 0 + match status, i: + case _, _: + return 0 +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0[["`*(empty)*`"]] + block1["return 0\n"] + block2["match status, i: + case _, _: + return 0\n"] + block3["i = 0\n"] + + start --> block3 + block3 --> block2 + block2 -- "case _, _" --> block1 + block2 -- "else" --> block0 + block1 --> return + block0 --> return +``` + +## Function 7 +### Source +```python +def func(status): + i = 0 + match status, i: + case _, 0: + return 0 + case _, 2: + return 0 +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0[["`*(empty)*`"]] + block1["return 0\n"] + block2["match status, i: + case _, 0: + return 0 + case _, 2: + return 0\n"] + block3["return 0\n"] + block4["match status, i: + case _, 0: + return 0 + case _, 2: + return 0\n"] + block5["i = 0\n"] + + start --> block5 + block5 --> block4 + block4 -- "case _, 0" --> block3 + block4 -- "else" --> block2 + block3 --> return + block2 -- "case _, 2" --> block1 + block2 -- "else" --> block0 + block1 --> return + block0 --> return +``` + +## Function 8 +### Source +```python +def func(point): + match point: + case (0, 0): + print("Origin") + case _: + raise ValueError("oops") +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0[["`*(empty)*`"]] + block1["raise ValueError(#quot;oops#quot;)\n"] + block2["match point: + case (0, 0): + print(#quot;Origin#quot;) + case _: + raise ValueError(#quot;oops#quot;)\n"] + block3["print(#quot;Origin#quot;)\n"] + block4["match point: + case (0, 0): + print(#quot;Origin#quot;) + case _: + raise ValueError(#quot;oops#quot;)\n"] + + start --> block4 + block4 -- "case (0, 0)" --> block3 + block4 -- "else" --> block2 + block3 --> block0 + block2 --> block1 + block1 --> return + block0 --> return +``` + +## Function 9 +### Source +```python +def func(point): + match point: + case (0, 0): + print("Origin") + case (0, y): + print(f"Y={y}") + case (x, 0): + print(f"X={x}") + case (x, y): + print(f"X={x}, Y={y}") + case _: + raise ValueError("Not a point") +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0[["`*(empty)*`"]] + block1["raise ValueError(#quot;Not a point#quot;)\n"] + block2["match point: + case (0, 0): + print(#quot;Origin#quot;) + case (0, y): + print(f#quot;Y={y}#quot;) + case (x, 0): + print(f#quot;X={x}#quot;) + case (x, y): + print(f#quot;X={x}, Y={y}#quot;) + case _: + raise ValueError(#quot;Not a point#quot;)\n"] + block3["print(f#quot;X={x}, Y={y}#quot;)\n"] + block4["match point: + case (0, 0): + print(#quot;Origin#quot;) + case (0, y): + print(f#quot;Y={y}#quot;) + case (x, 0): + print(f#quot;X={x}#quot;) + case (x, y): + print(f#quot;X={x}, Y={y}#quot;) + case _: + raise ValueError(#quot;Not a point#quot;)\n"] + block5["print(f#quot;X={x}#quot;)\n"] + block6["match point: + case (0, 0): + print(#quot;Origin#quot;) + case (0, y): + print(f#quot;Y={y}#quot;) + case (x, 0): + print(f#quot;X={x}#quot;) + case (x, y): + print(f#quot;X={x}, Y={y}#quot;) + case _: + raise ValueError(#quot;Not a point#quot;)\n"] + block7["print(f#quot;Y={y}#quot;)\n"] + block8["match point: + case (0, 0): + print(#quot;Origin#quot;) + case (0, y): + print(f#quot;Y={y}#quot;) + case (x, 0): + print(f#quot;X={x}#quot;) + case (x, y): + print(f#quot;X={x}, Y={y}#quot;) + case _: + raise ValueError(#quot;Not a point#quot;)\n"] + block9["print(#quot;Origin#quot;)\n"] + block10["match point: + case (0, 0): + print(#quot;Origin#quot;) + case (0, y): + print(f#quot;Y={y}#quot;) + case (x, 0): + print(f#quot;X={x}#quot;) + case (x, y): + print(f#quot;X={x}, Y={y}#quot;) + case _: + raise ValueError(#quot;Not a point#quot;)\n"] + + start --> block10 + block10 -- "case (0, 0)" --> block9 + block10 -- "else" --> block8 + block9 --> block0 + block8 -- "case (0, y)" --> block7 + block8 -- "else" --> block6 + block7 --> block0 + block6 -- "case (x, 0)" --> block5 + block6 -- "else" --> block4 + block5 --> block0 + block4 -- "case (x, y)" --> block3 + block4 -- "else" --> block2 + block3 --> block0 + block2 --> block1 + block1 --> return + block0 --> return +``` + +## Function 10 +### Source +```python +def where_is(point): + class Point: + x: int + y: int + + match point: + case Point(x=0, y=0): + print("Origin") + case Point(x=0, y=y): + print(f"Y={y}") + case Point(x=x, y=0): + print(f"X={x}") + case Point(): + print("Somewhere else") + case _: + print("Not a point") +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0[["`*(empty)*`"]] + block1["print(#quot;Not a point#quot;)\n"] + block2["match point: + case Point(x=0, y=0): + print(#quot;Origin#quot;) + case Point(x=0, y=y): + print(f#quot;Y={y}#quot;) + case Point(x=x, y=0): + print(f#quot;X={x}#quot;) + case Point(): + print(#quot;Somewhere else#quot;) + case _: + print(#quot;Not a point#quot;)\n"] + block3["print(#quot;Somewhere else#quot;)\n"] + block4["match point: + case Point(x=0, y=0): + print(#quot;Origin#quot;) + case Point(x=0, y=y): + print(f#quot;Y={y}#quot;) + case Point(x=x, y=0): + print(f#quot;X={x}#quot;) + case Point(): + print(#quot;Somewhere else#quot;) + case _: + print(#quot;Not a point#quot;)\n"] + block5["print(f#quot;X={x}#quot;)\n"] + block6["match point: + case Point(x=0, y=0): + print(#quot;Origin#quot;) + case Point(x=0, y=y): + print(f#quot;Y={y}#quot;) + case Point(x=x, y=0): + print(f#quot;X={x}#quot;) + case Point(): + print(#quot;Somewhere else#quot;) + case _: + print(#quot;Not a point#quot;)\n"] + block7["print(f#quot;Y={y}#quot;)\n"] + block8["match point: + case Point(x=0, y=0): + print(#quot;Origin#quot;) + case Point(x=0, y=y): + print(f#quot;Y={y}#quot;) + case Point(x=x, y=0): + print(f#quot;X={x}#quot;) + case Point(): + print(#quot;Somewhere else#quot;) + case _: + print(#quot;Not a point#quot;)\n"] + block9["print(#quot;Origin#quot;)\n"] + block10["match point: + case Point(x=0, y=0): + print(#quot;Origin#quot;) + case Point(x=0, y=y): + print(f#quot;Y={y}#quot;) + case Point(x=x, y=0): + print(f#quot;X={x}#quot;) + case Point(): + print(#quot;Somewhere else#quot;) + case _: + print(#quot;Not a point#quot;)\n"] + block11["class Point: + x: int + y: int\n"] + + start --> block11 + block11 --> block10 + block10 -- "case Point(x=0, y=0)" --> block9 + block10 -- "else" --> block8 + block9 --> block0 + block8 -- "case Point(x=0, y=y)" --> block7 + block8 -- "else" --> block6 + block7 --> block0 + block6 -- "case Point(x=x, y=0)" --> block5 + block6 -- "else" --> block4 + block5 --> block0 + block4 -- "case Point()" --> block3 + block4 -- "else" --> block2 + block3 --> block0 + block2 --> block1 + block1 --> block0 + block0 --> return +``` + +## Function 11 +### Source +```python +def func(points): + match points: + case []: + print("No points") + case [Point(0, 0)]: + print("The origin") + case [Point(x, y)]: + print(f"Single point {x}, {y}") + case [Point(0, y1), Point(0, y2)]: + print(f"Two on the Y axis at {y1}, {y2}") + case _: + print("Something else") +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0[["`*(empty)*`"]] + block1["print(#quot;Something else#quot;)\n"] + block2["match points: + case []: + print(#quot;No points#quot;) + case [Point(0, 0)]: + print(#quot;The origin#quot;) + case [Point(x, y)]: + print(f#quot;Single point {x}, {y}#quot;) + case [Point(0, y1), Point(0, y2)]: + print(f#quot;Two on the Y axis at {y1}, {y2}#quot;) + case _: + print(#quot;Something else#quot;)\n"] + block3["print(f#quot;Two on the Y axis at {y1}, {y2}#quot;)\n"] + block4["match points: + case []: + print(#quot;No points#quot;) + case [Point(0, 0)]: + print(#quot;The origin#quot;) + case [Point(x, y)]: + print(f#quot;Single point {x}, {y}#quot;) + case [Point(0, y1), Point(0, y2)]: + print(f#quot;Two on the Y axis at {y1}, {y2}#quot;) + case _: + print(#quot;Something else#quot;)\n"] + block5["print(f#quot;Single point {x}, {y}#quot;)\n"] + block6["match points: + case []: + print(#quot;No points#quot;) + case [Point(0, 0)]: + print(#quot;The origin#quot;) + case [Point(x, y)]: + print(f#quot;Single point {x}, {y}#quot;) + case [Point(0, y1), Point(0, y2)]: + print(f#quot;Two on the Y axis at {y1}, {y2}#quot;) + case _: + print(#quot;Something else#quot;)\n"] + block7["print(#quot;The origin#quot;)\n"] + block8["match points: + case []: + print(#quot;No points#quot;) + case [Point(0, 0)]: + print(#quot;The origin#quot;) + case [Point(x, y)]: + print(f#quot;Single point {x}, {y}#quot;) + case [Point(0, y1), Point(0, y2)]: + print(f#quot;Two on the Y axis at {y1}, {y2}#quot;) + case _: + print(#quot;Something else#quot;)\n"] + block9["print(#quot;No points#quot;)\n"] + block10["match points: + case []: + print(#quot;No points#quot;) + case [Point(0, 0)]: + print(#quot;The origin#quot;) + case [Point(x, y)]: + print(f#quot;Single point {x}, {y}#quot;) + case [Point(0, y1), Point(0, y2)]: + print(f#quot;Two on the Y axis at {y1}, {y2}#quot;) + case _: + print(#quot;Something else#quot;)\n"] + + start --> block10 + block10 -- "case []" --> block9 + block10 -- "else" --> block8 + block9 --> block0 + block8 -- "case [Point(0, 0)]" --> block7 + block8 -- "else" --> block6 + block7 --> block0 + block6 -- "case [Point(x, y)]" --> block5 + block6 -- "else" --> block4 + block5 --> block0 + block4 -- "case [Point(0, y1), Point(0, y2)]" --> block3 + block4 -- "else" --> block2 + block3 --> block0 + block2 --> block1 + block1 --> block0 + block0 --> return +``` + +## Function 12 +### Source +```python +def func(point): + match point: + case Point(x, y) if x == y: + print(f"Y=X at {x}") + case Point(x, y): + print(f"Not on the diagonal") +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0[["`*(empty)*`"]] + block1["print(f#quot;Not on the diagonal#quot;)\n"] + block2["match point: + case Point(x, y) if x == y: + print(f#quot;Y=X at {x}#quot;) + case Point(x, y): + print(f#quot;Not on the diagonal#quot;)\n"] + block3["print(f#quot;Y=X at {x}#quot;)\n"] + block4["match point: + case Point(x, y) if x == y: + print(f#quot;Y=X at {x}#quot;) + case Point(x, y): + print(f#quot;Not on the diagonal#quot;)\n"] + + start --> block4 + block4 -- "case Point(x, y) if x == y" --> block3 + block4 -- "else" --> block2 + block3 --> block0 + block2 -- "case Point(x, y)" --> block1 + block2 -- "else" --> block0 + block1 --> block0 + block0 --> return +``` + +## Function 13 +### Source +```python +def func(): + from enum import Enum + class Color(Enum): + RED = 'red' + GREEN = 'green' + BLUE = 'blue' + + color = Color(input("Enter your choice of 'red', 'blue' or 'green': ")) + + match color: + case Color.RED: + print("I see red!") + case Color.GREEN: + print("Grass is green") + case Color.BLUE: + print("I'm feeling the blues :(") +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0[["`*(empty)*`"]] + block1["print(#quot;I'm feeling the blues :(#quot;)\n"] + block2["match color: + case Color.RED: + print(#quot;I see red!#quot;) + case Color.GREEN: + print(#quot;Grass is green#quot;) + case Color.BLUE: + print(#quot;I'm feeling the blues :(#quot;)\n"] + block3["print(#quot;Grass is green#quot;)\n"] + block4["match color: + case Color.RED: + print(#quot;I see red!#quot;) + case Color.GREEN: + print(#quot;Grass is green#quot;) + case Color.BLUE: + print(#quot;I'm feeling the blues :(#quot;)\n"] + block5["print(#quot;I see red!#quot;)\n"] + block6["match color: + case Color.RED: + print(#quot;I see red!#quot;) + case Color.GREEN: + print(#quot;Grass is green#quot;) + case Color.BLUE: + print(#quot;I'm feeling the blues :(#quot;)\n"] + block7["from enum import Enum\nclass Color(Enum): + RED = 'red' + GREEN = 'green' + BLUE = 'blue'\ncolor = Color(input(#quot;Enter your choice of 'red', 'blue' or 'green': #quot;))\n"] + + start --> block7 + block7 --> block6 + block6 -- "case Color.RED" --> block5 + block6 -- "else" --> block4 + block5 --> block0 + block4 -- "case Color.GREEN" --> block3 + block4 -- "else" --> block2 + block3 --> block0 + block2 -- "case Color.BLUE" --> block1 + block2 -- "else" --> block0 + block1 --> block0 + block0 --> return +``` + +## Function 14 +### Source +```python +def func(point): + match point: + case (0, 0): + print("Origin") + case _: + raise ValueError("oops") +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0[["`*(empty)*`"]] + block1["raise ValueError(#quot;oops#quot;)\n"] + block2["match point: + case (0, 0): + print(#quot;Origin#quot;) + case _: + raise ValueError(#quot;oops#quot;)\n"] + block3["print(#quot;Origin#quot;)\n"] + block4["match point: + case (0, 0): + print(#quot;Origin#quot;) + case _: + raise ValueError(#quot;oops#quot;)\n"] + + start --> block4 + block4 -- "case (0, 0)" --> block3 + block4 -- "else" --> block2 + block3 --> block0 + block2 --> block1 + block1 --> return + block0 --> return +``` + + diff --git a/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs b/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs index 8f5db5a35bc32..51a75f817e0e7 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs @@ -2,8 +2,8 @@ use std::{fmt, iter, usize}; use log::error; use ruff_python_ast::{ - Expr, ExprBooleanLiteral, Identifier, MatchCase, Pattern, PatternMatchAs, Stmt, StmtFor, - StmtMatch, StmtReturn, StmtTry, StmtWhile, StmtWith, + Expr, ExprBooleanLiteral, Identifier, MatchCase, Pattern, PatternMatchAs, PatternMatchOr, Stmt, + StmtFor, StmtMatch, StmtReturn, StmtTry, StmtWhile, StmtWith, }; use ruff_text_size::{Ranged, TextRange, TextSize}; @@ -416,13 +416,6 @@ fn match_case<'stmt>( } last_statement_index }; - // TODO: handle named arguments, e.g. - // ```python - // match $subject: - // case $binding: - // print($binding) - // ``` - // These should also return `NextBlock::Always`. let next = if is_wildcard(case) { // Wildcard case is always taken. NextBlock::Always(next_block_index) @@ -436,10 +429,25 @@ fn match_case<'stmt>( BasicBlock { stmts, next } } -/// Returns true if `pattern` is a wildcard (`_`) pattern. +/// Returns true if the [`MatchCase`] is a wildcard pattern. fn is_wildcard(pattern: &MatchCase) -> bool { - pattern.guard.is_none() - && matches!(&pattern.pattern, Pattern::MatchAs(PatternMatchAs { pattern, name, .. }) if pattern.is_none() && name.is_none()) + /// Returns true if the [`Pattern`] is a wildcard pattern. + fn is_wildcard_pattern(pattern: &Pattern) -> bool { + match pattern { + Pattern::MatchValue(_) + | Pattern::MatchSingleton(_) + | Pattern::MatchSequence(_) + | Pattern::MatchMapping(_) + | Pattern::MatchClass(_) + | Pattern::MatchStar(_) => false, + Pattern::MatchAs(PatternMatchAs { pattern, .. }) => pattern.is_none(), + Pattern::MatchOr(PatternMatchOr { patterns, .. }) => { + patterns.iter().all(is_wildcard_pattern) + } + } + } + + pattern.guard.is_none() && is_wildcard_pattern(&pattern.pattern) } #[derive(Debug, Default)] From 277cd80175ae52c5d78331fa8dc3ed632999606a Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 1 Dec 2023 18:11:42 -0500 Subject: [PATCH 088/197] Add erroneous for-loop test case for CFG (#8957) --- .../test/fixtures/control-flow-graph/for.py | 15 + ..._rules__unreachable__tests__for.py.md.snap | 61 ++ ...__unreachable__tests__match.py.md.snap.new | 816 ------------------ 3 files changed, 76 insertions(+), 816 deletions(-) delete mode 100644 crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__match.py.md.snap.new diff --git a/crates/ruff_linter/resources/test/fixtures/control-flow-graph/for.py b/crates/ruff_linter/resources/test/fixtures/control-flow-graph/for.py index a5807a635a412..9aef74d5d027f 100644 --- a/crates/ruff_linter/resources/test/fixtures/control-flow-graph/for.py +++ b/crates/ruff_linter/resources/test/fixtures/control-flow-graph/for.py @@ -39,3 +39,18 @@ def func(): for i in range(1110): if True: break + +# TODO(charlie): The `pass` here does not get properly redirected to the top of the +# loop, unlike below. +def func(): + for i in range(5): + pass + else: + return 1 + +def func(): + for i in range(5): + pass + else: + return 1 + x = 1 diff --git a/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__for.py.md.snap b/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__for.py.md.snap index e93710e8eda53..6850c5f69b04b 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__for.py.md.snap +++ b/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__for.py.md.snap @@ -238,4 +238,65 @@ flowchart TD block0 --> return ``` +## Function 8 +### Source +```python +def func(): + for i in range(5): + pass + else: + return 1 +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0["pass\n"] + block1["return 1\n"] + block2["for i in range(5): + pass + else: + return 1\n"] + + start --> block2 + block2 -- "range(5)" --> block0 + block2 -- "else" --> block1 + block1 --> return + block0 --> return +``` + +## Function 9 +### Source +```python +def func(): + for i in range(5): + pass + else: + return 1 + x = 1 +``` + +### Control Flow Graph +```mermaid +flowchart TD + start(("Start")) + return(("End")) + block0["x = 1\n"] + block1["pass\n"] + block2["return 1\n"] + block3["for i in range(5): + pass + else: + return 1\n"] + + start --> block3 + block3 -- "range(5)" --> block1 + block3 -- "else" --> block2 + block2 --> return + block1 --> block3 + block0 --> return +``` + diff --git a/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__match.py.md.snap.new b/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__match.py.md.snap.new deleted file mode 100644 index 2dfe0793d895d..0000000000000 --- a/crates/ruff_linter/src/rules/ruff/rules/snapshots/ruff_linter__rules__ruff__rules__unreachable__tests__match.py.md.snap.new +++ /dev/null @@ -1,816 +0,0 @@ ---- -source: crates/ruff_linter/src/rules/ruff/rules/unreachable.rs -assertion_line: 1112 -description: "This is a Mermaid graph. You can use https://mermaid.live to visualize it as a diagram." ---- -## Function 0 -### Source -```python -def func(status): - match status: - case _: - return 0 - return "unreachable" -``` - -### Control Flow Graph -```mermaid -flowchart TD - start(("Start")) - return(("End")) - block0["return #quot;unreachable#quot;\n"] - block1["return 0\n"] - block2["match status: - case _: - return 0\n"] - - start --> block2 - block2 --> block1 - block1 --> return - block0 --> return -``` - -## Function 1 -### Source -```python -def func(status): - match status: - case 1: - return 1 - return 0 -``` - -### Control Flow Graph -```mermaid -flowchart TD - start(("Start")) - return(("End")) - block0["return 0\n"] - block1["return 1\n"] - block2["match status: - case 1: - return 1\n"] - - start --> block2 - block2 -- "case 1" --> block1 - block2 -- "else" --> block0 - block1 --> return - block0 --> return -``` - -## Function 2 -### Source -```python -def func(status): - match status: - case 1: - return 1 - case _: - return 0 -``` - -### Control Flow Graph -```mermaid -flowchart TD - start(("Start")) - return(("End")) - block0["return 0\n"] - block1["match status: - case 1: - return 1 - case _: - return 0\n"] - block2["return 1\n"] - block3["match status: - case 1: - return 1 - case _: - return 0\n"] - - start --> block3 - block3 -- "case 1" --> block2 - block3 -- "else" --> block1 - block2 --> return - block1 --> block0 - block0 --> return -``` - -## Function 3 -### Source -```python -def func(status): - match status: - case 1 | 2 | 3: - return 5 - return 6 -``` - -### Control Flow Graph -```mermaid -flowchart TD - start(("Start")) - return(("End")) - block0["return 6\n"] - block1["return 5\n"] - block2["match status: - case 1 | 2 | 3: - return 5\n"] - - start --> block2 - block2 -- "case 1 | 2 | 3" --> block1 - block2 -- "else" --> block0 - block1 --> return - block0 --> return -``` - -## Function 4 -### Source -```python -def func(status): - match status: - case 1 | 2 | 3: - return 5 - case _: - return 10 - return 0 -``` - -### Control Flow Graph -```mermaid -flowchart TD - start(("Start")) - return(("End")) - block0["return 0\n"] - block1["return 10\n"] - block2["match status: - case 1 | 2 | 3: - return 5 - case _: - return 10\n"] - block3["return 5\n"] - block4["match status: - case 1 | 2 | 3: - return 5 - case _: - return 10\n"] - - start --> block4 - block4 -- "case 1 | 2 | 3" --> block3 - block4 -- "else" --> block2 - block3 --> return - block2 --> block1 - block1 --> return - block0 --> return -``` - -## Function 5 -### Source -```python -def func(status): - match status: - case 0: - return 0 - case 1: - return 1 - case 1: - return "1 again" - case _: - return 3 -``` - -### Control Flow Graph -```mermaid -flowchart TD - start(("Start")) - return(("End")) - block0["return 3\n"] - block1["match status: - case 0: - return 0 - case 1: - return 1 - case 1: - return #quot;1 again#quot; - case _: - return 3\n"] - block2["return #quot;1 again#quot;\n"] - block3["match status: - case 0: - return 0 - case 1: - return 1 - case 1: - return #quot;1 again#quot; - case _: - return 3\n"] - block4["return 1\n"] - block5["match status: - case 0: - return 0 - case 1: - return 1 - case 1: - return #quot;1 again#quot; - case _: - return 3\n"] - block6["return 0\n"] - block7["match status: - case 0: - return 0 - case 1: - return 1 - case 1: - return #quot;1 again#quot; - case _: - return 3\n"] - - start --> block7 - block7 -- "case 0" --> block6 - block7 -- "else" --> block5 - block6 --> return - block5 -- "case 1" --> block4 - block5 -- "else" --> block3 - block4 --> return - block3 -- "case 1" --> block2 - block3 -- "else" --> block1 - block2 --> return - block1 --> block0 - block0 --> return -``` - -## Function 6 -### Source -```python -def func(status): - i = 0 - match status, i: - case _, _: - return 0 -``` - -### Control Flow Graph -```mermaid -flowchart TD - start(("Start")) - return(("End")) - block0[["`*(empty)*`"]] - block1["return 0\n"] - block2["match status, i: - case _, _: - return 0\n"] - block3["i = 0\n"] - - start --> block3 - block3 --> block2 - block2 -- "case _, _" --> block1 - block2 -- "else" --> block0 - block1 --> return - block0 --> return -``` - -## Function 7 -### Source -```python -def func(status): - i = 0 - match status, i: - case _, 0: - return 0 - case _, 2: - return 0 -``` - -### Control Flow Graph -```mermaid -flowchart TD - start(("Start")) - return(("End")) - block0[["`*(empty)*`"]] - block1["return 0\n"] - block2["match status, i: - case _, 0: - return 0 - case _, 2: - return 0\n"] - block3["return 0\n"] - block4["match status, i: - case _, 0: - return 0 - case _, 2: - return 0\n"] - block5["i = 0\n"] - - start --> block5 - block5 --> block4 - block4 -- "case _, 0" --> block3 - block4 -- "else" --> block2 - block3 --> return - block2 -- "case _, 2" --> block1 - block2 -- "else" --> block0 - block1 --> return - block0 --> return -``` - -## Function 8 -### Source -```python -def func(point): - match point: - case (0, 0): - print("Origin") - case _: - raise ValueError("oops") -``` - -### Control Flow Graph -```mermaid -flowchart TD - start(("Start")) - return(("End")) - block0[["`*(empty)*`"]] - block1["raise ValueError(#quot;oops#quot;)\n"] - block2["match point: - case (0, 0): - print(#quot;Origin#quot;) - case _: - raise ValueError(#quot;oops#quot;)\n"] - block3["print(#quot;Origin#quot;)\n"] - block4["match point: - case (0, 0): - print(#quot;Origin#quot;) - case _: - raise ValueError(#quot;oops#quot;)\n"] - - start --> block4 - block4 -- "case (0, 0)" --> block3 - block4 -- "else" --> block2 - block3 --> block0 - block2 --> block1 - block1 --> return - block0 --> return -``` - -## Function 9 -### Source -```python -def func(point): - match point: - case (0, 0): - print("Origin") - case (0, y): - print(f"Y={y}") - case (x, 0): - print(f"X={x}") - case (x, y): - print(f"X={x}, Y={y}") - case _: - raise ValueError("Not a point") -``` - -### Control Flow Graph -```mermaid -flowchart TD - start(("Start")) - return(("End")) - block0[["`*(empty)*`"]] - block1["raise ValueError(#quot;Not a point#quot;)\n"] - block2["match point: - case (0, 0): - print(#quot;Origin#quot;) - case (0, y): - print(f#quot;Y={y}#quot;) - case (x, 0): - print(f#quot;X={x}#quot;) - case (x, y): - print(f#quot;X={x}, Y={y}#quot;) - case _: - raise ValueError(#quot;Not a point#quot;)\n"] - block3["print(f#quot;X={x}, Y={y}#quot;)\n"] - block4["match point: - case (0, 0): - print(#quot;Origin#quot;) - case (0, y): - print(f#quot;Y={y}#quot;) - case (x, 0): - print(f#quot;X={x}#quot;) - case (x, y): - print(f#quot;X={x}, Y={y}#quot;) - case _: - raise ValueError(#quot;Not a point#quot;)\n"] - block5["print(f#quot;X={x}#quot;)\n"] - block6["match point: - case (0, 0): - print(#quot;Origin#quot;) - case (0, y): - print(f#quot;Y={y}#quot;) - case (x, 0): - print(f#quot;X={x}#quot;) - case (x, y): - print(f#quot;X={x}, Y={y}#quot;) - case _: - raise ValueError(#quot;Not a point#quot;)\n"] - block7["print(f#quot;Y={y}#quot;)\n"] - block8["match point: - case (0, 0): - print(#quot;Origin#quot;) - case (0, y): - print(f#quot;Y={y}#quot;) - case (x, 0): - print(f#quot;X={x}#quot;) - case (x, y): - print(f#quot;X={x}, Y={y}#quot;) - case _: - raise ValueError(#quot;Not a point#quot;)\n"] - block9["print(#quot;Origin#quot;)\n"] - block10["match point: - case (0, 0): - print(#quot;Origin#quot;) - case (0, y): - print(f#quot;Y={y}#quot;) - case (x, 0): - print(f#quot;X={x}#quot;) - case (x, y): - print(f#quot;X={x}, Y={y}#quot;) - case _: - raise ValueError(#quot;Not a point#quot;)\n"] - - start --> block10 - block10 -- "case (0, 0)" --> block9 - block10 -- "else" --> block8 - block9 --> block0 - block8 -- "case (0, y)" --> block7 - block8 -- "else" --> block6 - block7 --> block0 - block6 -- "case (x, 0)" --> block5 - block6 -- "else" --> block4 - block5 --> block0 - block4 -- "case (x, y)" --> block3 - block4 -- "else" --> block2 - block3 --> block0 - block2 --> block1 - block1 --> return - block0 --> return -``` - -## Function 10 -### Source -```python -def where_is(point): - class Point: - x: int - y: int - - match point: - case Point(x=0, y=0): - print("Origin") - case Point(x=0, y=y): - print(f"Y={y}") - case Point(x=x, y=0): - print(f"X={x}") - case Point(): - print("Somewhere else") - case _: - print("Not a point") -``` - -### Control Flow Graph -```mermaid -flowchart TD - start(("Start")) - return(("End")) - block0[["`*(empty)*`"]] - block1["print(#quot;Not a point#quot;)\n"] - block2["match point: - case Point(x=0, y=0): - print(#quot;Origin#quot;) - case Point(x=0, y=y): - print(f#quot;Y={y}#quot;) - case Point(x=x, y=0): - print(f#quot;X={x}#quot;) - case Point(): - print(#quot;Somewhere else#quot;) - case _: - print(#quot;Not a point#quot;)\n"] - block3["print(#quot;Somewhere else#quot;)\n"] - block4["match point: - case Point(x=0, y=0): - print(#quot;Origin#quot;) - case Point(x=0, y=y): - print(f#quot;Y={y}#quot;) - case Point(x=x, y=0): - print(f#quot;X={x}#quot;) - case Point(): - print(#quot;Somewhere else#quot;) - case _: - print(#quot;Not a point#quot;)\n"] - block5["print(f#quot;X={x}#quot;)\n"] - block6["match point: - case Point(x=0, y=0): - print(#quot;Origin#quot;) - case Point(x=0, y=y): - print(f#quot;Y={y}#quot;) - case Point(x=x, y=0): - print(f#quot;X={x}#quot;) - case Point(): - print(#quot;Somewhere else#quot;) - case _: - print(#quot;Not a point#quot;)\n"] - block7["print(f#quot;Y={y}#quot;)\n"] - block8["match point: - case Point(x=0, y=0): - print(#quot;Origin#quot;) - case Point(x=0, y=y): - print(f#quot;Y={y}#quot;) - case Point(x=x, y=0): - print(f#quot;X={x}#quot;) - case Point(): - print(#quot;Somewhere else#quot;) - case _: - print(#quot;Not a point#quot;)\n"] - block9["print(#quot;Origin#quot;)\n"] - block10["match point: - case Point(x=0, y=0): - print(#quot;Origin#quot;) - case Point(x=0, y=y): - print(f#quot;Y={y}#quot;) - case Point(x=x, y=0): - print(f#quot;X={x}#quot;) - case Point(): - print(#quot;Somewhere else#quot;) - case _: - print(#quot;Not a point#quot;)\n"] - block11["class Point: - x: int - y: int\n"] - - start --> block11 - block11 --> block10 - block10 -- "case Point(x=0, y=0)" --> block9 - block10 -- "else" --> block8 - block9 --> block0 - block8 -- "case Point(x=0, y=y)" --> block7 - block8 -- "else" --> block6 - block7 --> block0 - block6 -- "case Point(x=x, y=0)" --> block5 - block6 -- "else" --> block4 - block5 --> block0 - block4 -- "case Point()" --> block3 - block4 -- "else" --> block2 - block3 --> block0 - block2 --> block1 - block1 --> block0 - block0 --> return -``` - -## Function 11 -### Source -```python -def func(points): - match points: - case []: - print("No points") - case [Point(0, 0)]: - print("The origin") - case [Point(x, y)]: - print(f"Single point {x}, {y}") - case [Point(0, y1), Point(0, y2)]: - print(f"Two on the Y axis at {y1}, {y2}") - case _: - print("Something else") -``` - -### Control Flow Graph -```mermaid -flowchart TD - start(("Start")) - return(("End")) - block0[["`*(empty)*`"]] - block1["print(#quot;Something else#quot;)\n"] - block2["match points: - case []: - print(#quot;No points#quot;) - case [Point(0, 0)]: - print(#quot;The origin#quot;) - case [Point(x, y)]: - print(f#quot;Single point {x}, {y}#quot;) - case [Point(0, y1), Point(0, y2)]: - print(f#quot;Two on the Y axis at {y1}, {y2}#quot;) - case _: - print(#quot;Something else#quot;)\n"] - block3["print(f#quot;Two on the Y axis at {y1}, {y2}#quot;)\n"] - block4["match points: - case []: - print(#quot;No points#quot;) - case [Point(0, 0)]: - print(#quot;The origin#quot;) - case [Point(x, y)]: - print(f#quot;Single point {x}, {y}#quot;) - case [Point(0, y1), Point(0, y2)]: - print(f#quot;Two on the Y axis at {y1}, {y2}#quot;) - case _: - print(#quot;Something else#quot;)\n"] - block5["print(f#quot;Single point {x}, {y}#quot;)\n"] - block6["match points: - case []: - print(#quot;No points#quot;) - case [Point(0, 0)]: - print(#quot;The origin#quot;) - case [Point(x, y)]: - print(f#quot;Single point {x}, {y}#quot;) - case [Point(0, y1), Point(0, y2)]: - print(f#quot;Two on the Y axis at {y1}, {y2}#quot;) - case _: - print(#quot;Something else#quot;)\n"] - block7["print(#quot;The origin#quot;)\n"] - block8["match points: - case []: - print(#quot;No points#quot;) - case [Point(0, 0)]: - print(#quot;The origin#quot;) - case [Point(x, y)]: - print(f#quot;Single point {x}, {y}#quot;) - case [Point(0, y1), Point(0, y2)]: - print(f#quot;Two on the Y axis at {y1}, {y2}#quot;) - case _: - print(#quot;Something else#quot;)\n"] - block9["print(#quot;No points#quot;)\n"] - block10["match points: - case []: - print(#quot;No points#quot;) - case [Point(0, 0)]: - print(#quot;The origin#quot;) - case [Point(x, y)]: - print(f#quot;Single point {x}, {y}#quot;) - case [Point(0, y1), Point(0, y2)]: - print(f#quot;Two on the Y axis at {y1}, {y2}#quot;) - case _: - print(#quot;Something else#quot;)\n"] - - start --> block10 - block10 -- "case []" --> block9 - block10 -- "else" --> block8 - block9 --> block0 - block8 -- "case [Point(0, 0)]" --> block7 - block8 -- "else" --> block6 - block7 --> block0 - block6 -- "case [Point(x, y)]" --> block5 - block6 -- "else" --> block4 - block5 --> block0 - block4 -- "case [Point(0, y1), Point(0, y2)]" --> block3 - block4 -- "else" --> block2 - block3 --> block0 - block2 --> block1 - block1 --> block0 - block0 --> return -``` - -## Function 12 -### Source -```python -def func(point): - match point: - case Point(x, y) if x == y: - print(f"Y=X at {x}") - case Point(x, y): - print(f"Not on the diagonal") -``` - -### Control Flow Graph -```mermaid -flowchart TD - start(("Start")) - return(("End")) - block0[["`*(empty)*`"]] - block1["print(f#quot;Not on the diagonal#quot;)\n"] - block2["match point: - case Point(x, y) if x == y: - print(f#quot;Y=X at {x}#quot;) - case Point(x, y): - print(f#quot;Not on the diagonal#quot;)\n"] - block3["print(f#quot;Y=X at {x}#quot;)\n"] - block4["match point: - case Point(x, y) if x == y: - print(f#quot;Y=X at {x}#quot;) - case Point(x, y): - print(f#quot;Not on the diagonal#quot;)\n"] - - start --> block4 - block4 -- "case Point(x, y) if x == y" --> block3 - block4 -- "else" --> block2 - block3 --> block0 - block2 -- "case Point(x, y)" --> block1 - block2 -- "else" --> block0 - block1 --> block0 - block0 --> return -``` - -## Function 13 -### Source -```python -def func(): - from enum import Enum - class Color(Enum): - RED = 'red' - GREEN = 'green' - BLUE = 'blue' - - color = Color(input("Enter your choice of 'red', 'blue' or 'green': ")) - - match color: - case Color.RED: - print("I see red!") - case Color.GREEN: - print("Grass is green") - case Color.BLUE: - print("I'm feeling the blues :(") -``` - -### Control Flow Graph -```mermaid -flowchart TD - start(("Start")) - return(("End")) - block0[["`*(empty)*`"]] - block1["print(#quot;I'm feeling the blues :(#quot;)\n"] - block2["match color: - case Color.RED: - print(#quot;I see red!#quot;) - case Color.GREEN: - print(#quot;Grass is green#quot;) - case Color.BLUE: - print(#quot;I'm feeling the blues :(#quot;)\n"] - block3["print(#quot;Grass is green#quot;)\n"] - block4["match color: - case Color.RED: - print(#quot;I see red!#quot;) - case Color.GREEN: - print(#quot;Grass is green#quot;) - case Color.BLUE: - print(#quot;I'm feeling the blues :(#quot;)\n"] - block5["print(#quot;I see red!#quot;)\n"] - block6["match color: - case Color.RED: - print(#quot;I see red!#quot;) - case Color.GREEN: - print(#quot;Grass is green#quot;) - case Color.BLUE: - print(#quot;I'm feeling the blues :(#quot;)\n"] - block7["from enum import Enum\nclass Color(Enum): - RED = 'red' - GREEN = 'green' - BLUE = 'blue'\ncolor = Color(input(#quot;Enter your choice of 'red', 'blue' or 'green': #quot;))\n"] - - start --> block7 - block7 --> block6 - block6 -- "case Color.RED" --> block5 - block6 -- "else" --> block4 - block5 --> block0 - block4 -- "case Color.GREEN" --> block3 - block4 -- "else" --> block2 - block3 --> block0 - block2 -- "case Color.BLUE" --> block1 - block2 -- "else" --> block0 - block1 --> block0 - block0 --> return -``` - -## Function 14 -### Source -```python -def func(point): - match point: - case (0, 0): - print("Origin") - case _: - raise ValueError("oops") -``` - -### Control Flow Graph -```mermaid -flowchart TD - start(("Start")) - return(("End")) - block0[["`*(empty)*`"]] - block1["raise ValueError(#quot;oops#quot;)\n"] - block2["match point: - case (0, 0): - print(#quot;Origin#quot;) - case _: - raise ValueError(#quot;oops#quot;)\n"] - block3["print(#quot;Origin#quot;)\n"] - block4["match point: - case (0, 0): - print(#quot;Origin#quot;) - case _: - raise ValueError(#quot;oops#quot;)\n"] - - start --> block4 - block4 -- "case (0, 0)" --> block3 - block4 -- "else" --> block2 - block3 --> block0 - block2 --> block1 - block1 --> return - block0 --> return -``` - - From 58bf6f57626afe5f9d5b8635ae831f346913b5f2 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 1 Dec 2023 18:46:50 -0500 Subject: [PATCH 089/197] Remove todo branches from control-flow graph (#8960) --- .../src/rules/ruff/rules/unreachable.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs b/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs index 51a75f817e0e7..e94cb4179d3e9 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs @@ -485,6 +485,8 @@ impl<'stmt> BasicBlocksBuilder<'stmt> { | Stmt::AugAssign(_) | Stmt::AnnAssign(_) | Stmt::Break(_) + | Stmt::TypeAlias(_) + | Stmt::IpyEscapeCommand(_) | Stmt::Pass(_) => self.unconditional_next_block(after), Stmt::Continue(_) => { // NOTE: the next branch gets fixed up in `change_next_block`. @@ -646,6 +648,7 @@ impl<'stmt> BasicBlocksBuilder<'stmt> { | Expr::Starred(_) | Expr::Name(_) | Expr::List(_) + | Expr::IpyEscapeCommand(_) | Expr::Tuple(_) | Expr::Slice(_) => self.unconditional_next_block(after), // TODO: handle these expressions. @@ -659,13 +662,10 @@ impl<'stmt> BasicBlocksBuilder<'stmt> { | Expr::Await(_) | Expr::Yield(_) | Expr::YieldFrom(_) => self.unconditional_next_block(after), - Expr::IpyEscapeCommand(_) => todo!(), } } // The tough branches are done, here is an easy one. Stmt::Return(_) => NextBlock::Terminate, - Stmt::TypeAlias(_) => todo!(), - Stmt::IpyEscapeCommand(_) => todo!(), }; // Include any statements in the block that don't divert the control flow. @@ -898,6 +898,8 @@ fn needs_next_block(stmts: &[Stmt]) -> bool { | Stmt::AnnAssign(_) | Stmt::Expr(_) | Stmt::Pass(_) + | Stmt::TypeAlias(_) + | Stmt::IpyEscapeCommand(_) // TODO: check below. | Stmt::Break(_) | Stmt::Continue(_) @@ -907,8 +909,6 @@ fn needs_next_block(stmts: &[Stmt]) -> bool { | Stmt::Match(_) | Stmt::Try(_) | Stmt::Assert(_) => true, - Stmt::TypeAlias(_) => todo!(), - Stmt::IpyEscapeCommand(_) => todo!(), } } @@ -927,6 +927,8 @@ fn is_control_flow_stmt(stmt: &Stmt) -> bool { | Stmt::AugAssign(_) | Stmt::AnnAssign(_) | Stmt::Expr(_) + | Stmt::TypeAlias(_) + | Stmt::IpyEscapeCommand(_) | Stmt::Pass(_) => false, Stmt::Return(_) | Stmt::For(_) @@ -939,8 +941,6 @@ fn is_control_flow_stmt(stmt: &Stmt) -> bool { | Stmt::Assert(_) | Stmt::Break(_) | Stmt::Continue(_) => true, - Stmt::TypeAlias(_) => todo!(), - Stmt::IpyEscapeCommand(_) => todo!(), } } From 5aaf99b856bdd26cd281ab1b99b8d7227cd6185d Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Sat, 2 Dec 2023 09:35:34 +0900 Subject: [PATCH 090/197] Implement the `fix_power_op_line_length` preview style (#8947) --- .../src/expression/binary_like.rs | 16 +- .../src/expression/parentheses.rs | 20 + ...ty@cases__preview_power_op_spacing.py.snap | 354 ------------------ 3 files changed, 30 insertions(+), 360 deletions(-) delete mode 100644 crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_power_op_spacing.py.snap diff --git a/crates/ruff_python_formatter/src/expression/binary_like.rs b/crates/ruff_python_formatter/src/expression/binary_like.rs index 6c88db34f6e0f..149449d61cb04 100644 --- a/crates/ruff_python_formatter/src/expression/binary_like.rs +++ b/crates/ruff_python_formatter/src/expression/binary_like.rs @@ -3,7 +3,7 @@ use std::ops::{Deref, Index}; use smallvec::SmallVec; -use ruff_formatter::write; +use ruff_formatter::{write, FormatContext}; use ruff_python_ast::{ Expr, ExprAttribute, ExprBinOp, ExprBoolOp, ExprCompare, ExprUnaryOp, UnaryOp, }; @@ -13,10 +13,10 @@ use ruff_text_size::{Ranged, TextRange}; use crate::comments::{leading_comments, trailing_comments, Comments, SourceComment}; use crate::expression::parentheses::{ - in_parentheses_only_group, in_parentheses_only_soft_line_break, - in_parentheses_only_soft_line_break_or_space, is_expression_parenthesized, - write_in_parentheses_only_group_end_tag, write_in_parentheses_only_group_start_tag, - Parentheses, + in_parentheses_only_group, in_parentheses_only_if_group_breaks, + in_parentheses_only_soft_line_break, in_parentheses_only_soft_line_break_or_space, + is_expression_parenthesized, write_in_parentheses_only_group_end_tag, + write_in_parentheses_only_group_start_tag, Parentheses, }; use crate::expression::string::{AnyString, FormatString, StringLayout}; use crate::expression::OperatorPrecedence; @@ -718,7 +718,11 @@ impl Format> for FlatBinaryExpressionSlice<'_> { ) { hard_line_break().fmt(f)?; - } else if !is_pow { + } else if is_pow { + if f.context().options().preview().is_enabled() { + in_parentheses_only_if_group_breaks(&space()).fmt(f)?; + } + } else { space().fmt(f)?; } diff --git a/crates/ruff_python_formatter/src/expression/parentheses.rs b/crates/ruff_python_formatter/src/expression/parentheses.rs index 971d913146609..d6a40f213b6ad 100644 --- a/crates/ruff_python_formatter/src/expression/parentheses.rs +++ b/crates/ruff_python_formatter/src/expression/parentheses.rs @@ -355,6 +355,26 @@ pub(super) fn write_in_parentheses_only_group_end_tag(f: &mut PyFormatter) { } } +/// Shows prints `content` only if the expression is enclosed by (optional) parentheses (`()`, `[]`, or `{}`) +/// and splits across multiple lines. +pub(super) fn in_parentheses_only_if_group_breaks<'a, T>( + content: T, +) -> impl Format> +where + T: Format>, +{ + format_with(move |f: &mut PyFormatter| match f.context().node_level() { + NodeLevel::TopLevel(_) | NodeLevel::CompoundStatement | NodeLevel::Expression(None) => { + // no-op, not parenthesized + Ok(()) + } + NodeLevel::Expression(Some(parentheses_id)) => if_group_breaks(&content) + .with_group_id(Some(parentheses_id)) + .fmt(f), + NodeLevel::ParenthesizedExpression => if_group_breaks(&content).fmt(f), + }) +} + /// Format comments inside empty parentheses, brackets or curly braces. /// /// Empty `()`, `[]` and `{}` are special because there can be dangling comments, and they can be in diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_power_op_spacing.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_power_op_spacing.py.snap deleted file mode 100644 index f7cb0914c0304..0000000000000 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_power_op_spacing.py.snap +++ /dev/null @@ -1,354 +0,0 @@ ---- -source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_power_op_spacing.py ---- -## Input - -```python -a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -b = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -c = 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 -d = 1**1 ** 1**1 ** 1**1 ** 1**1 ** 1**1**1 ** 1 ** 1**1 ** 1**1**1**1**1 ** 1 ** 1**1**1 **1**1** 1 ** 1 ** 1 -e = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 -f = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 - -a = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -b = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -c = 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 -d = 1.0**1.0 ** 1.0**1.0 ** 1.0**1.0 ** 1.0**1.0 ** 1.0**1.0**1.0 ** 1.0 ** 1.0**1.0 ** 1.0**1.0**1.0 -``` - -## Black Differences - -```diff ---- Black -+++ Ruff -@@ -1,83 +1,83 @@ - a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 - b = ( - 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 - ) - c = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 - d = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 - e = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 - f = ( - 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 - ) - - a = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 - b = ( - 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 - ) - c = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 - d = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -``` - -## Ruff Output - -```python -a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -b = ( - 1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 -) -c = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -d = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -e = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 -f = ( - 𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 -) - -a = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -b = ( - 1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 -) -c = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -d = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -``` - -## Black Output - -```python -a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -b = ( - 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 -) -c = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -d = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -e = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 -f = ( - 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 -) - -a = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -b = ( - 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 -) -c = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -d = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -``` - - From 35082b28cdd7c7e9a9fa587149df657ca740a0be Mon Sep 17 00:00:00 2001 From: Tom Kuson Date: Sat, 2 Dec 2023 13:52:50 +0000 Subject: [PATCH 091/197] Fix error in `t-suffixed-type-alias` (`PYI043`) example (#8963) ## Summary For `t-suffixed-type-alias` to trigger, the type alias needs to be marked as such using the `typing.TypeAlias` annotation and the name of the alias must be marked as private using a leading underscore. The documentation example was of an unannotated type alias that was not marked as private, which was misleading. ## Test Plan The current example doesn't trigger the rule; the example in this merge request does. --- .../src/rules/flake8_pyi/rules/type_alias_naming.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/type_alias_naming.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/type_alias_naming.rs index e240bd3bd8191..4e60317211c2c 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/type_alias_naming.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/type_alias_naming.rs @@ -46,12 +46,16 @@ impl Violation for SnakeCaseTypeAlias { /// /// ## Example /// ```python -/// MyTypeT = int +/// from typing import TypeAlias +/// +/// _MyTypeT: TypeAlias = int /// ``` /// /// Use instead: /// ```python -/// MyType = int +/// from typing import TypeAlias +/// +/// _MyType: TypeAlias = int /// ``` #[violation] pub struct TSuffixedTypeAlias { From 22d8a989d48caf3e4bd558400cc3bc19f472001d Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 2 Dec 2023 08:56:57 -0500 Subject: [PATCH 092/197] Avoid underflow in `get_model` matching (#8965) Closes https://github.com/astral-sh/ruff/issues/8962. --- .../resources/test/fixtures/pep8_naming/N806.py | 3 +++ .../ruff_linter/src/rules/pep8_naming/helpers.rs | 6 +++++- ..._rules__pep8_naming__tests__N806_N806.py.snap | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py b/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py index bbaf2b785fc90..d3a0585cb46a1 100644 --- a/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py +++ b/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py @@ -52,3 +52,6 @@ def model_assign() -> None: Bad = import_string("django.core.exceptions.ValidationError") # N806 ValidationError = import_string("django.core.exceptions.ValidationError") # OK + + Bad = apps.get_model() # N806 + Bad = apps.get_model(model_name="Stream") # N806 diff --git a/crates/ruff_linter/src/rules/pep8_naming/helpers.rs b/crates/ruff_linter/src/rules/pep8_naming/helpers.rs index fc8f6568af827..00ad10b77f4da 100644 --- a/crates/ruff_linter/src/rules/pep8_naming/helpers.rs +++ b/crates/ruff_linter/src/rules/pep8_naming/helpers.rs @@ -101,11 +101,15 @@ pub(super) fn is_django_model_import(name: &str, stmt: &Stmt, semantic: &Semanti return false; }; + if arguments.is_empty() { + return false; + } + // Match against, e.g., `apps.get_model("zerver", "Attachment")`. if let Some(call_path) = collect_call_path(func.as_ref()) { if matches!(call_path.as_slice(), [.., "get_model"]) { if let Some(argument) = - arguments.find_argument("model_name", arguments.args.len() - 1) + arguments.find_argument("model_name", arguments.args.len().saturating_sub(1)) { if let Some(string_literal) = argument.as_string_literal_expr() { return string_literal.value.to_str() == name; diff --git a/crates/ruff_linter/src/rules/pep8_naming/snapshots/ruff_linter__rules__pep8_naming__tests__N806_N806.py.snap b/crates/ruff_linter/src/rules/pep8_naming/snapshots/ruff_linter__rules__pep8_naming__tests__N806_N806.py.snap index e572eecccb0ad..d53fb46f9df72 100644 --- a/crates/ruff_linter/src/rules/pep8_naming/snapshots/ruff_linter__rules__pep8_naming__tests__N806_N806.py.snap +++ b/crates/ruff_linter/src/rules/pep8_naming/snapshots/ruff_linter__rules__pep8_naming__tests__N806_N806.py.snap @@ -38,4 +38,20 @@ N806.py:53:5: N806 Variable `Bad` in function should be lowercase 54 | ValidationError = import_string("django.core.exceptions.ValidationError") # OK | +N806.py:56:5: N806 Variable `Bad` in function should be lowercase + | +54 | ValidationError = import_string("django.core.exceptions.ValidationError") # OK +55 | +56 | Bad = apps.get_model() # N806 + | ^^^ N806 +57 | Bad = apps.get_model(model_name="Stream") # N806 + | + +N806.py:57:5: N806 Variable `Bad` in function should be lowercase + | +56 | Bad = apps.get_model() # N806 +57 | Bad = apps.get_model(model_name="Stream") # N806 + | ^^^ N806 + | + From 20ab14e3548ffcc2da2dd35562a1365145fb9f87 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 2 Dec 2023 13:17:17 -0500 Subject: [PATCH 093/197] Avoid unnecessary index diagnostics when value is modified (#8970) Closes https://github.com/astral-sh/ruff/issues/8969. --- .../pylint/unnecessary_dict_index_lookup.py | 27 ++-- .../pylint/unnecessary_list_index_lookup.py | 49 ++++---- .../ruff_linter/src/rules/pylint/helpers.rs | 117 +++++++++++++++++- .../rules/unnecessary_dict_index_lookup.rs | 106 +--------------- .../rules/unnecessary_list_index_lookup.rs | 115 +---------------- ...1736_unnecessary_list_index_lookup.py.snap | 12 +- 6 files changed, 180 insertions(+), 246 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_dict_index_lookup.py b/crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_dict_index_lookup.py index cfdd9fc42ae04..d3daeb83c97b8 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_dict_index_lookup.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_dict_index_lookup.py @@ -14,16 +14,27 @@ def fix_these(): def dont_fix_these(): # once there is an assignment to the dict[index], we stop emitting diagnostics for fruit_name, fruit_count in FRUITS.items(): - FRUITS[fruit_name] = 0 # Ok - assert FRUITS[fruit_name] == 0 # Ok + FRUITS[fruit_name] = 0 # OK + assert FRUITS[fruit_name] == 0 # OK + + # once there is an assignment to the key, we stop emitting diagnostics + for fruit_name, fruit_count in FRUITS.items(): + fruit_name = 0 # OK + assert FRUITS[fruit_name] == 0 # OK + + # once there is an assignment to the value, we stop emitting diagnostics + for fruit_name, fruit_count in FRUITS.items(): + if fruit_count < 5: + fruit_count = -fruit_count + assert FRUITS[fruit_name] == 0 # OK def value_intentionally_unused(): - [FRUITS[fruit_name] for fruit_name, _ in FRUITS.items()] # Ok - {FRUITS[fruit_name] for fruit_name, _ in FRUITS.items()} # Ok - {fruit_name: FRUITS[fruit_name] for fruit_name, _ in FRUITS.items()} # Ok + [FRUITS[fruit_name] for fruit_name, _ in FRUITS.items()] # OK + {FRUITS[fruit_name] for fruit_name, _ in FRUITS.items()} # OK + {fruit_name: FRUITS[fruit_name] for fruit_name, _ in FRUITS.items()} # OK for fruit_name, _ in FRUITS.items(): - print(FRUITS[fruit_name]) # Ok - blah = FRUITS[fruit_name] # Ok - assert FRUITS[fruit_name] == "pear" # Ok + print(FRUITS[fruit_name]) # OK + blah = FRUITS[fruit_name] # OK + assert FRUITS[fruit_name] == "pear" # OK diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_list_index_lookup.py b/crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_list_index_lookup.py index 182e63cb7b913..8911c8bd26c96 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_list_index_lookup.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_list_index_lookup.py @@ -12,7 +12,7 @@ def fix_these(): print(letters[index]) # PLR1736 blah = letters[index] # PLR1736 assert letters[index] == "d" # PLR1736 - + for index, letter in builtins.enumerate(letters): print(letters[index]) # PLR1736 blah = letters[index] # PLR1736 @@ -22,38 +22,43 @@ def fix_these(): def dont_fix_these(): # once there is an assignment to the sequence[index], we stop emitting diagnostics for index, letter in enumerate(letters): - letters[index] = "d" # Ok - letters[index] += "e" # Ok - assert letters[index] == "de" # Ok - + letters[index] = "d" # OK + letters[index] += "e" # OK + assert letters[index] == "de" # OK + # once there is an assignment to the index, we stop emitting diagnostics for index, letter in enumerate(letters): - index += 1 # Ok - print(letters[index]) # Ok - + index += 1 # OK + print(letters[index]) # OK + # once there is an assignment to the sequence, we stop emitting diagnostics for index, letter in enumerate(letters): - letters = ["d", "e", "f"] # Ok - print(letters[index]) # Ok + letters = ["d", "e", "f"] # OK + print(letters[index]) # OK + + # once there is an assignment to the value, we stop emitting diagnostics + for index, letter in enumerate(letters): + letter = "d" + print(letters[index]) # OK # once there is an deletion from or of the sequence or index, we stop emitting diagnostics for index, letter in enumerate(letters): - del letters[index] # Ok - print(letters[index]) # Ok + del letters[index] # OK + print(letters[index]) # OK for index, letter in enumerate(letters): - del letters # Ok - print(letters[index]) # Ok + del letters # OK + print(letters[index]) # OK for index, letter in enumerate(letters): - del index # Ok - print(letters[index]) # Ok + del index # OK + print(letters[index]) # OK def value_intentionally_unused(): - [letters[index] for index, _ in enumerate(letters)] # Ok - {letters[index] for index, _ in enumerate(letters)} # Ok - {index: letters[index] for index, _ in enumerate(letters)} # Ok + [letters[index] for index, _ in enumerate(letters)] # OK + {letters[index] for index, _ in enumerate(letters)} # OK + {index: letters[index] for index, _ in enumerate(letters)} # OK for index, _ in enumerate(letters): - print(letters[index]) # Ok - blah = letters[index] # Ok - letters[index] = "d" # Ok + print(letters[index]) # OK + blah = letters[index] # OK + letters[index] = "d" # OK diff --git a/crates/ruff_linter/src/rules/pylint/helpers.rs b/crates/ruff_linter/src/rules/pylint/helpers.rs index 027272d03c004..d68e639b59f56 100644 --- a/crates/ruff_linter/src/rules/pylint/helpers.rs +++ b/crates/ruff_linter/src/rules/pylint/helpers.rs @@ -1,9 +1,11 @@ use std::fmt; use ruff_python_ast as ast; -use ruff_python_ast::{Arguments, CmpOp, Expr}; +use ruff_python_ast::visitor::Visitor; +use ruff_python_ast::{visitor, Arguments, CmpOp, Expr, Stmt}; use ruff_python_semantic::analyze::function_type; use ruff_python_semantic::{ScopeKind, SemanticModel}; +use ruff_text_size::TextRange; use crate::settings::LinterSettings; @@ -82,3 +84,116 @@ impl fmt::Display for CmpOpExt { write!(f, "{representation}") } } + +/// Visitor to track reads from an iterable in a loop. +#[derive(Debug)] +pub(crate) struct SequenceIndexVisitor<'a> { + /// `letters`, given `for index, letter in enumerate(letters)`. + sequence_name: &'a str, + /// `index`, given `for index, letter in enumerate(letters)`. + index_name: &'a str, + /// `letter`, given `for index, letter in enumerate(letters)`. + value_name: &'a str, + /// The ranges of any `letters[index]` accesses. + accesses: Vec, + /// Whether any of the variables have been modified. + modified: bool, +} + +impl<'a> SequenceIndexVisitor<'a> { + pub(crate) fn new(sequence_name: &'a str, index_name: &'a str, value_name: &'a str) -> Self { + Self { + sequence_name, + index_name, + value_name, + accesses: Vec::new(), + modified: false, + } + } + + pub(crate) fn into_accesses(self) -> Vec { + self.accesses + } +} + +impl SequenceIndexVisitor<'_> { + fn is_assignment(&self, expr: &Expr) -> bool { + // If we see the sequence, a subscript, or the index being modified, we'll stop emitting + // diagnostics. + match expr { + Expr::Name(ast::ExprName { id, .. }) => { + id == self.sequence_name || id == self.index_name || id == self.value_name + } + Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => { + let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { + return false; + }; + if id == self.sequence_name { + let Expr::Name(ast::ExprName { id, .. }) = slice.as_ref() else { + return false; + }; + if id == self.index_name { + return true; + } + } + false + } + _ => false, + } + } +} + +impl<'a> Visitor<'_> for SequenceIndexVisitor<'a> { + fn visit_stmt(&mut self, stmt: &Stmt) { + if self.modified { + return; + } + match stmt { + Stmt::Assign(ast::StmtAssign { targets, value, .. }) => { + self.modified = targets.iter().any(|target| self.is_assignment(target)); + self.visit_expr(value); + } + Stmt::AnnAssign(ast::StmtAnnAssign { target, value, .. }) => { + if let Some(value) = value { + self.modified = self.is_assignment(target); + self.visit_expr(value); + } + } + Stmt::AugAssign(ast::StmtAugAssign { target, value, .. }) => { + self.modified = self.is_assignment(target); + self.visit_expr(value); + } + Stmt::Delete(ast::StmtDelete { targets, .. }) => { + self.modified = targets.iter().any(|target| self.is_assignment(target)); + } + _ => visitor::walk_stmt(self, stmt), + } + } + + fn visit_expr(&mut self, expr: &Expr) { + if self.modified { + return; + } + match expr { + Expr::Subscript(ast::ExprSubscript { + value, + slice, + range, + .. + }) => { + let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { + return; + }; + if id == self.sequence_name { + let Expr::Name(ast::ExprName { id, .. }) = slice.as_ref() else { + return; + }; + if id == self.index_name { + self.accesses.push(*range); + } + } + } + _ => visitor::walk_expr(self, expr), + } + } +} diff --git a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dict_index_lookup.rs b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dict_index_lookup.rs index 16dc733d61d80..88a842b7d6b4b 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dict_index_lookup.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dict_index_lookup.rs @@ -1,13 +1,10 @@ -use ast::Stmt; -use ruff_python_ast::{self as ast, Expr, StmtFor}; - use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::visitor; use ruff_python_ast::visitor::Visitor; -use ruff_text_size::TextRange; +use ruff_python_ast::{self as ast, Expr, StmtFor}; use crate::checkers::ast::Checker; +use crate::rules::pylint::helpers::SequenceIndexVisitor; /// ## What it does /// Checks for key-based dict accesses during `.items()` iterations. @@ -54,10 +51,10 @@ pub(crate) fn unnecessary_dict_index_lookup(checker: &mut Checker, stmt_for: &St }; let ranges = { - let mut visitor = SubscriptVisitor::new(dict_name, index_name); + let mut visitor = SequenceIndexVisitor::new(dict_name, index_name, value_name); visitor.visit_body(&stmt_for.body); visitor.visit_body(&stmt_for.orelse); - visitor.diagnostic_ranges + visitor.into_accesses() }; for range in ranges { @@ -96,12 +93,12 @@ pub(crate) fn unnecessary_dict_index_lookup_comprehension(checker: &mut Checker, }; let ranges = { - let mut visitor = SubscriptVisitor::new(dict_name, index_name); + let mut visitor = SequenceIndexVisitor::new(dict_name, index_name, value_name); visitor.visit_expr(elt.as_ref()); for expr in &comp.ifs { visitor.visit_expr(expr); } - visitor.diagnostic_ranges + visitor.into_accesses() }; for range in ranges { @@ -161,94 +158,3 @@ fn dict_items<'a>( Some((dict_name, index_name, value_name)) } - -#[derive(Debug)] -struct SubscriptVisitor<'a> { - dict_name: &'a str, - index_name: &'a str, - diagnostic_ranges: Vec, - modified: bool, -} - -impl<'a> SubscriptVisitor<'a> { - fn new(dict_name: &'a str, index_name: &'a str) -> Self { - Self { - dict_name, - index_name, - diagnostic_ranges: Vec::new(), - modified: false, - } - } -} - -impl SubscriptVisitor<'_> { - fn is_assignment(&self, expr: &Expr) -> bool { - let Expr::Subscript(ast::ExprSubscript { value, slice, .. }) = expr else { - return false; - }; - let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { - return false; - }; - if id == self.dict_name { - let Expr::Name(ast::ExprName { id, .. }) = slice.as_ref() else { - return false; - }; - if id == self.index_name { - return true; - } - } - false - } -} - -impl<'a> Visitor<'_> for SubscriptVisitor<'a> { - fn visit_stmt(&mut self, stmt: &Stmt) { - if self.modified { - return; - } - match stmt { - Stmt::Assign(ast::StmtAssign { targets, value, .. }) => { - self.modified = targets.iter().any(|target| self.is_assignment(target)); - self.visit_expr(value); - } - Stmt::AnnAssign(ast::StmtAnnAssign { target, value, .. }) => { - if let Some(value) = value { - self.modified = self.is_assignment(target); - self.visit_expr(value); - } - } - Stmt::AugAssign(ast::StmtAugAssign { target, value, .. }) => { - self.modified = self.is_assignment(target); - self.visit_expr(value); - } - _ => visitor::walk_stmt(self, stmt), - } - } - - fn visit_expr(&mut self, expr: &Expr) { - if self.modified { - return; - } - match expr { - Expr::Subscript(ast::ExprSubscript { - value, - slice, - range, - .. - }) => { - let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { - return; - }; - if id == self.dict_name { - let Expr::Name(ast::ExprName { id, .. }) = slice.as_ref() else { - return; - }; - if id == self.index_name { - self.diagnostic_ranges.push(*range); - } - } - } - _ => visitor::walk_expr(self, expr), - } - } -} diff --git a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs index 17a42b29e25a2..920d2442e9b5a 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs @@ -1,13 +1,11 @@ -use ruff_python_ast::{self as ast, Expr, Stmt, StmtFor}; - use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::visitor; use ruff_python_ast::visitor::Visitor; +use ruff_python_ast::{self as ast, Expr, StmtFor}; use ruff_python_semantic::SemanticModel; -use ruff_text_size::TextRange; use crate::checkers::ast::Checker; +use crate::rules::pylint::helpers::SequenceIndexVisitor; /// ## What it does /// Checks for index-based list accesses during `enumerate` iterations. @@ -55,10 +53,10 @@ pub(crate) fn unnecessary_list_index_lookup(checker: &mut Checker, stmt_for: &St }; let ranges = { - let mut visitor = SubscriptVisitor::new(sequence, index_name); + let mut visitor = SequenceIndexVisitor::new(sequence, index_name, value_name); visitor.visit_body(&stmt_for.body); visitor.visit_body(&stmt_for.orelse); - visitor.diagnostic_ranges + visitor.into_accesses() }; for range in ranges { @@ -99,9 +97,9 @@ pub(crate) fn unnecessary_list_index_lookup_comprehension(checker: &mut Checker, }; let ranges = { - let mut visitor = SubscriptVisitor::new(sequence, index_name); + let mut visitor = SequenceIndexVisitor::new(sequence, index_name, value_name); visitor.visit_expr(elt.as_ref()); - visitor.diagnostic_ranges + visitor.into_accesses() }; for range in ranges { @@ -161,104 +159,3 @@ fn enumerate_items<'a>( Some((sequence, index_name, value_name)) } - -#[derive(Debug)] -struct SubscriptVisitor<'a> { - sequence_name: &'a str, - index_name: &'a str, - diagnostic_ranges: Vec, - modified: bool, -} - -impl<'a> SubscriptVisitor<'a> { - fn new(sequence_name: &'a str, index_name: &'a str) -> Self { - Self { - sequence_name, - index_name, - diagnostic_ranges: Vec::new(), - modified: false, - } - } -} - -impl SubscriptVisitor<'_> { - fn is_assignment(&self, expr: &Expr) -> bool { - // If we see the sequence, a subscript, or the index being modified, we'll stop emitting - // diagnostics. - match expr { - Expr::Name(ast::ExprName { id, .. }) => { - id == self.sequence_name || id == self.index_name - } - Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => { - let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { - return false; - }; - if id == self.sequence_name { - let Expr::Name(ast::ExprName { id, .. }) = slice.as_ref() else { - return false; - }; - if id == self.index_name { - return true; - } - } - false - } - _ => false, - } - } -} - -impl<'a> Visitor<'_> for SubscriptVisitor<'a> { - fn visit_stmt(&mut self, stmt: &Stmt) { - if self.modified { - return; - } - match stmt { - Stmt::Assign(ast::StmtAssign { targets, value, .. }) => { - self.modified = targets.iter().any(|target| self.is_assignment(target)); - self.visit_expr(value); - } - Stmt::AnnAssign(ast::StmtAnnAssign { target, value, .. }) => { - if let Some(value) = value { - self.modified = self.is_assignment(target); - self.visit_expr(value); - } - } - Stmt::AugAssign(ast::StmtAugAssign { target, value, .. }) => { - self.modified = self.is_assignment(target); - self.visit_expr(value); - } - Stmt::Delete(ast::StmtDelete { targets, .. }) => { - self.modified = targets.iter().any(|target| self.is_assignment(target)); - } - _ => visitor::walk_stmt(self, stmt), - } - } - - fn visit_expr(&mut self, expr: &Expr) { - if self.modified { - return; - } - match expr { - Expr::Subscript(ast::ExprSubscript { - value, - slice, - range, - .. - }) => { - let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { - return; - }; - if id == self.sequence_name { - let Expr::Name(ast::ExprName { id, .. }) = slice.as_ref() else { - return; - }; - if id == self.index_name { - self.diagnostic_ranges.push(*range); - } - } - } - _ => visitor::walk_expr(self, expr), - } - } -} diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1736_unnecessary_list_index_lookup.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1736_unnecessary_list_index_lookup.py.snap index 8e4d22472df3d..880422eab6674 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1736_unnecessary_list_index_lookup.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR1736_unnecessary_list_index_lookup.py.snap @@ -80,7 +80,7 @@ unnecessary_list_index_lookup.py:12:15: PLR1736 [*] Unnecessary lookup of list i 12 |+ print(letter) # PLR1736 13 13 | blah = letters[index] # PLR1736 14 14 | assert letters[index] == "d" # PLR1736 -15 15 | +15 15 | unnecessary_list_index_lookup.py:13:16: PLR1736 [*] Unnecessary lookup of list item by index | @@ -99,7 +99,7 @@ unnecessary_list_index_lookup.py:13:16: PLR1736 [*] Unnecessary lookup of list i 13 |- blah = letters[index] # PLR1736 13 |+ blah = letter # PLR1736 14 14 | assert letters[index] == "d" # PLR1736 -15 15 | +15 15 | 16 16 | for index, letter in builtins.enumerate(letters): unnecessary_list_index_lookup.py:14:16: PLR1736 [*] Unnecessary lookup of list item by index @@ -108,7 +108,7 @@ unnecessary_list_index_lookup.py:14:16: PLR1736 [*] Unnecessary lookup of list i 13 | blah = letters[index] # PLR1736 14 | assert letters[index] == "d" # PLR1736 | ^^^^^^^^^^^^^^ PLR1736 -15 | +15 | 16 | for index, letter in builtins.enumerate(letters): | = help: Use existing variable @@ -119,7 +119,7 @@ unnecessary_list_index_lookup.py:14:16: PLR1736 [*] Unnecessary lookup of list i 13 13 | blah = letters[index] # PLR1736 14 |- assert letters[index] == "d" # PLR1736 14 |+ assert letter == "d" # PLR1736 -15 15 | +15 15 | 16 16 | for index, letter in builtins.enumerate(letters): 17 17 | print(letters[index]) # PLR1736 @@ -135,7 +135,7 @@ unnecessary_list_index_lookup.py:17:15: PLR1736 [*] Unnecessary lookup of list i ℹ Safe fix 14 14 | assert letters[index] == "d" # PLR1736 -15 15 | +15 15 | 16 16 | for index, letter in builtins.enumerate(letters): 17 |- print(letters[index]) # PLR1736 17 |+ print(letter) # PLR1736 @@ -154,7 +154,7 @@ unnecessary_list_index_lookup.py:18:16: PLR1736 [*] Unnecessary lookup of list i = help: Use existing variable ℹ Safe fix -15 15 | +15 15 | 16 16 | for index, letter in builtins.enumerate(letters): 17 17 | print(letters[index]) # PLR1736 18 |- blah = letters[index] # PLR1736 From 3fbabfe12690c27c8a0d16230ed925afa7ed6c74 Mon Sep 17 00:00:00 2001 From: Tom Kuson Date: Sat, 2 Dec 2023 18:26:43 +0000 Subject: [PATCH 094/197] [`flake8-pyi`] Check PEP 695 type aliases for `snake-case-type-alias` and `t-suffixed-type-alias` (#8966) ## Summary Check PEP 695 type alias definitions for `snake-case-type-alias` (`PYI042`) and `t-suffixed-type-alias` (`PYI043`) Related to #8771. ## Test Plan `cargo test` --- .../resources/test/fixtures/flake8_pyi/PYI042.py | 4 ++++ .../resources/test/fixtures/flake8_pyi/PYI042.pyi | 4 ++++ .../resources/test/fixtures/flake8_pyi/PYI043.py | 4 ++++ .../resources/test/fixtures/flake8_pyi/PYI043.pyi | 4 ++++ crates/ruff_linter/src/checkers/ast/analyze/statement.rs | 8 ++++++++ ...inter__rules__flake8_pyi__tests__PYI042_PYI042.py.snap | 8 ++++++++ ...nter__rules__flake8_pyi__tests__PYI042_PYI042.pyi.snap | 8 ++++++++ ...inter__rules__flake8_pyi__tests__PYI043_PYI043.py.snap | 8 ++++++++ ...nter__rules__flake8_pyi__tests__PYI043_PYI043.pyi.snap | 8 ++++++++ 9 files changed, 56 insertions(+) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI042.py b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI042.py index 2936c39c6c836..2d2b932e42c8a 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI042.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI042.py @@ -22,3 +22,7 @@ # check that this edge case doesn't crash _: TypeAlias = str | int + +# PEP 695 +type foo_bar = int | str +type FooBar = int | str diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI042.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI042.pyi index 2936c39c6c836..2d2b932e42c8a 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI042.pyi +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI042.pyi @@ -22,3 +22,7 @@ Snake_case_alias: TypeAlias = int | float # PYI042, since not camel case # check that this edge case doesn't crash _: TypeAlias = str | int + +# PEP 695 +type foo_bar = int | str +type FooBar = int | str diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI043.py b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI043.py index b48f5e0fa8c47..b8107662f9931 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI043.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI043.py @@ -21,3 +21,7 @@ # check that this edge case doesn't crash _: TypeAlias = str | int + +# PEP 695 +type _FooT = str | int +type Foo = str | int diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI043.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI043.pyi index b48f5e0fa8c47..b8107662f9931 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI043.pyi +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI043.pyi @@ -21,3 +21,7 @@ _PrivateAliasS2: TypeAlias = Annotated[str, "also okay"] # check that this edge case doesn't crash _: TypeAlias = str | int + +# PEP 695 +type _FooT = str | int +type Foo = str | int diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 99ea30595f0a6..4b79a9ec7da14 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -1534,6 +1534,14 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { } } } + Stmt::TypeAlias(ast::StmtTypeAlias { name, .. }) => { + if checker.enabled(Rule::SnakeCaseTypeAlias) { + flake8_pyi::rules::snake_case_type_alias(checker, name); + } + if checker.enabled(Rule::TSuffixedTypeAlias) { + flake8_pyi::rules::t_suffixed_type_alias(checker, name); + } + } Stmt::Delete(delete @ ast::StmtDelete { targets, range: _ }) => { if checker.enabled(Rule::GlobalStatement) { for target in targets { diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI042_PYI042.py.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI042_PYI042.py.snap index 1f80b9c9af969..539eb12d99a7f 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI042_PYI042.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI042_PYI042.py.snap @@ -29,4 +29,12 @@ PYI042.py:20:1: PYI042 Type alias `_snake_case_alias2` should be CamelCase 21 | Snake_case_alias: TypeAlias = int | float # PYI042, since not camel case | +PYI042.py:27:6: PYI042 Type alias `foo_bar` should be CamelCase + | +26 | # PEP 695 +27 | type foo_bar = int | str + | ^^^^^^^ PYI042 +28 | type FooBar = int | str + | + diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI042_PYI042.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI042_PYI042.pyi.snap index ab3c2fe98eeed..9d1d034c0018e 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI042_PYI042.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI042_PYI042.pyi.snap @@ -29,4 +29,12 @@ PYI042.pyi:20:1: PYI042 Type alias `_snake_case_alias2` should be CamelCase 21 | Snake_case_alias: TypeAlias = int | float # PYI042, since not camel case | +PYI042.pyi:27:6: PYI042 Type alias `foo_bar` should be CamelCase + | +26 | # PEP 695 +27 | type foo_bar = int | str + | ^^^^^^^ PYI042 +28 | type FooBar = int | str + | + diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI043_PYI043.py.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI043_PYI043.py.snap index 3dfc9c819b5e8..550ad122d17de 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI043_PYI043.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI043_PYI043.py.snap @@ -30,4 +30,12 @@ PYI043.py:12:1: PYI043 Private type alias `_PrivateAliasT3` should not be suffix 14 | ] # PYI043, since this ends in a T | +PYI043.py:26:6: PYI043 Private type alias `_FooT` should not be suffixed with `T` (the `T` suffix implies that an object is a `TypeVar`) + | +25 | # PEP 695 +26 | type _FooT = str | int + | ^^^^^ PYI043 +27 | type Foo = str | int + | + diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI043_PYI043.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI043_PYI043.pyi.snap index f856dc86ad88a..80fb8b4c19182 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI043_PYI043.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI043_PYI043.pyi.snap @@ -30,4 +30,12 @@ PYI043.pyi:12:1: PYI043 Private type alias `_PrivateAliasT3` should not be suffi 14 | ] # PYI043, since this ends in a T | +PYI043.pyi:26:6: PYI043 Private type alias `_FooT` should not be suffixed with `T` (the `T` suffix implies that an object is a `TypeVar`) + | +25 | # PEP 695 +26 | type _FooT = str | int + | ^^^^^ PYI043 +27 | type Foo = str | int + | + From 1dda669f9a680ed55ff91d8c36c20560b6cab054 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 2 Dec 2023 13:37:49 -0500 Subject: [PATCH 095/197] Avoid syntax error via invalid ur string prefix (#8971) ## Summary If a string has a Unicode prefix, we can't add the `r` prefix on top of that -- we need to remove and replace it. (The Unicode prefix is redundant anyway in Python 3.) Closes https://github.com/astral-sh/ruff/issues/8967. --- .../test/fixtures/pycodestyle/W605_0.py | 3 + .../test/fixtures/pycodestyle/W605_1.py | 42 ++- .../test/fixtures/pycodestyle/W605_2.py | 54 ---- .../ruff_linter/src/rules/pycodestyle/mod.rs | 1 - .../rules/invalid_escape_sequence.rs | 84 ++++-- ...s__pycodestyle__tests__W605_W605_0.py.snap | 20 ++ ...s__pycodestyle__tests__W605_W605_1.py.snap | 273 +++++++++++++----- ...s__pycodestyle__tests__W605_W605_2.py.snap | 227 --------------- 8 files changed, 303 insertions(+), 401 deletions(-) delete mode 100644 crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_2.py delete mode 100644 crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W605_W605_2.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_0.py b/crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_0.py index 967ed5bc4d334..85ec535e22d19 100644 --- a/crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_0.py +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_0.py @@ -43,3 +43,6 @@ def f(): ''' # noqa regex = '\\\_' + +#: W605:1:7 +u'foo\ bar' diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_1.py b/crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_1.py index 20bf0ea14c8f7..b34ad587c46d5 100644 --- a/crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_1.py +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_1.py @@ -1,40 +1,54 @@ +# Same as `W605_0.py` but using f-strings instead. + #: W605:1:10 -regex = '\.png$' +regex = f'\.png$' #: W605:2:1 -regex = ''' +regex = f''' \.png$ ''' #: W605:2:6 f( - '\_' + f'\_' ) #: W605:4:6 -""" +f""" multi-line literal with \_ somewhere in the middle """ +#: W605:1:38 +value = f'new line\nand invalid escape \_ here' -def f(): - #: W605:1:11 - return'\.png$' #: Okay -regex = r'\.png$' -regex = '\\.png$' -regex = r''' +regex = fr'\.png$' +regex = f'\\.png$' +regex = fr''' \.png$ ''' -regex = r''' +regex = fr''' \\.png$ ''' -s = '\\' -regex = '\w' # noqa -regex = ''' +s = f'\\' +regex = f'\w' # noqa +regex = f''' \w ''' # noqa + +regex = f'\\\_' +value = f'\{{1}}' +value = f'\{1}' +value = f'{1:\}' +value = f"{f"\{1}"}" +value = rf"{f"\{1}"}" + +# Okay +value = rf'\{{1}}' +value = rf'\{1}' +value = rf'{1:\}' +value = f"{rf"\{1}"}" diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_2.py b/crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_2.py deleted file mode 100644 index b34ad587c46d5..0000000000000 --- a/crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_2.py +++ /dev/null @@ -1,54 +0,0 @@ -# Same as `W605_0.py` but using f-strings instead. - -#: W605:1:10 -regex = f'\.png$' - -#: W605:2:1 -regex = f''' -\.png$ -''' - -#: W605:2:6 -f( - f'\_' -) - -#: W605:4:6 -f""" -multi-line -literal -with \_ somewhere -in the middle -""" - -#: W605:1:38 -value = f'new line\nand invalid escape \_ here' - - -#: Okay -regex = fr'\.png$' -regex = f'\\.png$' -regex = fr''' -\.png$ -''' -regex = fr''' -\\.png$ -''' -s = f'\\' -regex = f'\w' # noqa -regex = f''' -\w -''' # noqa - -regex = f'\\\_' -value = f'\{{1}}' -value = f'\{1}' -value = f'{1:\}' -value = f"{f"\{1}"}" -value = rf"{f"\{1}"}" - -# Okay -value = rf'\{{1}}' -value = rf'\{1}' -value = rf'{1:\}' -value = f"{rf"\{1}"}" diff --git a/crates/ruff_linter/src/rules/pycodestyle/mod.rs b/crates/ruff_linter/src/rules/pycodestyle/mod.rs index b2a02f5e23c55..3f6aa412bf179 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/mod.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/mod.rs @@ -31,7 +31,6 @@ mod tests { #[test_case(Rule::BlankLineWithWhitespace, Path::new("W29.py"))] #[test_case(Rule::InvalidEscapeSequence, Path::new("W605_0.py"))] #[test_case(Rule::InvalidEscapeSequence, Path::new("W605_1.py"))] - #[test_case(Rule::InvalidEscapeSequence, Path::new("W605_2.py"))] #[test_case(Rule::LineTooLong, Path::new("E501.py"))] #[test_case(Rule::LineTooLong, Path::new("E501_3.py"))] #[test_case(Rule::MixedSpacesAndTabs, Path::new("E101.py"))] diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/invalid_escape_sequence.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/invalid_escape_sequence.rs index b4d100aa9d6f3..77a3d6ba621df 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/invalid_escape_sequence.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/invalid_escape_sequence.rs @@ -3,9 +3,9 @@ use memchr::memchr_iter; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_index::Indexer; -use ruff_python_parser::Tok; +use ruff_python_parser::{StringKind, Tok}; use ruff_source_file::Locator; -use ruff_text_size::{TextLen, TextRange, TextSize}; +use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; use crate::fix::edits::pad_start; @@ -58,18 +58,6 @@ impl AlwaysFixableViolation for InvalidEscapeSequence { } } -#[derive(Debug, PartialEq, Eq)] -enum FixTitle { - AddBackslash, - UseRawStringLiteral, -} - -#[derive(Debug)] -struct InvalidEscapeChar { - ch: char, - range: TextRange, -} - /// W605 pub(crate) fn invalid_escape_sequence( diagnostics: &mut Vec, @@ -195,41 +183,77 @@ pub(crate) fn invalid_escape_sequence( if contains_valid_escape_sequence { // Escape with backslash. for invalid_escape_char in &invalid_escape_chars { - let diagnostic = Diagnostic::new( + let mut diagnostic = Diagnostic::new( InvalidEscapeSequence { ch: invalid_escape_char.ch, fix_title: FixTitle::AddBackslash, }, - invalid_escape_char.range, - ) - .with_fix(Fix::safe_edit(Edit::insertion( + invalid_escape_char.range(), + ); + diagnostic.set_fix(Fix::safe_edit(Edit::insertion( r"\".to_string(), - invalid_escape_char.range.start() + TextSize::from(1), + invalid_escape_char.start() + TextSize::from(1), ))); invalid_escape_sequence.push(diagnostic); } } else { // Turn into raw string. for invalid_escape_char in &invalid_escape_chars { - let diagnostic = Diagnostic::new( + let mut diagnostic = Diagnostic::new( InvalidEscapeSequence { ch: invalid_escape_char.ch, fix_title: FixTitle::UseRawStringLiteral, }, - invalid_escape_char.range, - ) - .with_fix( - // If necessary, add a space between any leading keyword (`return`, `yield`, - // `assert`, etc.) and the string. For example, `return"foo"` is valid, but - // `returnr"foo"` is not. - Fix::safe_edit(Edit::insertion( - pad_start("r".to_string(), string_start_location, locator), - string_start_location, - )), + invalid_escape_char.range(), ); + + if matches!( + token, + Tok::String { + kind: StringKind::Unicode, + .. + } + ) { + // Replace the Unicode prefix with `r`. + diagnostic.set_fix(Fix::safe_edit(Edit::replacement( + "r".to_string(), + string_start_location, + string_start_location + TextSize::from(1), + ))); + } else { + // Insert the `r` prefix. + diagnostic.set_fix( + // If necessary, add a space between any leading keyword (`return`, `yield`, + // `assert`, etc.) and the string. For example, `return"foo"` is valid, but + // `returnr"foo"` is not. + Fix::safe_edit(Edit::insertion( + pad_start("r".to_string(), string_start_location, locator), + string_start_location, + )), + ); + } + invalid_escape_sequence.push(diagnostic); } } diagnostics.extend(invalid_escape_sequence); } + +#[derive(Debug, PartialEq, Eq)] +enum FixTitle { + AddBackslash, + UseRawStringLiteral, +} + +#[derive(Debug)] +struct InvalidEscapeChar { + ch: char, + range: TextRange, +} + +impl Ranged for InvalidEscapeChar { + fn range(&self) -> TextRange { + self.range + } +} diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W605_W605_0.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W605_W605_0.py.snap index 98da5fff80c25..e4630487b7500 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W605_W605_0.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W605_W605_0.py.snap @@ -125,6 +125,8 @@ W605_0.py:45:12: W605 [*] Invalid escape sequence: `\_` 44 | 45 | regex = '\\\_' | ^^ W605 +46 | +47 | #: W605:1:7 | = help: Add backslash to escape sequence @@ -134,5 +136,23 @@ W605_0.py:45:12: W605 [*] Invalid escape sequence: `\_` 44 44 | 45 |-regex = '\\\_' 45 |+regex = '\\\\_' +46 46 | +47 47 | #: W605:1:7 +48 48 | u'foo\ bar' + +W605_0.py:48:6: W605 [*] Invalid escape sequence: `\ ` + | +47 | #: W605:1:7 +48 | u'foo\ bar' + | ^^ W605 + | + = help: Use a raw string literal + +ℹ Safe fix +45 45 | regex = '\\\_' +46 46 | +47 47 | #: W605:1:7 +48 |-u'foo\ bar' + 48 |+r'foo\ bar' diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W605_W605_1.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W605_W605_1.py.snap index 2fee83a5fee08..c47507e0ccc88 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W605_W605_1.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W605_W605_1.py.snap @@ -1,104 +1,227 @@ --- source: crates/ruff_linter/src/rules/pycodestyle/mod.rs --- -W605_1.py:2:10: W605 [*] Invalid escape sequence: `\.` +W605_1.py:4:11: W605 [*] Invalid escape sequence: `\.` | -1 | #: W605:1:10 -2 | regex = '\.png$' - | ^^ W605 -3 | -4 | #: W605:2:1 +3 | #: W605:1:10 +4 | regex = f'\.png$' + | ^^ W605 +5 | +6 | #: W605:2:1 | = help: Use a raw string literal ℹ Safe fix -1 1 | #: W605:1:10 -2 |-regex = '\.png$' - 2 |+regex = r'\.png$' -3 3 | -4 4 | #: W605:2:1 -5 5 | regex = ''' - -W605_1.py:6:1: W605 [*] Invalid escape sequence: `\.` +1 1 | # Same as `W605_0.py` but using f-strings instead. +2 2 | +3 3 | #: W605:1:10 +4 |-regex = f'\.png$' + 4 |+regex = rf'\.png$' +5 5 | +6 6 | #: W605:2:1 +7 7 | regex = f''' + +W605_1.py:8:1: W605 [*] Invalid escape sequence: `\.` | -4 | #: W605:2:1 -5 | regex = ''' -6 | \.png$ +6 | #: W605:2:1 +7 | regex = f''' +8 | \.png$ | ^^ W605 -7 | ''' +9 | ''' | = help: Use a raw string literal ℹ Safe fix -2 2 | regex = '\.png$' -3 3 | -4 4 | #: W605:2:1 -5 |-regex = ''' - 5 |+regex = r''' -6 6 | \.png$ -7 7 | ''' -8 8 | - -W605_1.py:11:6: W605 [*] Invalid escape sequence: `\_` - | - 9 | #: W605:2:6 -10 | f( -11 | '\_' - | ^^ W605 -12 | ) +4 4 | regex = f'\.png$' +5 5 | +6 6 | #: W605:2:1 +7 |-regex = f''' + 7 |+regex = rf''' +8 8 | \.png$ +9 9 | ''' +10 10 | + +W605_1.py:13:7: W605 [*] Invalid escape sequence: `\_` + | +11 | #: W605:2:6 +12 | f( +13 | f'\_' + | ^^ W605 +14 | ) | = help: Use a raw string literal ℹ Safe fix -8 8 | -9 9 | #: W605:2:6 -10 10 | f( -11 |- '\_' - 11 |+ r'\_' -12 12 | ) -13 13 | -14 14 | #: W605:4:6 - -W605_1.py:18:6: W605 [*] Invalid escape sequence: `\_` - | -16 | multi-line -17 | literal -18 | with \_ somewhere +10 10 | +11 11 | #: W605:2:6 +12 12 | f( +13 |- f'\_' + 13 |+ rf'\_' +14 14 | ) +15 15 | +16 16 | #: W605:4:6 + +W605_1.py:20:6: W605 [*] Invalid escape sequence: `\_` + | +18 | multi-line +19 | literal +20 | with \_ somewhere | ^^ W605 -19 | in the middle -20 | """ +21 | in the middle +22 | """ | = help: Use a raw string literal ℹ Safe fix -12 12 | ) -13 13 | -14 14 | #: W605:4:6 -15 |-""" - 15 |+r""" -16 16 | multi-line -17 17 | literal -18 18 | with \_ somewhere - -W605_1.py:25:12: W605 [*] Invalid escape sequence: `\.` - | -23 | def f(): -24 | #: W605:1:11 -25 | return'\.png$' - | ^^ W605 -26 | -27 | #: Okay +14 14 | ) +15 15 | +16 16 | #: W605:4:6 +17 |-f""" + 17 |+rf""" +18 18 | multi-line +19 19 | literal +20 20 | with \_ somewhere + +W605_1.py:25:40: W605 [*] Invalid escape sequence: `\_` | - = help: Use a raw string literal +24 | #: W605:1:38 +25 | value = f'new line\nand invalid escape \_ here' + | ^^ W605 + | + = help: Add backslash to escape sequence ℹ Safe fix -22 22 | -23 23 | def f(): -24 24 | #: W605:1:11 -25 |- return'\.png$' - 25 |+ return r'\.png$' +22 22 | """ +23 23 | +24 24 | #: W605:1:38 +25 |-value = f'new line\nand invalid escape \_ here' + 25 |+value = f'new line\nand invalid escape \\_ here' 26 26 | -27 27 | #: Okay -28 28 | regex = r'\.png$' +27 27 | +28 28 | #: Okay + +W605_1.py:43:13: W605 [*] Invalid escape sequence: `\_` + | +41 | ''' # noqa +42 | +43 | regex = f'\\\_' + | ^^ W605 +44 | value = f'\{{1}}' +45 | value = f'\{1}' + | + = help: Add backslash to escape sequence + +ℹ Safe fix +40 40 | \w +41 41 | ''' # noqa +42 42 | +43 |-regex = f'\\\_' + 43 |+regex = f'\\\\_' +44 44 | value = f'\{{1}}' +45 45 | value = f'\{1}' +46 46 | value = f'{1:\}' + +W605_1.py:44:11: W605 [*] Invalid escape sequence: `\{` + | +43 | regex = f'\\\_' +44 | value = f'\{{1}}' + | ^^ W605 +45 | value = f'\{1}' +46 | value = f'{1:\}' + | + = help: Use a raw string literal + +ℹ Safe fix +41 41 | ''' # noqa +42 42 | +43 43 | regex = f'\\\_' +44 |-value = f'\{{1}}' + 44 |+value = rf'\{{1}}' +45 45 | value = f'\{1}' +46 46 | value = f'{1:\}' +47 47 | value = f"{f"\{1}"}" + +W605_1.py:45:11: W605 [*] Invalid escape sequence: `\{` + | +43 | regex = f'\\\_' +44 | value = f'\{{1}}' +45 | value = f'\{1}' + | ^^ W605 +46 | value = f'{1:\}' +47 | value = f"{f"\{1}"}" + | + = help: Use a raw string literal + +ℹ Safe fix +42 42 | +43 43 | regex = f'\\\_' +44 44 | value = f'\{{1}}' +45 |-value = f'\{1}' + 45 |+value = rf'\{1}' +46 46 | value = f'{1:\}' +47 47 | value = f"{f"\{1}"}" +48 48 | value = rf"{f"\{1}"}" + +W605_1.py:46:14: W605 [*] Invalid escape sequence: `\}` + | +44 | value = f'\{{1}}' +45 | value = f'\{1}' +46 | value = f'{1:\}' + | ^^ W605 +47 | value = f"{f"\{1}"}" +48 | value = rf"{f"\{1}"}" + | + = help: Use a raw string literal + +ℹ Safe fix +43 43 | regex = f'\\\_' +44 44 | value = f'\{{1}}' +45 45 | value = f'\{1}' +46 |-value = f'{1:\}' + 46 |+value = rf'{1:\}' +47 47 | value = f"{f"\{1}"}" +48 48 | value = rf"{f"\{1}"}" +49 49 | + +W605_1.py:47:14: W605 [*] Invalid escape sequence: `\{` + | +45 | value = f'\{1}' +46 | value = f'{1:\}' +47 | value = f"{f"\{1}"}" + | ^^ W605 +48 | value = rf"{f"\{1}"}" + | + = help: Use a raw string literal + +ℹ Safe fix +44 44 | value = f'\{{1}}' +45 45 | value = f'\{1}' +46 46 | value = f'{1:\}' +47 |-value = f"{f"\{1}"}" + 47 |+value = f"{rf"\{1}"}" +48 48 | value = rf"{f"\{1}"}" +49 49 | +50 50 | # Okay + +W605_1.py:48:15: W605 [*] Invalid escape sequence: `\{` + | +46 | value = f'{1:\}' +47 | value = f"{f"\{1}"}" +48 | value = rf"{f"\{1}"}" + | ^^ W605 +49 | +50 | # Okay + | + = help: Use a raw string literal + +ℹ Safe fix +45 45 | value = f'\{1}' +46 46 | value = f'{1:\}' +47 47 | value = f"{f"\{1}"}" +48 |-value = rf"{f"\{1}"}" + 48 |+value = rf"{rf"\{1}"}" +49 49 | +50 50 | # Okay +51 51 | value = rf'\{{1}}' diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W605_W605_2.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W605_W605_2.py.snap deleted file mode 100644 index 9f1016ae835e3..0000000000000 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__W605_W605_2.py.snap +++ /dev/null @@ -1,227 +0,0 @@ ---- -source: crates/ruff_linter/src/rules/pycodestyle/mod.rs ---- -W605_2.py:4:11: W605 [*] Invalid escape sequence: `\.` - | -3 | #: W605:1:10 -4 | regex = f'\.png$' - | ^^ W605 -5 | -6 | #: W605:2:1 - | - = help: Use a raw string literal - -ℹ Safe fix -1 1 | # Same as `W605_0.py` but using f-strings instead. -2 2 | -3 3 | #: W605:1:10 -4 |-regex = f'\.png$' - 4 |+regex = rf'\.png$' -5 5 | -6 6 | #: W605:2:1 -7 7 | regex = f''' - -W605_2.py:8:1: W605 [*] Invalid escape sequence: `\.` - | -6 | #: W605:2:1 -7 | regex = f''' -8 | \.png$ - | ^^ W605 -9 | ''' - | - = help: Use a raw string literal - -ℹ Safe fix -4 4 | regex = f'\.png$' -5 5 | -6 6 | #: W605:2:1 -7 |-regex = f''' - 7 |+regex = rf''' -8 8 | \.png$ -9 9 | ''' -10 10 | - -W605_2.py:13:7: W605 [*] Invalid escape sequence: `\_` - | -11 | #: W605:2:6 -12 | f( -13 | f'\_' - | ^^ W605 -14 | ) - | - = help: Use a raw string literal - -ℹ Safe fix -10 10 | -11 11 | #: W605:2:6 -12 12 | f( -13 |- f'\_' - 13 |+ rf'\_' -14 14 | ) -15 15 | -16 16 | #: W605:4:6 - -W605_2.py:20:6: W605 [*] Invalid escape sequence: `\_` - | -18 | multi-line -19 | literal -20 | with \_ somewhere - | ^^ W605 -21 | in the middle -22 | """ - | - = help: Use a raw string literal - -ℹ Safe fix -14 14 | ) -15 15 | -16 16 | #: W605:4:6 -17 |-f""" - 17 |+rf""" -18 18 | multi-line -19 19 | literal -20 20 | with \_ somewhere - -W605_2.py:25:40: W605 [*] Invalid escape sequence: `\_` - | -24 | #: W605:1:38 -25 | value = f'new line\nand invalid escape \_ here' - | ^^ W605 - | - = help: Add backslash to escape sequence - -ℹ Safe fix -22 22 | """ -23 23 | -24 24 | #: W605:1:38 -25 |-value = f'new line\nand invalid escape \_ here' - 25 |+value = f'new line\nand invalid escape \\_ here' -26 26 | -27 27 | -28 28 | #: Okay - -W605_2.py:43:13: W605 [*] Invalid escape sequence: `\_` - | -41 | ''' # noqa -42 | -43 | regex = f'\\\_' - | ^^ W605 -44 | value = f'\{{1}}' -45 | value = f'\{1}' - | - = help: Add backslash to escape sequence - -ℹ Safe fix -40 40 | \w -41 41 | ''' # noqa -42 42 | -43 |-regex = f'\\\_' - 43 |+regex = f'\\\\_' -44 44 | value = f'\{{1}}' -45 45 | value = f'\{1}' -46 46 | value = f'{1:\}' - -W605_2.py:44:11: W605 [*] Invalid escape sequence: `\{` - | -43 | regex = f'\\\_' -44 | value = f'\{{1}}' - | ^^ W605 -45 | value = f'\{1}' -46 | value = f'{1:\}' - | - = help: Use a raw string literal - -ℹ Safe fix -41 41 | ''' # noqa -42 42 | -43 43 | regex = f'\\\_' -44 |-value = f'\{{1}}' - 44 |+value = rf'\{{1}}' -45 45 | value = f'\{1}' -46 46 | value = f'{1:\}' -47 47 | value = f"{f"\{1}"}" - -W605_2.py:45:11: W605 [*] Invalid escape sequence: `\{` - | -43 | regex = f'\\\_' -44 | value = f'\{{1}}' -45 | value = f'\{1}' - | ^^ W605 -46 | value = f'{1:\}' -47 | value = f"{f"\{1}"}" - | - = help: Use a raw string literal - -ℹ Safe fix -42 42 | -43 43 | regex = f'\\\_' -44 44 | value = f'\{{1}}' -45 |-value = f'\{1}' - 45 |+value = rf'\{1}' -46 46 | value = f'{1:\}' -47 47 | value = f"{f"\{1}"}" -48 48 | value = rf"{f"\{1}"}" - -W605_2.py:46:14: W605 [*] Invalid escape sequence: `\}` - | -44 | value = f'\{{1}}' -45 | value = f'\{1}' -46 | value = f'{1:\}' - | ^^ W605 -47 | value = f"{f"\{1}"}" -48 | value = rf"{f"\{1}"}" - | - = help: Use a raw string literal - -ℹ Safe fix -43 43 | regex = f'\\\_' -44 44 | value = f'\{{1}}' -45 45 | value = f'\{1}' -46 |-value = f'{1:\}' - 46 |+value = rf'{1:\}' -47 47 | value = f"{f"\{1}"}" -48 48 | value = rf"{f"\{1}"}" -49 49 | - -W605_2.py:47:14: W605 [*] Invalid escape sequence: `\{` - | -45 | value = f'\{1}' -46 | value = f'{1:\}' -47 | value = f"{f"\{1}"}" - | ^^ W605 -48 | value = rf"{f"\{1}"}" - | - = help: Use a raw string literal - -ℹ Safe fix -44 44 | value = f'\{{1}}' -45 45 | value = f'\{1}' -46 46 | value = f'{1:\}' -47 |-value = f"{f"\{1}"}" - 47 |+value = f"{rf"\{1}"}" -48 48 | value = rf"{f"\{1}"}" -49 49 | -50 50 | # Okay - -W605_2.py:48:15: W605 [*] Invalid escape sequence: `\{` - | -46 | value = f'{1:\}' -47 | value = f"{f"\{1}"}" -48 | value = rf"{f"\{1}"}" - | ^^ W605 -49 | -50 | # Okay - | - = help: Use a raw string literal - -ℹ Safe fix -45 45 | value = f'\{1}' -46 46 | value = f'{1:\}' -47 47 | value = f"{f"\{1}"}" -48 |-value = rf"{f"\{1}"}" - 48 |+value = rf"{rf"\{1}"}" -49 49 | -50 50 | # Okay -51 51 | value = rf'\{{1}}' - - From 17c88176952ddb390c3a9d860704092d135ab00e Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sun, 3 Dec 2023 11:01:58 -0500 Subject: [PATCH 096/197] Avoid off-by-one error in stripping noqa following multi-byte char (#8979) Closes https://github.com/astral-sh/ruff/issues/8976. --- .../resources/test/fixtures/ruff/RUF100_3.py | 3 ++ crates/ruff_linter/src/checkers/noqa.rs | 14 ++---- ..._linter__rules__ruff__tests__ruf100_3.snap | 50 +++++++++++++++++++ 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF100_3.py b/crates/ruff_linter/resources/test/fixtures/ruff/RUF100_3.py index 64f9cd12c49a4..17e6367ad0592 100644 --- a/crates/ruff_linter/resources/test/fixtures/ruff/RUF100_3.py +++ b/crates/ruff_linter/resources/test/fixtures/ruff/RUF100_3.py @@ -23,3 +23,6 @@ print(a) # noqa: E501, F821 # comment print(a) # noqa: E501, F821 comment print(a) # noqa: E501, F821 comment + +print(a) # comment with unicode µ # noqa: E501 +print(a) # comment with unicode µ # noqa: E501, F821 diff --git a/crates/ruff_linter/src/checkers/noqa.rs b/crates/ruff_linter/src/checkers/noqa.rs index 7b4224c4e1e99..055f802ccc7c8 100644 --- a/crates/ruff_linter/src/checkers/noqa.rs +++ b/crates/ruff_linter/src/checkers/noqa.rs @@ -3,10 +3,10 @@ use std::path::Path; use itertools::Itertools; -use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; +use ruff_text_size::{Ranged, TextLen, TextRange}; use ruff_diagnostics::{Diagnostic, Edit, Fix}; -use ruff_python_trivia::CommentRanges; +use ruff_python_trivia::{CommentRanges, PythonWhitespace}; use ruff_source_file::Locator; use crate::noqa; @@ -200,17 +200,11 @@ fn delete_noqa(range: TextRange, locator: &Locator) -> Edit { // Compute the leading space. let prefix = locator.slice(TextRange::new(line_range.start(), range.start())); - let leading_space = prefix - .rfind(|c: char| !c.is_whitespace()) - .map_or(prefix.len(), |i| prefix.len() - i - 1); - let leading_space_len = TextSize::try_from(leading_space).unwrap(); + let leading_space_len = prefix.text_len() - prefix.trim_whitespace_end().text_len(); // Compute the trailing space. let suffix = locator.slice(TextRange::new(range.end(), line_range.end())); - let trailing_space = suffix - .find(|c: char| !c.is_whitespace()) - .map_or(suffix.len(), |i| i); - let trailing_space_len = TextSize::try_from(trailing_space).unwrap(); + let trailing_space_len = suffix.text_len() - suffix.trim_whitespace_start().text_len(); // Ex) `# noqa` if line_range diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__ruf100_3.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__ruf100_3.snap index 019c140aecbc9..5f38b489e2ab9 100644 --- a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__ruf100_3.snap +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__ruf100_3.snap @@ -344,6 +344,7 @@ RUF100_3.py:23:11: RUF100 [*] Unused `noqa` directive (unused: `E501`) 23 |+print(a) # noqa: F821 # comment 24 24 | print(a) # noqa: E501, F821 comment 25 25 | print(a) # noqa: E501, F821 comment +26 26 | RUF100_3.py:24:11: RUF100 [*] Unused `noqa` directive (unused: `E501`) | @@ -362,6 +363,8 @@ RUF100_3.py:24:11: RUF100 [*] Unused `noqa` directive (unused: `E501`) 24 |-print(a) # noqa: E501, F821 comment 24 |+print(a) # noqa: F821 comment 25 25 | print(a) # noqa: E501, F821 comment +26 26 | +27 27 | print(a) # comment with unicode µ # noqa: E501 RUF100_3.py:25:11: RUF100 [*] Unused `noqa` directive (unused: `E501`) | @@ -369,6 +372,8 @@ RUF100_3.py:25:11: RUF100 [*] Unused `noqa` directive (unused: `E501`) 24 | print(a) # noqa: E501, F821 comment 25 | print(a) # noqa: E501, F821 comment | ^^^^^^^^^^^^^^^^^^ RUF100 +26 | +27 | print(a) # comment with unicode µ # noqa: E501 | = help: Remove unused `noqa` directive @@ -378,5 +383,50 @@ RUF100_3.py:25:11: RUF100 [*] Unused `noqa` directive (unused: `E501`) 24 24 | print(a) # noqa: E501, F821 comment 25 |-print(a) # noqa: E501, F821 comment 25 |+print(a) # noqa: F821 comment +26 26 | +27 27 | print(a) # comment with unicode µ # noqa: E501 +28 28 | print(a) # comment with unicode µ # noqa: E501, F821 + +RUF100_3.py:27:7: F821 Undefined name `a` + | +25 | print(a) # noqa: E501, F821 comment +26 | +27 | print(a) # comment with unicode µ # noqa: E501 + | ^ F821 +28 | print(a) # comment with unicode µ # noqa: E501, F821 + | + +RUF100_3.py:27:39: RUF100 [*] Unused `noqa` directive (unused: `E501`) + | +25 | print(a) # noqa: E501, F821 comment +26 | +27 | print(a) # comment with unicode µ # noqa: E501 + | ^^^^^^^^^^^^ RUF100 +28 | print(a) # comment with unicode µ # noqa: E501, F821 + | + = help: Remove unused `noqa` directive + +ℹ Safe fix +24 24 | print(a) # noqa: E501, F821 comment +25 25 | print(a) # noqa: E501, F821 comment +26 26 | +27 |-print(a) # comment with unicode µ # noqa: E501 + 27 |+print(a) # comment with unicode µ +28 28 | print(a) # comment with unicode µ # noqa: E501, F821 + +RUF100_3.py:28:39: RUF100 [*] Unused `noqa` directive (unused: `E501`) + | +27 | print(a) # comment with unicode µ # noqa: E501 +28 | print(a) # comment with unicode µ # noqa: E501, F821 + | ^^^^^^^^^^^^^^^^^^ RUF100 + | + = help: Remove unused `noqa` directive + +ℹ Safe fix +25 25 | print(a) # noqa: E501, F821 comment +26 26 | +27 27 | print(a) # comment with unicode µ # noqa: E501 +28 |-print(a) # comment with unicode µ # noqa: E501, F821 + 28 |+print(a) # comment with unicode µ # noqa: F821 From b358cbf398b85cbb8cfcf7c49749cd291b62f421 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sun, 3 Dec 2023 15:19:43 -0500 Subject: [PATCH 097/197] Fix start >= end error in over-indentation (#8982) Closes https://github.com/astral-sh/ruff/issues/8977. --- .../test/fixtures/pydocstyle/D208.py | 5 + .../src/rules/pydocstyle/rules/indent.rs | 3 +- ...ules__pydocstyle__tests__D208_D208.py.snap | 102 ++++++++++-------- 3 files changed, 67 insertions(+), 43 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D208.py b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D208.py index f0515248abb5c..27cc67d056c30 100644 --- a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D208.py +++ b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D208.py @@ -1,3 +1,8 @@ +""" + Author +""" + + class Platform: """ Remove sampler Args: diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs index f56bc1bed47b2..c7220cb0b6181 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs @@ -251,7 +251,8 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { let mut diagnostic = Diagnostic::new(OverIndentation, TextRange::empty(line.start())); let edit = if indent.is_empty() { - Edit::deletion(line.start(), line_indent.text_len()) + // Delete the entire indent. + Edit::range_deletion(TextRange::at(line.start(), line_indent.text_len())) } else { // Convert the character count to an offset within the source. let offset = checker diff --git a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap index ca8b68bcbeee5..944cbb9d520b0 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap +++ b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap @@ -1,57 +1,75 @@ --- source: crates/ruff_linter/src/rules/pydocstyle/mod.rs --- -D208.py:3:1: D208 [*] Docstring is over-indented +D208.py:2:1: D208 [*] Docstring is over-indented | -1 | class Platform: -2 | """ Remove sampler -3 | Args: +1 | """ +2 | Author | D208 -4 |     Returns: -5 | """ +3 | """ | = help: Remove over-indentation ℹ Safe fix -1 1 | class Platform: -2 2 | """ Remove sampler -3 |- Args: - 3 |+ Args: -4 4 |     Returns: -5 5 | """ - -D208.py:4:1: D208 [*] Docstring is over-indented - | -2 | """ Remove sampler -3 | Args: -4 |     Returns: - | D208 -5 | """ - | - = help: Remove over-indentation +1 1 | """ +2 |- Author + 2 |+Author +3 3 | """ +4 4 | +5 5 | + +D208.py:8:1: D208 [*] Docstring is over-indented + | + 6 | class Platform: + 7 | """ Remove sampler + 8 | Args: + | D208 + 9 |     Returns: +10 | """ + | + = help: Remove over-indentation ℹ Safe fix -1 1 | class Platform: -2 2 | """ Remove sampler -3 3 | Args: -4 |-     Returns: - 4 |+ Returns: -5 5 | """ - -D208.py:5:1: D208 [*] Docstring is over-indented - | -3 | Args: -4 |     Returns: -5 | """ - | D208 - | - = help: Remove over-indentation +5 5 | +6 6 | class Platform: +7 7 | """ Remove sampler +8 |- Args: + 8 |+ Args: +9 9 |     Returns: +10 10 | """ + +D208.py:9:1: D208 [*] Docstring is over-indented + | + 7 | """ Remove sampler + 8 | Args: + 9 |     Returns: + | D208 +10 | """ + | + = help: Remove over-indentation + +ℹ Safe fix +6 6 | class Platform: +7 7 | """ Remove sampler +8 8 | Args: +9 |-     Returns: + 9 |+ Returns: +10 10 | """ + +D208.py:10:1: D208 [*] Docstring is over-indented + | + 8 | Args: + 9 |     Returns: +10 | """ + | D208 + | + = help: Remove over-indentation ℹ Safe fix -2 2 | """ Remove sampler -3 3 | Args: -4 4 |     Returns: -5 |- """ - 5 |+ """ +7 7 | """ Remove sampler +8 8 | Args: +9 9 |     Returns: +10 |- """ + 10 |+ """ From bfae1f1412d60fec43c3b0b7123d64e5505c82f8 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sun, 3 Dec 2023 15:45:30 -0500 Subject: [PATCH 098/197] Convert over-indentation rule to use number of characters (#8983) Closes https://github.com/astral-sh/ruff/issues/8978. --- .../test/fixtures/pydocstyle/D208.py | 6 ++++ .../src/rules/pydocstyle/rules/indent.rs | 28 +++++++++---------- ...ules__pydocstyle__tests__D208_D208.py.snap | 6 ++++ 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D208.py b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D208.py index 27cc67d056c30..4e99cf4b7fdf5 100644 --- a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D208.py +++ b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D208.py @@ -8,3 +8,9 @@ class Platform: Args:     Returns: """ + + +def memory_test(): + """ +   参数含义:precision:精确到小数点后几位 + """ diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs index c7220cb0b6181..1c2ced8bd1b0d 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs @@ -172,8 +172,9 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { let mut has_seen_tab = docstring.indentation.contains('\t'); let mut is_over_indented = true; let mut over_indented_lines = vec![]; - let mut over_indented_offset = usize::MAX; + let mut over_indented_size = usize::MAX; + let docstring_indent_size = docstring.indentation.chars().count(); for i in 0..lines.len() { // First lines and continuations doesn't need any indentation. if i == 0 || lines[i - 1].ends_with('\\') { @@ -189,6 +190,7 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { } let line_indent = leading_space(line); + let line_indent_size = line_indent.chars().count(); // We only report tab indentation once, so only check if we haven't seen a tab // yet. @@ -197,9 +199,7 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { if checker.enabled(Rule::UnderIndentation) { // We report under-indentation on every line. This isn't great, but enables // fix. - if (i == lines.len() - 1 || !is_blank) - && line_indent.len() < docstring.indentation.len() - { + if (i == lines.len() - 1 || !is_blank) && line_indent_size < docstring_indent_size { let mut diagnostic = Diagnostic::new(UnderIndentation, TextRange::empty(line.start())); diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( @@ -217,14 +217,12 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { // until we've viewed all the lines, so for now, just track // the over-indentation status of every line. if i < lines.len() - 1 { - if line_indent.len() > docstring.indentation.len() { + if line_indent_size > docstring_indent_size { over_indented_lines.push(line); // Track the _smallest_ offset we see, in terms of characters. - over_indented_offset = std::cmp::min( - line_indent.chars().count() - docstring.indentation.chars().count(), - over_indented_offset, - ); + over_indented_size = + std::cmp::min(line_indent_size - docstring_indent_size, over_indented_size); } else { is_over_indented = false; } @@ -250,6 +248,7 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { // enables the fix capability. let mut diagnostic = Diagnostic::new(OverIndentation, TextRange::empty(line.start())); + let edit = if indent.is_empty() { // Delete the entire indent. Edit::range_deletion(TextRange::at(line.start(), line_indent.text_len())) @@ -259,13 +258,11 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { .locator() .after(line.start() + indent.text_len()) .chars() - .take(over_indented_offset) + .take(over_indented_size) .map(TextLen::text_len) .sum::(); - Edit::range_replacement( - indent.clone(), - TextRange::at(line.start(), indent.text_len() + offset), - ) + let range = TextRange::at(line.start(), indent.text_len() + offset); + Edit::range_replacement(indent, range) }; diagnostic.set_fix(Fix::safe_edit(edit)); checker.diagnostics.push(diagnostic); @@ -275,7 +272,8 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { // If the last line is over-indented... if let Some(last) = lines.last() { let line_indent = leading_space(last); - if line_indent.len() > docstring.indentation.len() { + let line_indent_size = line_indent.chars().count(); + if line_indent_size > docstring_indent_size { let mut diagnostic = Diagnostic::new(OverIndentation, TextRange::empty(last.start())); let indent = clean_space(docstring.indentation); diff --git a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap index 944cbb9d520b0..517dc3802e1ec 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap +++ b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D208.py.snap @@ -37,6 +37,7 @@ D208.py:8:1: D208 [*] Docstring is over-indented 8 |+ Args: 9 9 |     Returns: 10 10 | """ +11 11 | D208.py:9:1: D208 [*] Docstring is over-indented | @@ -55,6 +56,8 @@ D208.py:9:1: D208 [*] Docstring is over-indented 9 |-     Returns: 9 |+ Returns: 10 10 | """ +11 11 | +12 12 | D208.py:10:1: D208 [*] Docstring is over-indented | @@ -71,5 +74,8 @@ D208.py:10:1: D208 [*] Docstring is over-indented 9 9 |     Returns: 10 |- """ 10 |+ """ +11 11 | +12 12 | +13 13 | def memory_test(): From 6fe8f8a272e7b550b1bd02ce357eaa84ba18dcd7 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sun, 3 Dec 2023 19:15:40 -0500 Subject: [PATCH 099/197] Avoid unstable formatting in ellipsis-only body with trailing comment (#8984) ## Summary We should avoid inlining the ellipsis in: ```python def h(): ... # bye ``` Just as we omit the ellipsis in: ```python def h(): # bye ... ``` Closes https://github.com/astral-sh/ruff/issues/8905. --- .../test/fixtures/ruff/statement/ellipsis.pyi | 6 +++++- crates/ruff_python_formatter/src/statement/suite.rs | 4 +++- .../snapshots/format@statement__ellipsis.pyi.snap | 11 ++++++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/ellipsis.pyi b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/ellipsis.pyi index 499ef0aacc0c7..aa693c3443edd 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/ellipsis.pyi +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/ellipsis.pyi @@ -68,6 +68,10 @@ with True: with True: ... # comment +with True: + ... + # comment + match x: case 1: ... @@ -99,4 +103,4 @@ try: except: ... # comment finally: - ... # comment \ No newline at end of file + ... # comment diff --git a/crates/ruff_python_formatter/src/statement/suite.rs b/crates/ruff_python_formatter/src/statement/suite.rs index d8001cebe3c43..b60474dbd0043 100644 --- a/crates/ruff_python_formatter/src/statement/suite.rs +++ b/crates/ruff_python_formatter/src/statement/suite.rs @@ -511,7 +511,9 @@ pub(crate) fn contains_only_an_ellipsis(body: &[Stmt], comments: &Comments) -> b let [node] = body else { return false; }; - value.is_ellipsis_literal_expr() && !comments.has_leading(node) + value.is_ellipsis_literal_expr() + && !comments.has_leading(node) + && !comments.has_trailing_own_line(node) } _ => false, } diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__ellipsis.pyi.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__ellipsis.pyi.snap index 756fbff9f8e34..89bab19aef384 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__ellipsis.pyi.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__ellipsis.pyi.snap @@ -74,6 +74,10 @@ with True: with True: ... # comment +with True: + ... + # comment + match x: case 1: ... @@ -105,7 +109,8 @@ try: except: ... # comment finally: - ... # comment``` + ... # comment +``` ## Output ```python @@ -163,6 +168,10 @@ with True: with True: ... # comment +with True: + ... + # comment + match x: case 1: ... case 2: From 8088c5367a1d7e9abf584740981eec5bb714dbf0 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Mon, 4 Dec 2023 14:12:12 +0900 Subject: [PATCH 100/197] Refactor the comment handling of a statement's last expression (#8920) --- .../src/expression/mod.rs | 142 +----------- .../src/statement/stmt_ann_assign.rs | 6 +- .../src/statement/stmt_assign.rs | 202 +++++++++++++++++- .../src/statement/stmt_aug_assign.rs | 6 +- .../src/statement/stmt_return.rs | 8 +- 5 files changed, 203 insertions(+), 161 deletions(-) diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index b9dc9e8520a04..06cbe3bc2cebd 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -12,9 +12,7 @@ use ruff_python_trivia::CommentRanges; use ruff_text_size::Ranged; use crate::builders::parenthesize_if_expands; -use crate::comments::{ - leading_comments, trailing_comments, LeadingDanglingTrailingComments, SourceComment, -}; +use crate::comments::{leading_comments, trailing_comments, LeadingDanglingTrailingComments}; use crate::context::{NodeLevel, WithNodeLevel}; use crate::expression::expr_generator_exp::is_generator_parenthesized; use crate::expression::expr_tuple::is_tuple_parenthesized; @@ -434,106 +432,16 @@ impl Format> for MaybeParenthesizeExpression<'_> { } Parenthesize::IfBreaks => { - // Is the expression the last token in the parent statement. - // Excludes `await` and `yield` for which Black doesn't seem to apply the layout? - let last_expression = parent.is_stmt_assign() - || parent.is_stmt_ann_assign() - || parent.is_stmt_aug_assign() - || parent.is_stmt_return(); - - // Format the statements and value's trailing end of line comments: - // * after the expression if the expression needs no parentheses (necessary or the `expand_parent` makes the group never fit). - // * inside the parentheses if the expression exceeds the line-width. - // - // ```python - // a = long # with_comment - // b = ( - // short # with_comment - // ) - // - // # formatted - // a = ( - // long # with comment - // ) - // b = short # with comment - // ``` - // This matches Black's formatting with the exception that ruff applies this style also for - // attribute chains and non-fluent call expressions. See https://github.com/psf/black/issues/4001#issuecomment-1786681792 - // - // This logic isn't implemented in [`place_comment`] by associating trailing statement comments to the expression because - // doing so breaks the suite empty lines formatting that relies on trailing comments to be stored on the statement. - let (inline_comments, expression_trailing_comments) = if last_expression - && !( - // Ignore non-fluent attribute chains for black compatibility. - // See https://github.com/psf/black/issues/4001#issuecomment-1786681792 - expression.is_attribute_expr() - || expression.is_call_expr() - || expression.is_yield_from_expr() - || expression.is_yield_expr() - || expression.is_await_expr() - ) { - let parent_trailing_comments = comments.trailing(*parent); - let after_end_of_line = parent_trailing_comments - .partition_point(|comment| comment.line_position().is_end_of_line()); - let (stmt_inline_comments, _) = - parent_trailing_comments.split_at(after_end_of_line); - - let after_end_of_line = node_comments - .trailing - .partition_point(|comment| comment.line_position().is_end_of_line()); - - let (expression_inline_comments, expression_trailing_comments) = - node_comments.trailing.split_at(after_end_of_line); - - ( - OptionalParenthesesInlinedComments { - expression: expression_inline_comments, - statement: stmt_inline_comments, - }, - expression_trailing_comments, - ) + if node_comments.has_trailing() { + expression.format().with_options(Parentheses::Always).fmt(f) } else { - ( - OptionalParenthesesInlinedComments::default(), - node_comments.trailing, - ) - }; - - if expression_trailing_comments.is_empty() { // The group id is necessary because the nested expressions may reference it. let group_id = f.group_id("optional_parentheses"); let f = &mut WithNodeLevel::new(NodeLevel::Expression(Some(group_id)), f); - best_fit_parenthesize(&format_with(|f| { - inline_comments.mark_formatted(); - - expression - .format() - .with_options(Parentheses::Never) - .fmt(f)?; - - if !inline_comments.is_empty() { - // If the expressions exceeds the line width, format the comments in the parentheses - if_group_breaks(&inline_comments) - .with_group_id(Some(group_id)) - .fmt(f)?; - } - - Ok(()) - })) - .with_group_id(Some(group_id)) - .fmt(f)?; - - if !inline_comments.is_empty() { - // If the line fits into the line width, format the comments after the parenthesized expression - if_group_fits_on_line(&inline_comments) - .with_group_id(Some(group_id)) - .fmt(f)?; - } - - Ok(()) - } else { - expression.format().with_options(Parentheses::Always).fmt(f) + best_fit_parenthesize(&expression.format().with_options(Parentheses::Never)) + .with_group_id(Some(group_id)) + .fmt(f) } } }, @@ -1248,41 +1156,3 @@ impl From for OperatorPrecedence { } } } - -#[derive(Debug, Default)] -struct OptionalParenthesesInlinedComments<'a> { - expression: &'a [SourceComment], - statement: &'a [SourceComment], -} - -impl<'a> OptionalParenthesesInlinedComments<'a> { - fn is_empty(&self) -> bool { - self.expression.is_empty() && self.statement.is_empty() - } - - fn iter_comments(&self) -> impl Iterator { - self.expression.iter().chain(self.statement) - } - - fn mark_formatted(&self) { - for comment in self.iter_comments() { - comment.mark_formatted(); - } - } -} - -impl Format> for OptionalParenthesesInlinedComments<'_> { - fn fmt(&self, f: &mut Formatter>) -> FormatResult<()> { - for comment in self.iter_comments() { - comment.mark_unformatted(); - } - - write!( - f, - [ - trailing_comments(self.expression), - trailing_comments(self.statement) - ] - ) - } -} diff --git a/crates/ruff_python_formatter/src/statement/stmt_ann_assign.rs b/crates/ruff_python_formatter/src/statement/stmt_ann_assign.rs index cb5f5fa745278..17efcab1a8f77 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_ann_assign.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_ann_assign.rs @@ -2,10 +2,8 @@ use ruff_formatter::write; use ruff_python_ast::StmtAnnAssign; use crate::comments::{SourceComment, SuppressionKind}; - -use crate::expression::maybe_parenthesize_expression; -use crate::expression::parentheses::Parenthesize; use crate::prelude::*; +use crate::statement::stmt_assign::FormatStatementsLastExpression; use crate::statement::trailing_semicolon; #[derive(Default)] @@ -33,7 +31,7 @@ impl FormatNodeRule for FormatStmtAnnAssign { space(), token("="), space(), - maybe_parenthesize_expression(value, item, Parenthesize::IfBreaks) + FormatStatementsLastExpression::new(value, item) ] )?; } diff --git a/crates/ruff_python_formatter/src/statement/stmt_assign.rs b/crates/ruff_python_formatter/src/statement/stmt_assign.rs index 7a8a5fd2be005..5044e450bbee0 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_assign.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_assign.rs @@ -1,9 +1,11 @@ use ruff_formatter::{format_args, write, FormatError}; -use ruff_python_ast::{Expr, StmtAssign}; +use ruff_python_ast::{AnyNodeRef, Expr, StmtAssign}; -use crate::comments::{SourceComment, SuppressionKind}; +use crate::comments::{trailing_comments, SourceComment, SuppressionKind}; use crate::context::{NodeLevel, WithNodeLevel}; -use crate::expression::parentheses::{Parentheses, Parenthesize}; +use crate::expression::parentheses::{ + NeedsParentheses, OptionalParentheses, Parentheses, Parenthesize, +}; use crate::expression::{has_own_parentheses, maybe_parenthesize_expression}; use crate::prelude::*; use crate::statement::trailing_semicolon; @@ -34,14 +36,7 @@ impl FormatNodeRule for FormatStmtAssign { ] )?; - write!( - f, - [maybe_parenthesize_expression( - value, - item, - Parenthesize::IfBreaks - )] - )?; + FormatStatementsLastExpression::new(value, item).fmt(f)?; if f.options().source_type().is_ipynb() && f.context().node_level().is_last_top_level_statement() @@ -133,3 +128,188 @@ enum ParenthesizeTarget { Never, IfBreaks, } + +/// Formats the last expression in statements that start with a keyword (like `return`) or after an operator (assignments). +/// +/// It avoids parenthesizing unsplittable values (like `None`, `True`, `False`, Names, a subset of strings) just to make +/// the trailing comment fit and inlines a trailing comment if the value itself exceeds the configured line width: +/// +/// The implementation formats the statement's and value's trailing end of line comments: +/// * after the expression if the expression needs no parentheses (necessary or the `expand_parent` makes the group never fit). +/// * inside the parentheses if the expression exceeds the line-width. +/// +/// ```python +/// a = loooooooooooooooooooooooooooong # with_comment +/// b = ( +/// short # with_comment +/// ) +/// ``` +/// +/// Which gets formatted to: +/// +/// ```python +/// # formatted +/// a = ( +/// loooooooooooooooooooooooooooong # with comment +/// ) +/// b = short # with comment +/// ``` +/// +/// The long name gets parenthesized because it exceeds the configured line width and the trailing comma of the +/// statement gets formatted inside (instead of outside) the parentheses. +/// +/// The `short` name gets unparenthesized because it fits into the configured line length, regardless of whether +/// the comment exceeds the line width or not. +/// +/// This logic isn't implemented in [`place_comment`] by associating trailing statement comments to the expression because +/// doing so breaks the suite empty lines formatting that relies on trailing comments to be stored on the statement. +pub(super) struct FormatStatementsLastExpression<'a> { + expression: &'a Expr, + parent: AnyNodeRef<'a>, +} + +impl<'a> FormatStatementsLastExpression<'a> { + pub(super) fn new>>(expression: &'a Expr, parent: P) -> Self { + Self { + expression, + parent: parent.into(), + } + } +} + +impl Format> for FormatStatementsLastExpression<'_> { + fn fmt(&self, f: &mut Formatter>) -> FormatResult<()> { + let can_inline_comment = match self.expression { + Expr::Name(_) + | Expr::NoneLiteral(_) + | Expr::NumberLiteral(_) + | Expr::BooleanLiteral(_) => true, + Expr::StringLiteral(string) => { + string.needs_parentheses(self.parent, f.context()) == OptionalParentheses::BestFit + } + Expr::BytesLiteral(bytes) => { + bytes.needs_parentheses(self.parent, f.context()) == OptionalParentheses::BestFit + } + Expr::FString(fstring) => { + fstring.needs_parentheses(self.parent, f.context()) == OptionalParentheses::BestFit + } + _ => false, + }; + + if !can_inline_comment { + return maybe_parenthesize_expression( + self.expression, + self.parent, + Parenthesize::IfBreaks, + ) + .fmt(f); + } + + let comments = f.context().comments().clone(); + let expression_comments = comments.leading_dangling_trailing(self.expression); + + if expression_comments.has_leading() { + // Preserve the parentheses if the expression has any leading comments, + // same as `maybe_parenthesize_expression` + return self + .expression + .format() + .with_options(Parentheses::Always) + .fmt(f); + } + + let statement_trailing_comments = comments.trailing(self.parent); + let after_end_of_line = statement_trailing_comments + .partition_point(|comment| comment.line_position().is_end_of_line()); + let (stmt_inline_comments, _) = statement_trailing_comments.split_at(after_end_of_line); + + let after_end_of_line = expression_comments + .trailing + .partition_point(|comment| comment.line_position().is_end_of_line()); + + let (expression_inline_comments, expression_trailing_comments) = + expression_comments.trailing.split_at(after_end_of_line); + + if expression_trailing_comments.is_empty() { + let inline_comments = OptionalParenthesesInlinedComments { + expression: expression_inline_comments, + statement: stmt_inline_comments, + }; + + let group_id = f.group_id("optional_parentheses"); + let f = &mut WithNodeLevel::new(NodeLevel::Expression(Some(group_id)), f); + + best_fit_parenthesize(&format_with(|f| { + inline_comments.mark_formatted(); + + self.expression + .format() + .with_options(Parentheses::Never) + .fmt(f)?; + + if !inline_comments.is_empty() { + // If the expressions exceeds the line width, format the comments in the parentheses + if_group_breaks(&inline_comments) + .with_group_id(Some(group_id)) + .fmt(f)?; + } + + Ok(()) + })) + .with_group_id(Some(group_id)) + .fmt(f)?; + + if !inline_comments.is_empty() { + // If the line fits into the line width, format the comments after the parenthesized expression + if_group_fits_on_line(&inline_comments) + .with_group_id(Some(group_id)) + .fmt(f)?; + } + + Ok(()) + } else { + self.expression + .format() + .with_options(Parentheses::Always) + .fmt(f) + } + } +} + +#[derive(Debug, Default)] +struct OptionalParenthesesInlinedComments<'a> { + expression: &'a [SourceComment], + statement: &'a [SourceComment], +} + +impl<'a> OptionalParenthesesInlinedComments<'a> { + fn is_empty(&self) -> bool { + self.expression.is_empty() && self.statement.is_empty() + } + + fn iter_comments(&self) -> impl Iterator { + self.expression.iter().chain(self.statement) + } + + fn mark_formatted(&self) { + for comment in self.expression { + comment.mark_formatted(); + } + } +} + +impl Format> for OptionalParenthesesInlinedComments<'_> { + fn fmt(&self, f: &mut Formatter>) -> FormatResult<()> { + for comment in self.iter_comments() { + comment.mark_unformatted(); + } + + write!( + f, + [ + trailing_comments(self.expression), + trailing_comments(self.statement) + ] + ) + } +} diff --git a/crates/ruff_python_formatter/src/statement/stmt_aug_assign.rs b/crates/ruff_python_formatter/src/statement/stmt_aug_assign.rs index 65260c5fecdc9..19202ecf0f982 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_aug_assign.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_aug_assign.rs @@ -2,10 +2,8 @@ use ruff_formatter::write; use ruff_python_ast::StmtAugAssign; use crate::comments::{SourceComment, SuppressionKind}; - -use crate::expression::maybe_parenthesize_expression; -use crate::expression::parentheses::Parenthesize; use crate::prelude::*; +use crate::statement::stmt_assign::FormatStatementsLastExpression; use crate::statement::trailing_semicolon; use crate::{AsFormat, FormatNodeRule}; @@ -28,7 +26,7 @@ impl FormatNodeRule for FormatStmtAugAssign { op.format(), token("="), space(), - maybe_parenthesize_expression(value, item, Parenthesize::IfBreaks) + FormatStatementsLastExpression::new(value, item) ] )?; diff --git a/crates/ruff_python_formatter/src/statement/stmt_return.rs b/crates/ruff_python_formatter/src/statement/stmt_return.rs index be63db2e73f2b..b0c5253e0fa38 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_return.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_return.rs @@ -3,9 +3,8 @@ use ruff_python_ast::{Expr, StmtReturn}; use crate::comments::{SourceComment, SuppressionKind}; use crate::expression::expr_tuple::TupleParentheses; -use crate::expression::maybe_parenthesize_expression; -use crate::expression::parentheses::Parenthesize; use crate::prelude::*; +use crate::statement::stmt_assign::FormatStatementsLastExpression; #[derive(Default)] pub struct FormatStmtReturn; @@ -31,10 +30,7 @@ impl FormatNodeRule for FormatStmtReturn { Some(value) => { write!( f, - [ - space(), - maybe_parenthesize_expression(value, item, Parenthesize::IfBreaks) - ] + [space(), FormatStatementsLastExpression::new(value, item)] ) } None => Ok(()), From 0bf0aa28ac05eb4157c8e1932abc91301aaedce7 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Mon, 4 Dec 2023 14:27:04 +0900 Subject: [PATCH 101/197] Inline trailing comments for type alias similar to assignments (#8941) --- .../resources/test/fixtures/ruff/statement/type_alias.py | 2 ++ .../src/statement/stmt_type_alias.rs | 5 ++--- .../tests/snapshots/format@statement__type_alias.py.snap | 8 ++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/type_alias.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/type_alias.py index 8e29cd3730c9c..ad13b9d84cd6e 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/type_alias.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/type_alias.py @@ -16,10 +16,12 @@ type Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[Aaaaaaaaaaaaaaaaaaaaaaaaaaaa] = int type Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[Aaaaaaaaaaaaaaaaaaaaaaaaaaaa, Bbbbbbbbbbbbb] = int type Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = Tttttttttttttttttttttttttttttttttttttttttttttttttttttttt +type Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = Tttttttttttttttttttttttttttttttttttttttttttttttttttttttt # with comment # long value type X = Ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt type X = Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | Ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +type XXXXXXXXXXXXX = Tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt # with comment # soft keyword as alias name type type = int diff --git a/crates/ruff_python_formatter/src/statement/stmt_type_alias.rs b/crates/ruff_python_formatter/src/statement/stmt_type_alias.rs index c2daaf8528d20..6376236afb7d1 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_type_alias.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_type_alias.rs @@ -2,9 +2,8 @@ use ruff_formatter::write; use ruff_python_ast::StmtTypeAlias; use crate::comments::{SourceComment, SuppressionKind}; -use crate::expression::maybe_parenthesize_expression; -use crate::expression::parentheses::Parenthesize; use crate::prelude::*; +use crate::statement::stmt_assign::FormatStatementsLastExpression; #[derive(Default)] pub struct FormatStmtTypeAlias; @@ -30,7 +29,7 @@ impl FormatNodeRule for FormatStmtTypeAlias { space(), token("="), space(), - maybe_parenthesize_expression(value, item, Parenthesize::IfBreaks) + FormatStatementsLastExpression::new(value, item) ] ) } diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__type_alias.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__type_alias.py.snap index ccc44b8db950a..6320591b80c05 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__type_alias.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__type_alias.py.snap @@ -22,10 +22,12 @@ type Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx type Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[Aaaaaaaaaaaaaaaaaaaaaaaaaaaa] = int type Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[Aaaaaaaaaaaaaaaaaaaaaaaaaaaa, Bbbbbbbbbbbbb] = int type Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = Tttttttttttttttttttttttttttttttttttttttttttttttttttttttt +type Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = Tttttttttttttttttttttttttttttttttttttttttttttttttttttttt # with comment # long value type X = Ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt type X = Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | Ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +type XXXXXXXXXXXXX = Tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt # with comment # soft keyword as alias name type type = int @@ -127,6 +129,9 @@ type Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Bbbbbbbbbbbbb, ] = int type Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = Tttttttttttttttttttttttttttttttttttttttttttttttttttttttt +type Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = ( + Tttttttttttttttttttttttttttttttttttttttttttttttttttttttt # with comment +) # long value type X = Ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt @@ -135,6 +140,9 @@ type X = ( | Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | Ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc ) +type XXXXXXXXXXXXX = ( + Tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt # with comment +) # soft keyword as alias name type type = int From 7e390d3772a0e5007ecc0240f765611762befb14 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Mon, 4 Dec 2023 14:36:28 +0900 Subject: [PATCH 102/197] Move `ParenthesizedExpr` to `ruff_python_parser` (#8987) --- crates/ruff_python_ast/src/nodes.rs | 198 -- crates/ruff_python_parser/src/parser.rs | 219 +- crates/ruff_python_parser/src/python.lalrpop | 102 +- crates/ruff_python_parser/src/python.rs | 2964 +++++++++--------- 4 files changed, 1747 insertions(+), 1736 deletions(-) diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index eaf9881a3706c..32ddbeef59a46 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -3729,204 +3729,6 @@ impl Ranged for crate::nodes::ParameterWithDefault { } } -/// An expression that may be parenthesized. -#[derive(Clone, Debug)] -pub struct ParenthesizedExpr { - /// The range of the expression, including any parentheses. - pub range: TextRange, - /// The underlying expression. - pub expr: Expr, -} -impl ParenthesizedExpr { - /// Returns `true` if the expression is may be parenthesized. - pub fn is_parenthesized(&self) -> bool { - self.range != self.expr.range() - } -} -impl Ranged for ParenthesizedExpr { - fn range(&self) -> TextRange { - self.range - } -} -impl From for ParenthesizedExpr { - fn from(expr: Expr) -> Self { - ParenthesizedExpr { - range: expr.range(), - expr, - } - } -} -impl From for Expr { - fn from(parenthesized_expr: ParenthesizedExpr) -> Self { - parenthesized_expr.expr - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprIpyEscapeCommand) -> Self { - Expr::IpyEscapeCommand(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprBoolOp) -> Self { - Expr::BoolOp(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprNamedExpr) -> Self { - Expr::NamedExpr(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprBinOp) -> Self { - Expr::BinOp(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprUnaryOp) -> Self { - Expr::UnaryOp(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprLambda) -> Self { - Expr::Lambda(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprIfExp) -> Self { - Expr::IfExp(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprDict) -> Self { - Expr::Dict(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprSet) -> Self { - Expr::Set(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprListComp) -> Self { - Expr::ListComp(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprSetComp) -> Self { - Expr::SetComp(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprDictComp) -> Self { - Expr::DictComp(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprGeneratorExp) -> Self { - Expr::GeneratorExp(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprAwait) -> Self { - Expr::Await(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprYield) -> Self { - Expr::Yield(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprYieldFrom) -> Self { - Expr::YieldFrom(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprCompare) -> Self { - Expr::Compare(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprCall) -> Self { - Expr::Call(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprFormattedValue) -> Self { - Expr::FormattedValue(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprFString) -> Self { - Expr::FString(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprStringLiteral) -> Self { - Expr::StringLiteral(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprBytesLiteral) -> Self { - Expr::BytesLiteral(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprNumberLiteral) -> Self { - Expr::NumberLiteral(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprBooleanLiteral) -> Self { - Expr::BooleanLiteral(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprNoneLiteral) -> Self { - Expr::NoneLiteral(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprEllipsisLiteral) -> Self { - Expr::EllipsisLiteral(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprAttribute) -> Self { - Expr::Attribute(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprSubscript) -> Self { - Expr::Subscript(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprStarred) -> Self { - Expr::Starred(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprName) -> Self { - Expr::Name(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprList) -> Self { - Expr::List(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprTuple) -> Self { - Expr::Tuple(payload).into() - } -} -impl From for ParenthesizedExpr { - fn from(payload: ExprSlice) -> Self { - Expr::Slice(payload).into() - } -} - #[cfg(target_pointer_width = "64")] mod size_assertions { use static_assertions::assert_eq_size; diff --git a/crates/ruff_python_parser/src/parser.rs b/crates/ruff_python_parser/src/parser.rs index 963d3a33064eb..26603ca3dda4e 100644 --- a/crates/ruff_python_parser/src/parser.rs +++ b/crates/ruff_python_parser/src/parser.rs @@ -16,7 +16,7 @@ use std::{fmt, iter}; use itertools::Itertools; pub(super) use lalrpop_util::ParseError as LalrpopError; -use ruff_text_size::{TextRange, TextSize}; +use ruff_text_size::{Ranged, TextRange, TextSize}; use crate::lexer::{lex, lex_starts_at, Spanned}; use crate::{ @@ -25,8 +25,14 @@ use crate::{ token::Tok, Mode, }; -use ruff_python_ast as ast; -use ruff_python_ast::{Mod, ModModule, Suite}; +use ruff_python_ast::{ + Expr, ExprAttribute, ExprAwait, ExprBinOp, ExprBoolOp, ExprBooleanLiteral, ExprBytesLiteral, + ExprCall, ExprCompare, ExprDict, ExprDictComp, ExprEllipsisLiteral, ExprFString, + ExprGeneratorExp, ExprIfExp, ExprIpyEscapeCommand, ExprLambda, ExprList, ExprListComp, + ExprName, ExprNamedExpr, ExprNoneLiteral, ExprNumberLiteral, ExprSet, ExprSetComp, ExprSlice, + ExprStarred, ExprStringLiteral, ExprSubscript, ExprTuple, ExprUnaryOp, ExprYield, + ExprYieldFrom, Mod, ModModule, Suite, +}; /// Parse a full Python program usually consisting of multiple lines. /// @@ -76,7 +82,7 @@ pub fn parse_suite(source: &str, source_path: &str) -> Result /// assert!(expr.is_ok()); /// /// ``` -pub fn parse_expression(source: &str, source_path: &str) -> Result { +pub fn parse_expression(source: &str, source_path: &str) -> Result { let lexer = lex(source, Mode::Expression); match parse_tokens(lexer, source, Mode::Expression, source_path)? { Mod::Expression(expression) => Ok(*expression.body), @@ -105,7 +111,7 @@ pub fn parse_expression_starts_at( source: &str, source_path: &str, offset: TextSize, -) -> Result { +) -> Result { let lexer = lex_starts_at(source, Mode::Module, offset); match parse_tokens(lexer, source, Mode::Expression, source_path)? { Mod::Expression(expression) => Ok(*expression.body), @@ -418,6 +424,209 @@ impl ParseErrorType { } } +/// An expression that may be parenthesized. +#[derive(Clone, Debug)] +pub(super) struct ParenthesizedExpr { + /// The range of the expression, including any parentheses. + pub(super) range: TextRange, + /// The underlying expression. + pub(super) expr: Expr, +} + +impl ParenthesizedExpr { + /// Returns `true` if the expression is parenthesized. + pub(super) fn is_parenthesized(&self) -> bool { + self.range.start() != self.expr.range().start() + } +} + +impl Ranged for ParenthesizedExpr { + fn range(&self) -> TextRange { + self.range + } +} +impl From for ParenthesizedExpr { + fn from(expr: Expr) -> Self { + ParenthesizedExpr { + range: expr.range(), + expr, + } + } +} +impl From for Expr { + fn from(parenthesized_expr: ParenthesizedExpr) -> Self { + parenthesized_expr.expr + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprIpyEscapeCommand) -> Self { + Expr::IpyEscapeCommand(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprBoolOp) -> Self { + Expr::BoolOp(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprNamedExpr) -> Self { + Expr::NamedExpr(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprBinOp) -> Self { + Expr::BinOp(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprUnaryOp) -> Self { + Expr::UnaryOp(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprLambda) -> Self { + Expr::Lambda(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprIfExp) -> Self { + Expr::IfExp(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprDict) -> Self { + Expr::Dict(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprSet) -> Self { + Expr::Set(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprListComp) -> Self { + Expr::ListComp(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprSetComp) -> Self { + Expr::SetComp(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprDictComp) -> Self { + Expr::DictComp(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprGeneratorExp) -> Self { + Expr::GeneratorExp(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprAwait) -> Self { + Expr::Await(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprYield) -> Self { + Expr::Yield(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprYieldFrom) -> Self { + Expr::YieldFrom(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprCompare) -> Self { + Expr::Compare(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprCall) -> Self { + Expr::Call(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprFString) -> Self { + Expr::FString(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprStringLiteral) -> Self { + Expr::StringLiteral(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprBytesLiteral) -> Self { + Expr::BytesLiteral(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprNumberLiteral) -> Self { + Expr::NumberLiteral(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprBooleanLiteral) -> Self { + Expr::BooleanLiteral(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprNoneLiteral) -> Self { + Expr::NoneLiteral(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprEllipsisLiteral) -> Self { + Expr::EllipsisLiteral(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprAttribute) -> Self { + Expr::Attribute(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprSubscript) -> Self { + Expr::Subscript(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprStarred) -> Self { + Expr::Starred(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprName) -> Self { + Expr::Name(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprList) -> Self { + Expr::List(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprTuple) -> Self { + Expr::Tuple(payload).into() + } +} +impl From for ParenthesizedExpr { + fn from(payload: ExprSlice) -> Self { + Expr::Slice(payload).into() + } +} + +#[cfg(target_pointer_width = "64")] +mod size_assertions { + use crate::parser::ParenthesizedExpr; + use static_assertions::assert_eq_size; + + assert_eq_size!(ParenthesizedExpr, [u8; 88]); +} + #[cfg(test)] mod tests { use insta::assert_debug_snapshot; diff --git a/crates/ruff_python_parser/src/python.lalrpop b/crates/ruff_python_parser/src/python.lalrpop index 98ac90fc73e65..46eef9cf961f3 100644 --- a/crates/ruff_python_parser/src/python.lalrpop +++ b/crates/ruff_python_parser/src/python.lalrpop @@ -156,33 +156,33 @@ ExpressionStatement: ast::Stmt = { }, }; -AssignSuffix: ast::ParenthesizedExpr = { +AssignSuffix: crate::parser::ParenthesizedExpr = { "=" => e, "=" => e }; -TestListOrYieldExpr: ast::ParenthesizedExpr = { +TestListOrYieldExpr: crate::parser::ParenthesizedExpr = { TestList, YieldExpr } #[inline] -TestOrStarExprList: ast::ParenthesizedExpr = { +TestOrStarExprList: crate::parser::ParenthesizedExpr = { // as far as I can tell, these were the same TestList }; -TestOrStarExpr: ast::ParenthesizedExpr = { +TestOrStarExpr: crate::parser::ParenthesizedExpr = { Test<"all">, StarExpr, }; -NamedOrStarExpr: ast::ParenthesizedExpr = { +NamedOrStarExpr: crate::parser::ParenthesizedExpr = { NamedExpression, StarExpr, }; -TestOrStarNamedExpr: ast::ParenthesizedExpr = { +TestOrStarNamedExpr: crate::parser::ParenthesizedExpr = { NamedExpressionTest, StarExpr, }; @@ -345,7 +345,7 @@ IpyEscapeCommandStatement: ast::Stmt = { } } -IpyEscapeCommandExpr: ast::ParenthesizedExpr = { +IpyEscapeCommandExpr: crate::parser::ParenthesizedExpr = { =>? { if mode == Mode::Ipython { // This should never occur as the lexer won't allow it. @@ -630,13 +630,13 @@ StarPattern: ast::Pattern = { }.into(), } -NumberAtom: ast::ParenthesizedExpr = { +NumberAtom: crate::parser::ParenthesizedExpr = { => ast::Expr::NumberLiteral( ast::ExprNumberLiteral { value, range: (location..end_location).into() } ).into(), } -NumberExpr: ast::ParenthesizedExpr = { +NumberExpr: crate::parser::ParenthesizedExpr = { NumberAtom, "-" => ast::Expr::UnaryOp( ast::ExprUnaryOp { @@ -647,7 +647,7 @@ NumberExpr: ast::ParenthesizedExpr = { ).into(), } -AddOpExpr: ast::ParenthesizedExpr = { +AddOpExpr: crate::parser::ParenthesizedExpr = { => ast::ExprBinOp { left: Box::new(left.into()), op, @@ -1316,7 +1316,7 @@ Decorator: ast::Decorator = { }, }; -YieldExpr: ast::ParenthesizedExpr = { +YieldExpr: crate::parser::ParenthesizedExpr = { "yield" => ast::ExprYield { value: value.map(ast::Expr::from).map(Box::new), range: (location..end_location).into(), @@ -1327,7 +1327,7 @@ YieldExpr: ast::ParenthesizedExpr = { }.into(), }; -Test: ast::ParenthesizedExpr = { +Test: crate::parser::ParenthesizedExpr = { > "if" > "else" > => ast::ExprIfExp { test: Box::new(test.into()), body: Box::new(body.into()), @@ -1338,12 +1338,12 @@ Test: ast::ParenthesizedExpr = { LambdaDef, }; -NamedExpressionTest: ast::ParenthesizedExpr = { +NamedExpressionTest: crate::parser::ParenthesizedExpr = { NamedExpression, Test<"all">, } -NamedExpressionName: ast::ParenthesizedExpr = { +NamedExpressionName: crate::parser::ParenthesizedExpr = { => ast::ExprName { id: id.into(), ctx: ast::ExprContext::Store, @@ -1351,7 +1351,7 @@ NamedExpressionName: ast::ParenthesizedExpr = { }.into(), } -NamedExpression: ast::ParenthesizedExpr = { +NamedExpression: crate::parser::ParenthesizedExpr = { ":=" > => { ast::ExprNamedExpr { target: Box::new(target.into()), @@ -1361,7 +1361,7 @@ NamedExpression: ast::ParenthesizedExpr = { }, }; -LambdaDef: ast::ParenthesizedExpr = { +LambdaDef: crate::parser::ParenthesizedExpr = { "lambda" ?> ":" > =>? { if fstring_middle.is_some() { return Err(LexicalError { @@ -1379,7 +1379,7 @@ LambdaDef: ast::ParenthesizedExpr = { } } -OrTest: ast::ParenthesizedExpr = { +OrTest: crate::parser::ParenthesizedExpr = { > "or")+> > => { let values = values.into_iter().chain(std::iter::once(last)).map(ast::Expr::from).collect(); ast::ExprBoolOp { op: ast::BoolOp::Or, values, range: (location..end_location).into() }.into() @@ -1387,7 +1387,7 @@ OrTest: ast::ParenthesizedExpr = { AndTest, }; -AndTest: ast::ParenthesizedExpr = { +AndTest: crate::parser::ParenthesizedExpr = { > "and")+> > => { let values = values.into_iter().chain(std::iter::once(last)).map(ast::Expr::from).collect(); ast::ExprBoolOp { op: ast::BoolOp::And, values, range: (location..end_location).into() }.into() @@ -1395,7 +1395,7 @@ AndTest: ast::ParenthesizedExpr = { NotTest, }; -NotTest: ast::ParenthesizedExpr = { +NotTest: crate::parser::ParenthesizedExpr = { "not" > => ast::ExprUnaryOp { operand: Box::new(operand.into()), op: ast::UnaryOp::Not, @@ -1404,7 +1404,7 @@ NotTest: ast::ParenthesizedExpr = { Comparison, }; -Comparison: ast::ParenthesizedExpr = { +Comparison: crate::parser::ParenthesizedExpr = { > )+> => { let (ops, comparators) = comparisons.into_iter().map(|(op, comparator)| (op, ast::Expr::from(comparator))).unzip(); ast::ExprCompare { left: Box::new(left.into()), ops, comparators, range: (location..end_location).into() }.into() @@ -1425,7 +1425,7 @@ CompOp: ast::CmpOp = { "is" "not" => ast::CmpOp::IsNot, }; -Expression: ast::ParenthesizedExpr = { +Expression: crate::parser::ParenthesizedExpr = { > "|" > => ast::ExprBinOp { left: Box::new(left.into()), op: ast::Operator::BitOr, @@ -1435,7 +1435,7 @@ Expression: ast::ParenthesizedExpr = { XorExpression, }; -XorExpression: ast::ParenthesizedExpr = { +XorExpression: crate::parser::ParenthesizedExpr = { > "^" > => ast::ExprBinOp { left: Box::new(left.into()), op: ast::Operator::BitXor, @@ -1445,7 +1445,7 @@ XorExpression: ast::ParenthesizedExpr = { AndExpression, }; -AndExpression: ast::ParenthesizedExpr = { +AndExpression: crate::parser::ParenthesizedExpr = { > "&" > => ast::ExprBinOp { left: Box::new(left.into()), op: ast::Operator::BitAnd, @@ -1455,7 +1455,7 @@ AndExpression: ast::ParenthesizedExpr = { ShiftExpression, }; -ShiftExpression: ast::ParenthesizedExpr = { +ShiftExpression: crate::parser::ParenthesizedExpr = { > > => ast::ExprBinOp { left: Box::new(left.into()), op, @@ -1470,7 +1470,7 @@ ShiftOp: ast::Operator = { ">>" => ast::Operator::RShift, }; -ArithmeticExpression: ast::ParenthesizedExpr = { +ArithmeticExpression: crate::parser::ParenthesizedExpr = { > > => ast::ExprBinOp { left: Box::new(left.into()), op, @@ -1485,7 +1485,7 @@ AddOp: ast::Operator = { "-" => ast::Operator::Sub, }; -Term: ast::ParenthesizedExpr = { +Term: crate::parser::ParenthesizedExpr = { > > => ast::ExprBinOp { left: Box::new(left.into()), op, @@ -1503,7 +1503,7 @@ MulOp: ast::Operator = { "@" => ast::Operator::MatMult, }; -Factor: ast::ParenthesizedExpr = { +Factor: crate::parser::ParenthesizedExpr = { > => ast::ExprUnaryOp { operand: Box::new(operand.into()), op, @@ -1518,7 +1518,7 @@ UnaryOp: ast::UnaryOp = { "~" => ast::UnaryOp::Invert, }; -Power: ast::ParenthesizedExpr = { +Power: crate::parser::ParenthesizedExpr = { > "**" > => ast::ExprBinOp { left: Box::new(left.into()), op: ast::Operator::Pow, @@ -1528,14 +1528,14 @@ Power: ast::ParenthesizedExpr = { AtomExpr, }; -AtomExpr: ast::ParenthesizedExpr = { +AtomExpr: crate::parser::ParenthesizedExpr = { "await" > => { ast::ExprAwait { value: Box::new(value.into()), range: (location..end_location).into() }.into() }, AtomExpr2, } -AtomExpr2: ast::ParenthesizedExpr = { +AtomExpr2: crate::parser::ParenthesizedExpr = { Atom, > => ast::ExprCall { func: Box::new(func.into()), @@ -1556,7 +1556,7 @@ AtomExpr2: ast::ParenthesizedExpr = { }.into(), }; -SubscriptList: ast::ParenthesizedExpr = { +SubscriptList: crate::parser::ParenthesizedExpr = { Subscript, "," => { ast::ExprTuple { @@ -1575,7 +1575,7 @@ SubscriptList: ast::ParenthesizedExpr = { } }; -Subscript: ast::ParenthesizedExpr = { +Subscript: crate::parser::ParenthesizedExpr = { TestOrStarNamedExpr, ?> ":" ?> => { let lower = lower.map(ast::Expr::from).map(Box::new); @@ -1587,7 +1587,7 @@ Subscript: ast::ParenthesizedExpr = { } }; -SliceOp: Option = { +SliceOp: Option = { ":" ?> => e, } @@ -1693,7 +1693,7 @@ FStringConversion: (TextSize, ast::ConversionFlag) = { } }; -Atom: ast::ParenthesizedExpr = { +Atom: crate::parser::ParenthesizedExpr = { => expr.into(), => ast::ExprNumberLiteral { value, @@ -1713,7 +1713,7 @@ Atom: ast::ParenthesizedExpr = { }, "(" >> ")" if Goal != "no-withitems" => { if elts.len() == 1 && trailing_comma.is_none() { - ast::ParenthesizedExpr { + crate::parser::ParenthesizedExpr { expr: elts.into_iter().next().unwrap().into(), range: (location..end_location).into(), } @@ -1730,7 +1730,7 @@ Atom: ast::ParenthesizedExpr = { location: mid.start(), })?; } - Ok(ast::ParenthesizedExpr { + Ok(crate::parser::ParenthesizedExpr { expr: mid.into(), range: (location..end_location).into(), }) @@ -1744,7 +1744,7 @@ Atom: ast::ParenthesizedExpr = { ctx: ast::ExprContext::Load, range: (location..end_location).into(), }.into(), - "(" ")" => ast::ParenthesizedExpr { + "(" ")" => crate::parser::ParenthesizedExpr { expr: e.into(), range: (location..end_location).into(), }, @@ -1793,37 +1793,37 @@ Atom: ast::ParenthesizedExpr = { "..." => ast::ExprEllipsisLiteral { range: (location..end_location).into() }.into(), }; -ListLiteralValues: Vec = { +ListLiteralValues: Vec = { > ","? => e, }; -DictLiteralValues: Vec<(Option>, ast::ParenthesizedExpr)> = { +DictLiteralValues: Vec<(Option>, crate::parser::ParenthesizedExpr)> = { > ","? => elements, }; -DictEntry: (ast::ParenthesizedExpr, ast::ParenthesizedExpr) = { +DictEntry: (crate::parser::ParenthesizedExpr, crate::parser::ParenthesizedExpr) = { > ":" > => (e1, e2), }; -DictElement: (Option>, ast::ParenthesizedExpr) = { +DictElement: (Option>, crate::parser::ParenthesizedExpr) = { => (Some(Box::new(e.0)), e.1), "**" > => (None, e), }; -SetLiteralValues: Vec = { +SetLiteralValues: Vec = { > ","? => e1 }; -ExpressionOrStarExpression: ast::ParenthesizedExpr = { +ExpressionOrStarExpression: crate::parser::ParenthesizedExpr = { Expression<"all">, StarExpr }; -ExpressionList: ast::ParenthesizedExpr = { +ExpressionList: crate::parser::ParenthesizedExpr = { GenericList }; -ExpressionList2: Vec = { +ExpressionList2: Vec = { > ","? => elements, }; @@ -1832,14 +1832,14 @@ ExpressionList2: Vec = { // - a single expression // - a single expression followed by a trailing comma #[inline] -TestList: ast::ParenthesizedExpr = { +TestList: crate::parser::ParenthesizedExpr = { GenericList }; -GenericList: ast::ParenthesizedExpr = { +GenericList: crate::parser::ParenthesizedExpr = { > => { if elts.len() == 1 && trailing_comma.is_none() { - ast::ParenthesizedExpr { + crate::parser::ParenthesizedExpr { expr: elts.into_iter().next().unwrap().into(), range: (location..end_location).into(), } @@ -1851,7 +1851,7 @@ GenericList: ast::ParenthesizedExpr = { } // Test -StarExpr: ast::ParenthesizedExpr = { +StarExpr: crate::parser::ParenthesizedExpr = { "*" > => ast::ExprStarred { value: Box::new(value.into()), ctx: ast::ExprContext::Load, @@ -1876,8 +1876,8 @@ SingleForComprehension: ast::Comprehension = { } }; -ExpressionNoCond: ast::ParenthesizedExpr = OrTest<"all">; -ComprehensionIf: ast::ParenthesizedExpr = "if" => c; +ExpressionNoCond: crate::parser::ParenthesizedExpr = OrTest<"all">; +ComprehensionIf: crate::parser::ParenthesizedExpr = "if" => c; Arguments: ast::Arguments = { "(" > ")" =>? { diff --git a/crates/ruff_python_parser/src/python.rs b/crates/ruff_python_parser/src/python.rs index 3b2174bc69456..3e04daf83a8b7 100644 --- a/crates/ruff_python_parser/src/python.rs +++ b/crates/ruff_python_parser/src/python.rs @@ -1,5 +1,5 @@ // auto-generated: "lalrpop 0.20.0" -// sha3: c7c0b9368fa05f7d2fc1d06a665ff4232555f276a1d9569afdbc86d0905b3a2a +// sha3: bf21214efe22cee1db2a8fe27c1793b02afee5017a8474a3543f4d8526c1c0ec use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; use ruff_python_ast::{self as ast, Int, IpyEscapeKind}; use crate::{ @@ -62,9 +62,9 @@ mod __parse__Top { Variant12(alloc::vec::Vec), Variant13((Option>, Vec, Option>)), Variant14(core::option::Option<(Option>, Vec, Option>)>), - Variant15(ast::ParenthesizedExpr), - Variant16(core::option::Option), - Variant17(alloc::vec::Vec), + Variant15(crate::parser::ParenthesizedExpr), + Variant16(core::option::Option), + Variant17(alloc::vec::Vec), Variant18(ast::WithItem), Variant19(alloc::vec::Vec), Variant20((token::Tok, ast::Identifier)), @@ -74,23 +74,23 @@ mod __parse__Top { Variant24(core::option::Option), Variant25(ast::Suite), Variant26(core::option::Option), - Variant27((TextSize, ast::ParenthesizedExpr, ast::Suite)), - Variant28(alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)>), + Variant27((TextSize, crate::parser::ParenthesizedExpr, ast::Suite)), + Variant28(alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)>), Variant29((TextSize, ast::Suite)), Variant30(core::option::Option<(TextSize, ast::Suite)>), Variant31((Option<(TextSize, TextSize, Option)>, ast::Expr)), Variant32(alloc::vec::Vec<(Option<(TextSize, TextSize, Option)>, ast::Expr)>), - Variant33(Vec), - Variant34(core::option::Option>), + Variant33(Vec), + Variant34(core::option::Option>), Variant35(ast::Pattern), Variant36(alloc::vec::Vec), Variant37(ast::Stmt), Variant38(alloc::vec::Vec), - Variant39((ast::ParenthesizedExpr, ast::Identifier)), + Variant39((crate::parser::ParenthesizedExpr, ast::Identifier)), Variant40(Vec), Variant41(core::option::Option>), - Variant42((ast::CmpOp, ast::ParenthesizedExpr)), - Variant43(alloc::vec::Vec<(ast::CmpOp, ast::ParenthesizedExpr)>), + Variant42((ast::CmpOp, crate::parser::ParenthesizedExpr)), + Variant43(alloc::vec::Vec<(ast::CmpOp, crate::parser::ParenthesizedExpr)>), Variant44(ast::Expr), Variant45(core::option::Option), Variant46(ast::Parameters), @@ -106,10 +106,10 @@ mod __parse__Top { Variant56(ast::CmpOp), Variant57(ast::Decorator), Variant58(alloc::vec::Vec), - Variant59((Option>, ast::ParenthesizedExpr)), - Variant60((ast::ParenthesizedExpr, ast::ParenthesizedExpr)), - Variant61(Vec<(Option>, ast::ParenthesizedExpr)>), - Variant62(core::option::Option>, ast::ParenthesizedExpr)>>), + Variant59((Option>, crate::parser::ParenthesizedExpr)), + Variant60((crate::parser::ParenthesizedExpr, crate::parser::ParenthesizedExpr)), + Variant61(Vec<(Option>, crate::parser::ParenthesizedExpr)>), + Variant62(core::option::Option>, crate::parser::ParenthesizedExpr)>>), Variant63(ast::Parameter), Variant64(core::option::Option), Variant65(ast::ExceptHandler), @@ -139,8 +139,8 @@ mod __parse__Top { Variant89(ast::PatternArguments), Variant90(ast::Comprehension), Variant91(alloc::vec::Vec), - Variant92(Option), - Variant93(core::option::Option>), + Variant92(Option), + Variant93(core::option::Option>), Variant94(Vec), Variant95(ast::Mod), Variant96(Vec), @@ -18353,7 +18353,7 @@ mod __parse__Top { fn __pop_Variant59< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, (Option>, ast::ParenthesizedExpr), TextSize) + ) -> (TextSize, (Option>, crate::parser::ParenthesizedExpr), TextSize) { match __symbols.pop() { Some((__l, __Symbol::Variant59(__v), __r)) => (__l, __v, __r), @@ -18400,23 +18400,23 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant27< + fn __pop_Variant29< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, (TextSize, ast::ParenthesizedExpr, ast::Suite), TextSize) + ) -> (TextSize, (TextSize, ast::Suite), TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant27(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant29(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } - fn __pop_Variant29< + fn __pop_Variant27< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, (TextSize, ast::Suite), TextSize) + ) -> (TextSize, (TextSize, crate::parser::ParenthesizedExpr, ast::Suite), TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant29(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant27(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -18433,7 +18433,7 @@ mod __parse__Top { fn __pop_Variant42< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, (ast::CmpOp, ast::ParenthesizedExpr), TextSize) + ) -> (TextSize, (ast::CmpOp, crate::parser::ParenthesizedExpr), TextSize) { match __symbols.pop() { Some((__l, __Symbol::Variant42(__v), __r)) => (__l, __v, __r), @@ -18453,7 +18453,7 @@ mod __parse__Top { fn __pop_Variant39< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, (ast::ParenthesizedExpr, ast::Identifier), TextSize) + ) -> (TextSize, (crate::parser::ParenthesizedExpr, ast::Identifier), TextSize) { match __symbols.pop() { Some((__l, __Symbol::Variant39(__v), __r)) => (__l, __v, __r), @@ -18463,7 +18463,7 @@ mod __parse__Top { fn __pop_Variant60< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, (ast::ParenthesizedExpr, ast::ParenthesizedExpr), TextSize) + ) -> (TextSize, (crate::parser::ParenthesizedExpr, crate::parser::ParenthesizedExpr), TextSize) { match __symbols.pop() { Some((__l, __Symbol::Variant60(__v), __r)) => (__l, __v, __r), @@ -18513,7 +18513,7 @@ mod __parse__Top { fn __pop_Variant92< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, Option, TextSize) + ) -> (TextSize, Option, TextSize) { match __symbols.pop() { Some((__l, __Symbol::Variant92(__v), __r)) => (__l, __v, __r), @@ -18563,7 +18563,7 @@ mod __parse__Top { fn __pop_Variant61< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, Vec<(Option>, ast::ParenthesizedExpr)>, TextSize) + ) -> (TextSize, Vec<(Option>, crate::parser::ParenthesizedExpr)>, TextSize) { match __symbols.pop() { Some((__l, __Symbol::Variant61(__v), __r)) => (__l, __v, __r), @@ -18630,16 +18630,6 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant33< - >( - __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, Vec, TextSize) - { - match __symbols.pop() { - Some((__l, __Symbol::Variant33(__v), __r)) => (__l, __v, __r), - _ => __symbol_type_mismatch() - } - } fn __pop_Variant53< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> @@ -18690,6 +18680,16 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } + fn __pop_Variant33< + >( + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> + ) -> (TextSize, Vec, TextSize) + { + match __symbols.pop() { + Some((__l, __Symbol::Variant33(__v), __r)) => (__l, __v, __r), + _ => __symbol_type_mismatch() + } + } fn __pop_Variant32< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> @@ -18703,7 +18703,7 @@ mod __parse__Top { fn __pop_Variant28< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)>, TextSize) + ) -> (TextSize, alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)>, TextSize) { match __symbols.pop() { Some((__l, __Symbol::Variant28(__v), __r)) => (__l, __v, __r), @@ -18713,7 +18713,7 @@ mod __parse__Top { fn __pop_Variant43< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, alloc::vec::Vec<(ast::CmpOp, ast::ParenthesizedExpr)>, TextSize) + ) -> (TextSize, alloc::vec::Vec<(ast::CmpOp, crate::parser::ParenthesizedExpr)>, TextSize) { match __symbols.pop() { Some((__l, __Symbol::Variant43(__v), __r)) => (__l, __v, __r), @@ -18790,16 +18790,6 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant17< - >( - __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, alloc::vec::Vec, TextSize) - { - match __symbols.pop() { - Some((__l, __Symbol::Variant17(__v), __r)) => (__l, __v, __r), - _ => __symbol_type_mismatch() - } - } fn __pop_Variant36< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> @@ -18830,6 +18820,16 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } + fn __pop_Variant17< + >( + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> + ) -> (TextSize, alloc::vec::Vec, TextSize) + { + match __symbols.pop() { + Some((__l, __Symbol::Variant17(__v), __r)) => (__l, __v, __r), + _ => __symbol_type_mismatch() + } + } fn __pop_Variant22< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> @@ -19000,16 +19000,6 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant15< - >( - __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, ast::ParenthesizedExpr, TextSize) - { - match __symbols.pop() { - Some((__l, __Symbol::Variant15(__v), __r)) => (__l, __v, __r), - _ => __symbol_type_mismatch() - } - } fn __pop_Variant35< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> @@ -19163,7 +19153,7 @@ mod __parse__Top { fn __pop_Variant93< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, core::option::Option>, TextSize) + ) -> (TextSize, core::option::Option>, TextSize) { match __symbols.pop() { Some((__l, __Symbol::Variant93(__v), __r)) => (__l, __v, __r), @@ -19173,7 +19163,7 @@ mod __parse__Top { fn __pop_Variant62< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, core::option::Option>, ast::ParenthesizedExpr)>>, TextSize) + ) -> (TextSize, core::option::Option>, crate::parser::ParenthesizedExpr)>>, TextSize) { match __symbols.pop() { Some((__l, __Symbol::Variant62(__v), __r)) => (__l, __v, __r), @@ -19190,23 +19180,23 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant34< + fn __pop_Variant41< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, core::option::Option>, TextSize) + ) -> (TextSize, core::option::Option>, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant34(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant41(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } - fn __pop_Variant41< + fn __pop_Variant34< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, core::option::Option>, TextSize) + ) -> (TextSize, core::option::Option>, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant41(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant34(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -19260,16 +19250,6 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant16< - >( - __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, core::option::Option, TextSize) - { - match __symbols.pop() { - Some((__l, __Symbol::Variant16(__v), __r)) => (__l, __v, __r), - _ => __symbol_type_mismatch() - } - } fn __pop_Variant88< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> @@ -19300,6 +19280,16 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } + fn __pop_Variant16< + >( + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> + ) -> (TextSize, core::option::Option, TextSize) + { + match __symbols.pop() { + Some((__l, __Symbol::Variant16(__v), __r)) => (__l, __v, __r), + _ => __symbol_type_mismatch() + } + } fn __pop_Variant8< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> @@ -19310,6 +19300,16 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } + fn __pop_Variant15< + >( + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> + ) -> (TextSize, crate::parser::ParenthesizedExpr, TextSize) + { + match __symbols.pop() { + Some((__l, __Symbol::Variant15(__v), __r)) => (__l, __v, __r), + _ => __symbol_type_mismatch() + } + } fn __pop_Variant2< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> @@ -32518,7 +32518,7 @@ fn __action2< mode: Mode, (_, start, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, body, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, body, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, alloc::vec::Vec, TextSize), (_, end, _): (TextSize, TextSize, TextSize), ) -> ast::Mod @@ -32843,7 +32843,7 @@ fn __action25< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, targets, _): (TextSize, Vec, TextSize), + (_, targets, _): (TextSize, Vec, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -32861,8 +32861,8 @@ fn __action26< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, expression, _): (TextSize, ast::ParenthesizedExpr, TextSize), - (_, suffix, _): (TextSize, alloc::vec::Vec, TextSize), + (_, expression, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), + (_, suffix, _): (TextSize, alloc::vec::Vec, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> Result> { @@ -32896,9 +32896,9 @@ fn __action27< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, target, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, target, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, op, _): (TextSize, ast::Operator, TextSize), - (_, rhs, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, rhs, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> Result> { @@ -32922,10 +32922,10 @@ fn __action28< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, target, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, target, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, annotation, _): (TextSize, ast::ParenthesizedExpr, TextSize), - (_, rhs, _): (TextSize, core::option::Option, TextSize), + (_, annotation, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), + (_, rhs, _): (TextSize, core::option::Option, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> Result> { @@ -32951,8 +32951,8 @@ fn __action29< source_code: &str, mode: Mode, (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { e } @@ -32964,8 +32964,8 @@ fn __action30< source_code: &str, mode: Mode, (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { e } @@ -32976,8 +32976,8 @@ fn __action31< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -32988,8 +32988,8 @@ fn __action32< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -33000,8 +33000,8 @@ fn __action33< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -33012,8 +33012,8 @@ fn __action34< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -33024,8 +33024,8 @@ fn __action35< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -33036,8 +33036,8 @@ fn __action36< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -33048,8 +33048,8 @@ fn __action37< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -33060,8 +33060,8 @@ fn __action38< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -33072,8 +33072,8 @@ fn __action39< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -33275,7 +33275,7 @@ fn __action55< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, value, _): (TextSize, core::option::Option, TextSize), + (_, value, _): (TextSize, core::option::Option, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -33293,7 +33293,7 @@ fn __action56< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, expression, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, expression, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -33342,8 +33342,8 @@ fn __action59< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, exc, _): (TextSize, ast::ParenthesizedExpr, TextSize), - (_, cause, _): (TextSize, core::option::Option, TextSize), + (_, exc, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), + (_, cause, _): (TextSize, core::option::Option, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -33583,8 +33583,8 @@ fn __action73< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, test, _): (TextSize, ast::ParenthesizedExpr, TextSize), - (_, msg, _): (TextSize, core::option::Option, TextSize), + (_, test, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), + (_, msg, _): (TextSize, core::option::Option, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -33637,7 +33637,7 @@ fn __action75< (_, location, _): (TextSize, TextSize, TextSize), (_, c, _): (TextSize, (IpyEscapeKind, String), TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { { if mode == Mode::Ipython { @@ -33669,7 +33669,7 @@ fn __action76< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, suffix, _): (TextSize, alloc::vec::Vec, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> Result> @@ -33846,7 +33846,7 @@ fn __action85< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, subject, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, subject, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), @@ -33881,7 +33881,7 @@ fn __action86< (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, tuple_location, _): (TextSize, TextSize, TextSize), - (_, subject, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, subject, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, tuple_end_location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), @@ -33924,7 +33924,7 @@ fn __action87< (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, tuple_location, _): (TextSize, TextSize, TextSize), - (_, elts, _): (TextSize, Vec, TextSize), + (_, elts, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, core::option::Option, TextSize), (_, tuple_end_location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), @@ -33992,7 +33992,7 @@ fn __action89< source_code: &str, mode: Mode, (_, _, _): (TextSize, token::Tok, TextSize), - (_, guard, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, guard, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Expr { { @@ -34350,7 +34350,7 @@ fn __action111< (_, location, _): (TextSize, TextSize, TextSize), (_, value, _): (TextSize, ast::Number, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::Expr::NumberLiteral( ast::ExprNumberLiteral { value, range: (location..end_location).into() } @@ -34363,8 +34363,8 @@ fn __action112< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -34377,9 +34377,9 @@ fn __action113< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, operand, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, operand, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::Expr::UnaryOp( ast::ExprUnaryOp { @@ -34397,11 +34397,11 @@ fn __action114< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, op, _): (TextSize, ast::Operator, TextSize), - (_, right, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBinOp { left: Box::new(left.into()), @@ -34469,7 +34469,7 @@ fn __action118< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, value, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, value, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::Pattern { @@ -34486,7 +34486,7 @@ fn __action119< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, value, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, value, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::Pattern { @@ -34653,7 +34653,7 @@ fn __action129< >( source_code: &str, mode: Mode, - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Expr { e.into() @@ -34665,7 +34665,7 @@ fn __action130< >( source_code: &str, mode: Mode, - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Expr { e.into() @@ -35001,10 +35001,10 @@ fn __action146< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, test, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, test, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, body, _): (TextSize, ast::Suite, TextSize), - (_, s2, _): (TextSize, alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)>, TextSize), + (_, s2, _): (TextSize, alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)>, TextSize), (_, s3, _): (TextSize, core::option::Option<(TextSize, ast::Suite)>, TextSize), ) -> ast::Stmt { @@ -35037,7 +35037,7 @@ fn __action147< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, test, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, test, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, body, _): (TextSize, ast::Suite, TextSize), (_, s2, _): (TextSize, core::option::Option, TextSize), @@ -35070,9 +35070,9 @@ fn __action148< (_, location, _): (TextSize, TextSize, TextSize), (_, is_async, _): (TextSize, core::option::Option, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, target, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, target, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, iter, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, iter, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, body, _): (TextSize, ast::Suite, TextSize), (_, orelse, _): (TextSize, core::option::Option, TextSize), @@ -35206,7 +35206,7 @@ fn __action152< (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, typ, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, typ, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, body, _): (TextSize, ast::Suite, TextSize), ) -> ast::ExceptHandler @@ -35233,7 +35233,7 @@ fn __action153< (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, x, _): (TextSize, (ast::ParenthesizedExpr, ast::Identifier), TextSize), + (_, x, _): (TextSize, (crate::parser::ParenthesizedExpr, ast::Identifier), TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, body, _): (TextSize, ast::Suite, TextSize), ) -> ast::ExceptHandler @@ -35259,7 +35259,7 @@ fn __action154< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, typ, _): (TextSize, core::option::Option, TextSize), + (_, typ, _): (TextSize, core::option::Option, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, body, _): (TextSize, ast::Suite, TextSize), ) -> ast::ExceptHandler @@ -35285,7 +35285,7 @@ fn __action155< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, x, _): (TextSize, (ast::ParenthesizedExpr, ast::Identifier), TextSize), + (_, x, _): (TextSize, (crate::parser::ParenthesizedExpr, ast::Identifier), TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, body, _): (TextSize, ast::Suite, TextSize), ) -> ast::ExceptHandler @@ -35408,7 +35408,7 @@ fn __action161< >( source_code: &str, mode: Mode, - (_, all, _): (TextSize, Vec, TextSize), + (_, all, _): (TextSize, Vec, TextSize), ) -> Vec { { @@ -35427,9 +35427,9 @@ fn __action162< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, context_expr, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, context_expr, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, optional_vars, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, optional_vars, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::WithItem { @@ -35456,7 +35456,7 @@ fn __action163< (_, name, _): (TextSize, ast::Identifier, TextSize), (_, type_params, _): (TextSize, core::option::Option, TextSize), (_, parameters, _): (TextSize, ast::Parameters, TextSize), - (_, returns, _): (TextSize, core::option::Option, TextSize), + (_, returns, _): (TextSize, core::option::Option, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, body, _): (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -35507,7 +35507,7 @@ fn __action165< (_, name, _): (TextSize, ast::Expr, TextSize), (_, type_params, _): (TextSize, core::option::Option, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, value, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, value, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -35589,7 +35589,7 @@ fn __action169< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, name, _): (TextSize, ast::Identifier, TextSize), - (_, annotation, _): (TextSize, core::option::Option, TextSize), + (_, annotation, _): (TextSize, core::option::Option, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::ParameterWithDefault { @@ -35608,7 +35608,7 @@ fn __action170< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, name, _): (TextSize, ast::Identifier, TextSize), - (_, annotation, _): (TextSize, core::option::Option, TextSize), + (_, annotation, _): (TextSize, core::option::Option, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::Parameter { @@ -35626,7 +35626,7 @@ fn __action171< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, name, _): (TextSize, ast::Identifier, TextSize), - (_, annotation, _): (TextSize, core::option::Option, TextSize), + (_, annotation, _): (TextSize, core::option::Option, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::Parameter { @@ -35697,7 +35697,7 @@ fn __action174< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, name, _): (TextSize, ast::Identifier, TextSize), - (_, bound, _): (TextSize, core::option::Option, TextSize), + (_, bound, _): (TextSize, core::option::Option, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::TypeParam { @@ -35754,7 +35754,7 @@ fn __action177< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, expression, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, expression, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), ) -> ast::Decorator @@ -35772,9 +35772,9 @@ fn __action178< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, value, _): (TextSize, core::option::Option, TextSize), + (_, value, _): (TextSize, core::option::Option, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprYield { value: value.map(ast::Expr::from).map(Box::new), @@ -35791,9 +35791,9 @@ fn __action179< (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, value, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, value, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprYieldFrom { value: Box::new(value.into()), @@ -35807,8 +35807,8 @@ fn __action180< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -35819,8 +35819,8 @@ fn __action181< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -35834,7 +35834,7 @@ fn __action182< (_, location, _): (TextSize, TextSize, TextSize), (_, id, _): (TextSize, ast::Identifier, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprName { id: id.into(), @@ -35850,11 +35850,11 @@ fn __action183< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, target, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, target, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, value, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, value, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { ast::ExprNamedExpr { @@ -35878,9 +35878,9 @@ fn __action184< (_, end_location_args, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, fstring_middle, _): (TextSize, core::option::Option<(String, bool)>, TextSize), - (_, body, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, body, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { { if fstring_middle.is_some() { @@ -36171,8 +36171,8 @@ fn __action207< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -36184,10 +36184,10 @@ fn __action208< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, s1, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, s1, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { ast::ExprTuple { @@ -36205,10 +36205,10 @@ fn __action209< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, elts, _): (TextSize, Vec, TextSize), + (_, elts, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, core::option::Option, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { let elts = elts.into_iter().map(ast::Expr::from).collect(); @@ -36226,8 +36226,8 @@ fn __action210< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -36239,12 +36239,12 @@ fn __action211< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, lower, _): (TextSize, core::option::Option, TextSize), + (_, lower, _): (TextSize, core::option::Option, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, upper, _): (TextSize, core::option::Option, TextSize), - (_, step, _): (TextSize, core::option::Option>, TextSize), + (_, upper, _): (TextSize, core::option::Option, TextSize), + (_, step, _): (TextSize, core::option::Option>, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { let lower = lower.map(ast::Expr::from).map(Box::new); @@ -36264,8 +36264,8 @@ fn __action212< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, core::option::Option, TextSize), -) -> Option + (_, e, _): (TextSize, core::option::Option, TextSize), +) -> Option { e } @@ -36398,7 +36398,7 @@ fn __action221< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, value, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, value, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, debug, _): (TextSize, core::option::Option, TextSize), (_, conversion, _): (TextSize, core::option::Option<(TextSize, ast::ConversionFlag)>, TextSize), (_, format_spec, _): (TextSize, core::option::Option, TextSize), @@ -36507,9 +36507,9 @@ fn __action225< >( source_code: &str, mode: Mode, - (_, e, _): (TextSize, Vec, TextSize), + (_, e, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, core::option::Option, TextSize), -) -> Vec +) -> Vec { e } @@ -36520,9 +36520,9 @@ fn __action226< >( source_code: &str, mode: Mode, - (_, elements, _): (TextSize, Vec<(Option>, ast::ParenthesizedExpr)>, TextSize), + (_, elements, _): (TextSize, Vec<(Option>, crate::parser::ParenthesizedExpr)>, TextSize), (_, _, _): (TextSize, core::option::Option, TextSize), -) -> Vec<(Option>, ast::ParenthesizedExpr)> +) -> Vec<(Option>, crate::parser::ParenthesizedExpr)> { elements } @@ -36533,10 +36533,10 @@ fn __action227< >( source_code: &str, mode: Mode, - (_, e1, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, e1, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e2, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> (ast::ParenthesizedExpr, ast::ParenthesizedExpr) + (_, e2, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> (crate::parser::ParenthesizedExpr, crate::parser::ParenthesizedExpr) { (e1, e2) } @@ -36547,8 +36547,8 @@ fn __action228< >( source_code: &str, mode: Mode, - (_, e, _): (TextSize, (ast::ParenthesizedExpr, ast::ParenthesizedExpr), TextSize), -) -> (Option>, ast::ParenthesizedExpr) + (_, e, _): (TextSize, (crate::parser::ParenthesizedExpr, crate::parser::ParenthesizedExpr), TextSize), +) -> (Option>, crate::parser::ParenthesizedExpr) { (Some(Box::new(e.0)), e.1) } @@ -36560,8 +36560,8 @@ fn __action229< source_code: &str, mode: Mode, (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> (Option>, ast::ParenthesizedExpr) + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> (Option>, crate::parser::ParenthesizedExpr) { (None, e) } @@ -36572,9 +36572,9 @@ fn __action230< >( source_code: &str, mode: Mode, - (_, e1, _): (TextSize, Vec, TextSize), + (_, e1, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, core::option::Option, TextSize), -) -> Vec +) -> Vec { e1 } @@ -36585,8 +36585,8 @@ fn __action231< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -36597,8 +36597,8 @@ fn __action232< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -36609,8 +36609,8 @@ fn __action233< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -36621,9 +36621,9 @@ fn __action234< >( source_code: &str, mode: Mode, - (_, elements, _): (TextSize, Vec, TextSize), + (_, elements, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, core::option::Option, TextSize), -) -> Vec +) -> Vec { elements } @@ -36634,8 +36634,8 @@ fn __action235< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -36648,9 +36648,9 @@ fn __action236< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, value, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, value, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprStarred { value: Box::new(value.into()), @@ -36680,10 +36680,10 @@ fn __action238< (_, location, _): (TextSize, TextSize, TextSize), (_, is_async, _): (TextSize, core::option::Option, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, target, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, target, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, iter, _): (TextSize, ast::ParenthesizedExpr, TextSize), - (_, ifs, _): (TextSize, alloc::vec::Vec, TextSize), + (_, iter, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), + (_, ifs, _): (TextSize, alloc::vec::Vec, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::Comprehension { @@ -36706,8 +36706,8 @@ fn __action239< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -36719,8 +36719,8 @@ fn __action240< source_code: &str, mode: Mode, (_, _, _): (TextSize, token::Tok, TextSize), - (_, c, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, c, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { c } @@ -36755,7 +36755,7 @@ fn __action242< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, elt, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, elt, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, generators, _): (TextSize, core::option::Option>, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> (Option<(TextSize, TextSize, Option)>, ast::Expr) @@ -36784,7 +36784,7 @@ fn __action243< (_, location, _): (TextSize, TextSize, TextSize), (_, i, _): (TextSize, ast::Identifier, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> (Option<(TextSize, TextSize, Option)>, ast::Expr) { @@ -36799,7 +36799,7 @@ fn __action244< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, value, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, value, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> (Option<(TextSize, TextSize, Option)>, ast::Expr) { @@ -36819,7 +36819,7 @@ fn __action245< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> (Option<(TextSize, TextSize, Option)>, ast::Expr) { @@ -36927,7 +36927,7 @@ fn __action253< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> alloc::vec::Vec +) -> alloc::vec::Vec { alloc::vec![] } @@ -36938,8 +36938,8 @@ fn __action254< >( source_code: &str, mode: Mode, - (_, v, _): (TextSize, alloc::vec::Vec, TextSize), -) -> alloc::vec::Vec + (_, v, _): (TextSize, alloc::vec::Vec, TextSize), +) -> alloc::vec::Vec { v } @@ -36951,10 +36951,10 @@ fn __action255< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, values, _): (TextSize, alloc::vec::Vec, TextSize), - (_, last, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, values, _): (TextSize, alloc::vec::Vec, TextSize), + (_, last, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { let values = values.into_iter().chain(std::iter::once(last)).map(ast::Expr::from).collect(); @@ -36968,8 +36968,8 @@ fn __action256< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -37006,14 +37006,14 @@ fn __action259< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, elts, _): (TextSize, Vec, TextSize), + (_, elts, _): (TextSize, Vec, TextSize), (_, trailing_comma, _): (TextSize, core::option::Option, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { if elts.len() == 1 && trailing_comma.is_none() { - ast::ParenthesizedExpr { + crate::parser::ParenthesizedExpr { expr: elts.into_iter().next().unwrap().into(), range: (location..end_location).into(), } @@ -37030,8 +37030,8 @@ fn __action260< >( source_code: &str, mode: Mode, - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Vec + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Vec { vec![e] } @@ -37042,10 +37042,10 @@ fn __action261< >( source_code: &str, mode: Mode, - (_, mut v, _): (TextSize, Vec, TextSize), + (_, mut v, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Vec + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Vec { { v.push(e); @@ -37060,14 +37060,14 @@ fn __action262< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, elts, _): (TextSize, Vec, TextSize), + (_, elts, _): (TextSize, Vec, TextSize), (_, trailing_comma, _): (TextSize, core::option::Option, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { if elts.len() == 1 && trailing_comma.is_none() { - ast::ParenthesizedExpr { + crate::parser::ParenthesizedExpr { expr: elts.into_iter().next().unwrap().into(), range: (location..end_location).into(), } @@ -37084,8 +37084,8 @@ fn __action263< >( source_code: &str, mode: Mode, - (_, e, _): (TextSize, (Option>, ast::ParenthesizedExpr), TextSize), -) -> Vec<(Option>, ast::ParenthesizedExpr)> + (_, e, _): (TextSize, (Option>, crate::parser::ParenthesizedExpr), TextSize), +) -> Vec<(Option>, crate::parser::ParenthesizedExpr)> { vec![e] } @@ -37096,10 +37096,10 @@ fn __action264< >( source_code: &str, mode: Mode, - (_, mut v, _): (TextSize, Vec<(Option>, ast::ParenthesizedExpr)>, TextSize), + (_, mut v, _): (TextSize, Vec<(Option>, crate::parser::ParenthesizedExpr)>, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, (Option>, ast::ParenthesizedExpr), TextSize), -) -> Vec<(Option>, ast::ParenthesizedExpr)> + (_, e, _): (TextSize, (Option>, crate::parser::ParenthesizedExpr), TextSize), +) -> Vec<(Option>, crate::parser::ParenthesizedExpr)> { { v.push(e); @@ -37113,8 +37113,8 @@ fn __action265< >( source_code: &str, mode: Mode, - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Vec + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Vec { vec![e] } @@ -37125,10 +37125,10 @@ fn __action266< >( source_code: &str, mode: Mode, - (_, mut v, _): (TextSize, Vec, TextSize), + (_, mut v, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Vec + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Vec { { v.push(e); @@ -37271,8 +37271,8 @@ fn __action277< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, Option, TextSize), -) -> core::option::Option> + (_, __0, _): (TextSize, Option, TextSize), +) -> core::option::Option> { Some(__0) } @@ -37285,7 +37285,7 @@ fn __action278< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> core::option::Option> +) -> core::option::Option> { None } @@ -37296,10 +37296,10 @@ fn __action279< >( source_code: &str, mode: Mode, - (_, e1, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, e1, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e2, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Vec + (_, e2, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Vec { vec![e1, e2] } @@ -37310,10 +37310,10 @@ fn __action280< >( source_code: &str, mode: Mode, - (_, mut v, _): (TextSize, Vec, TextSize), + (_, mut v, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Vec + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Vec { { v.push(e); @@ -37544,8 +37544,8 @@ fn __action293< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> core::option::Option + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> core::option::Option { Some(__0) } @@ -37558,7 +37558,7 @@ fn __action294< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> core::option::Option +) -> core::option::Option { None } @@ -37570,8 +37570,8 @@ fn __action295< source_code: &str, mode: Mode, (_, _, _): (TextSize, token::Tok, TextSize), - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -37582,8 +37582,8 @@ fn __action296< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> core::option::Option + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> core::option::Option { Some(__0) } @@ -37596,7 +37596,7 @@ fn __action297< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> core::option::Option +) -> core::option::Option { None } @@ -37608,8 +37608,8 @@ fn __action298< source_code: &str, mode: Mode, (_, _, _): (TextSize, token::Tok, TextSize), - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -37770,8 +37770,8 @@ fn __action306< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> core::option::Option + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> core::option::Option { Some(__0) } @@ -37784,7 +37784,7 @@ fn __action307< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> core::option::Option +) -> core::option::Option { None } @@ -37796,8 +37796,8 @@ fn __action308< source_code: &str, mode: Mode, (_, _, _): (TextSize, token::Tok, TextSize), - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -37858,8 +37858,8 @@ fn __action313< >( source_code: &str, mode: Mode, - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Vec + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Vec { vec![e] } @@ -37870,10 +37870,10 @@ fn __action314< >( source_code: &str, mode: Mode, - (_, mut v, _): (TextSize, Vec, TextSize), + (_, mut v, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Vec + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Vec { { v.push(e); @@ -37912,7 +37912,7 @@ fn __action317< >( source_code: &str, mode: Mode, - (_, context_expr, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, context_expr, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::WithItem { { @@ -37980,7 +37980,7 @@ fn __action322< >( source_code: &str, mode: Mode, - (_, context_expr, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, context_expr, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::WithItem { { @@ -38048,8 +38048,8 @@ fn __action327< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> core::option::Option + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> core::option::Option { Some(__0) } @@ -38062,7 +38062,7 @@ fn __action328< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> core::option::Option +) -> core::option::Option { None } @@ -38073,10 +38073,10 @@ fn __action329< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, __1, _): (TextSize, ast::Identifier, TextSize), -) -> (ast::ParenthesizedExpr, ast::Identifier) +) -> (crate::parser::ParenthesizedExpr, ast::Identifier) { (__0, __1) } @@ -38282,7 +38282,7 @@ fn __action345< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)> +) -> alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)> { alloc::vec![] } @@ -38293,8 +38293,8 @@ fn __action346< >( source_code: &str, mode: Mode, - (_, v, _): (TextSize, alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)>, TextSize), -) -> alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)> + (_, v, _): (TextSize, alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)>, TextSize), +) -> alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)> { v } @@ -38307,10 +38307,10 @@ fn __action347< mode: Mode, (_, __0, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, __1, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, __1, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, __2, _): (TextSize, ast::Suite, TextSize), -) -> (TextSize, ast::ParenthesizedExpr, ast::Suite) +) -> (TextSize, crate::parser::ParenthesizedExpr, ast::Suite) { (__0, __1, __2) } @@ -38592,10 +38592,10 @@ fn __action367< >( source_code: &str, mode: Mode, - (_, e1, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, e1, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e2, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Vec + (_, e2, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Vec { vec![e1, e2] } @@ -38606,10 +38606,10 @@ fn __action368< >( source_code: &str, mode: Mode, - (_, mut v, _): (TextSize, Vec, TextSize), + (_, mut v, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Vec + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Vec { { v.push(e); @@ -38686,11 +38686,11 @@ fn __action374< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, right, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBinOp { left: Box::new(left.into()), @@ -38706,8 +38706,8 @@ fn __action375< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -38718,8 +38718,8 @@ fn __action376< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> core::option::Option + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> core::option::Option { Some(__0) } @@ -38732,7 +38732,7 @@ fn __action377< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> core::option::Option +) -> core::option::Option { None } @@ -38744,8 +38744,8 @@ fn __action378< source_code: &str, mode: Mode, (_, _, _): (TextSize, token::Tok, TextSize), - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -38986,8 +38986,8 @@ fn __action396< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> core::option::Option + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> core::option::Option { Some(__0) } @@ -39000,7 +39000,7 @@ fn __action397< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> core::option::Option +) -> core::option::Option { None } @@ -39012,8 +39012,8 @@ fn __action398< source_code: &str, mode: Mode, (_, _, _): (TextSize, token::Tok, TextSize), - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -39024,8 +39024,8 @@ fn __action399< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> core::option::Option + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> core::option::Option { Some(__0) } @@ -39038,7 +39038,7 @@ fn __action400< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> core::option::Option +) -> core::option::Option { None } @@ -39049,8 +39049,8 @@ fn __action401< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> core::option::Option + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> core::option::Option { Some(__0) } @@ -39063,7 +39063,7 @@ fn __action402< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> core::option::Option +) -> core::option::Option { None } @@ -39075,13 +39075,13 @@ fn __action403< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, body, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, body, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, test, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, test, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, orelse, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, orelse, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprIfExp { test: Box::new(test.into()), @@ -39097,8 +39097,8 @@ fn __action404< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -39109,8 +39109,8 @@ fn __action405< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -39123,7 +39123,7 @@ fn __action406< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> alloc::vec::Vec +) -> alloc::vec::Vec { alloc::vec![] } @@ -39134,8 +39134,8 @@ fn __action407< >( source_code: &str, mode: Mode, - (_, v, _): (TextSize, alloc::vec::Vec, TextSize), -) -> alloc::vec::Vec + (_, v, _): (TextSize, alloc::vec::Vec, TextSize), +) -> alloc::vec::Vec { v } @@ -39320,8 +39320,8 @@ fn __action422< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> alloc::vec::Vec + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> alloc::vec::Vec { alloc::vec![__0] } @@ -39332,9 +39332,9 @@ fn __action423< >( source_code: &str, mode: Mode, - (_, v, _): (TextSize, alloc::vec::Vec, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> alloc::vec::Vec + (_, v, _): (TextSize, alloc::vec::Vec, TextSize), + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> alloc::vec::Vec { { let mut v = v; v.push(e); v } } @@ -39384,11 +39384,11 @@ fn __action427< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, right, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBinOp { left: Box::new(left.into()), @@ -39404,8 +39404,8 @@ fn __action428< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -39466,8 +39466,8 @@ fn __action433< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, (TextSize, ast::ParenthesizedExpr, ast::Suite), TextSize), -) -> alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)> + (_, __0, _): (TextSize, (TextSize, crate::parser::ParenthesizedExpr, ast::Suite), TextSize), +) -> alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)> { alloc::vec![__0] } @@ -39478,9 +39478,9 @@ fn __action434< >( source_code: &str, mode: Mode, - (_, v, _): (TextSize, alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)>, TextSize), - (_, e, _): (TextSize, (TextSize, ast::ParenthesizedExpr, ast::Suite), TextSize), -) -> alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)> + (_, v, _): (TextSize, alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)>, TextSize), + (_, e, _): (TextSize, (TextSize, crate::parser::ParenthesizedExpr, ast::Suite), TextSize), +) -> alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)> { { let mut v = v; v.push(e); v } } @@ -39492,13 +39492,13 @@ fn __action435< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, body, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, body, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, test, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, test, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, orelse, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, orelse, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprIfExp { test: Box::new(test.into()), @@ -39514,8 +39514,8 @@ fn __action436< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -39526,8 +39526,8 @@ fn __action437< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -39838,8 +39838,8 @@ fn __action458< >( source_code: &str, mode: Mode, - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Vec + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Vec { vec![e] } @@ -39850,10 +39850,10 @@ fn __action459< >( source_code: &str, mode: Mode, - (_, mut v, _): (TextSize, Vec, TextSize), + (_, mut v, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Vec + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Vec { { v.push(e); @@ -39867,8 +39867,8 @@ fn __action460< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> alloc::vec::Vec + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> alloc::vec::Vec { alloc::vec![__0] } @@ -39879,9 +39879,9 @@ fn __action461< >( source_code: &str, mode: Mode, - (_, v, _): (TextSize, alloc::vec::Vec, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> alloc::vec::Vec + (_, v, _): (TextSize, alloc::vec::Vec, TextSize), + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> alloc::vec::Vec { { let mut v = v; v.push(e); v } } @@ -39892,9 +39892,9 @@ fn __action462< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { __0 } @@ -39906,10 +39906,10 @@ fn __action463< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, values, _): (TextSize, alloc::vec::Vec, TextSize), - (_, last, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, values, _): (TextSize, alloc::vec::Vec, TextSize), + (_, last, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { let values = values.into_iter().chain(std::iter::once(last)).map(ast::Expr::from).collect(); @@ -39923,8 +39923,8 @@ fn __action464< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -39935,8 +39935,8 @@ fn __action465< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> alloc::vec::Vec + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> alloc::vec::Vec { alloc::vec![__0] } @@ -39947,9 +39947,9 @@ fn __action466< >( source_code: &str, mode: Mode, - (_, v, _): (TextSize, alloc::vec::Vec, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> alloc::vec::Vec + (_, v, _): (TextSize, alloc::vec::Vec, TextSize), + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> alloc::vec::Vec { { let mut v = v; v.push(e); v } } @@ -40048,8 +40048,8 @@ fn __action474< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> alloc::vec::Vec + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> alloc::vec::Vec { alloc::vec![__0] } @@ -40060,9 +40060,9 @@ fn __action475< >( source_code: &str, mode: Mode, - (_, v, _): (TextSize, alloc::vec::Vec, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> alloc::vec::Vec + (_, v, _): (TextSize, alloc::vec::Vec, TextSize), + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> alloc::vec::Vec { { let mut v = v; v.push(e); v } } @@ -40073,9 +40073,9 @@ fn __action476< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40088,9 +40088,9 @@ fn __action477< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, operand, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, operand, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprUnaryOp { operand: Box::new(operand.into()), @@ -40105,8 +40105,8 @@ fn __action478< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40223,7 +40223,7 @@ fn __action487< mode: Mode, (_, mut i, _): (TextSize, ast::ParameterWithDefault, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, default, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, default, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::ParameterWithDefault { @@ -40371,7 +40371,7 @@ fn __action498< mode: Mode, (_, mut i, _): (TextSize, ast::ParameterWithDefault, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, default, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, default, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> ast::ParameterWithDefault { @@ -40439,10 +40439,10 @@ fn __action503< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, values, _): (TextSize, alloc::vec::Vec, TextSize), - (_, last, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, values, _): (TextSize, alloc::vec::Vec, TextSize), + (_, last, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { let values = values.into_iter().chain(std::iter::once(last)).map(ast::Expr::from).collect(); @@ -40456,8 +40456,8 @@ fn __action504< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40469,11 +40469,11 @@ fn __action505< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, right, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBinOp { left: Box::new(left.into()), @@ -40489,8 +40489,8 @@ fn __action506< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40502,11 +40502,11 @@ fn __action507< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, op, _): (TextSize, ast::Operator, TextSize), - (_, right, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBinOp { left: Box::new(left.into()), @@ -40522,8 +40522,8 @@ fn __action508< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40535,10 +40535,10 @@ fn __action509< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, values, _): (TextSize, alloc::vec::Vec, TextSize), - (_, last, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, values, _): (TextSize, alloc::vec::Vec, TextSize), + (_, last, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { let values = values.into_iter().chain(std::iter::once(last)).map(ast::Expr::from).collect(); @@ -40552,8 +40552,8 @@ fn __action510< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40615,10 +40615,10 @@ fn __action515< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), - (_, comparisons, _): (TextSize, alloc::vec::Vec<(ast::CmpOp, ast::ParenthesizedExpr)>, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), + (_, comparisons, _): (TextSize, alloc::vec::Vec<(ast::CmpOp, crate::parser::ParenthesizedExpr)>, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { let (ops, comparators) = comparisons.into_iter().map(|(op, comparator)| (op, ast::Expr::from(comparator))).unzip(); @@ -40632,8 +40632,8 @@ fn __action516< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40644,8 +40644,8 @@ fn __action517< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, (ast::CmpOp, ast::ParenthesizedExpr), TextSize), -) -> alloc::vec::Vec<(ast::CmpOp, ast::ParenthesizedExpr)> + (_, __0, _): (TextSize, (ast::CmpOp, crate::parser::ParenthesizedExpr), TextSize), +) -> alloc::vec::Vec<(ast::CmpOp, crate::parser::ParenthesizedExpr)> { alloc::vec![__0] } @@ -40656,9 +40656,9 @@ fn __action518< >( source_code: &str, mode: Mode, - (_, v, _): (TextSize, alloc::vec::Vec<(ast::CmpOp, ast::ParenthesizedExpr)>, TextSize), - (_, e, _): (TextSize, (ast::CmpOp, ast::ParenthesizedExpr), TextSize), -) -> alloc::vec::Vec<(ast::CmpOp, ast::ParenthesizedExpr)> + (_, v, _): (TextSize, alloc::vec::Vec<(ast::CmpOp, crate::parser::ParenthesizedExpr)>, TextSize), + (_, e, _): (TextSize, (ast::CmpOp, crate::parser::ParenthesizedExpr), TextSize), +) -> alloc::vec::Vec<(ast::CmpOp, crate::parser::ParenthesizedExpr)> { { let mut v = v; v.push(e); v } } @@ -40670,8 +40670,8 @@ fn __action519< source_code: &str, mode: Mode, (_, __0, _): (TextSize, ast::CmpOp, TextSize), - (_, __1, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> (ast::CmpOp, ast::ParenthesizedExpr) + (_, __1, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> (ast::CmpOp, crate::parser::ParenthesizedExpr) { (__0, __1) } @@ -40684,9 +40684,9 @@ fn __action520< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, operand, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, operand, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprUnaryOp { operand: Box::new(operand.into()), @@ -40701,8 +40701,8 @@ fn __action521< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40714,11 +40714,11 @@ fn __action522< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, op, _): (TextSize, ast::Operator, TextSize), - (_, right, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBinOp { left: Box::new(left.into()), @@ -40734,8 +40734,8 @@ fn __action523< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40747,11 +40747,11 @@ fn __action524< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, op, _): (TextSize, ast::Operator, TextSize), - (_, right, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBinOp { left: Box::new(left.into()), @@ -40767,8 +40767,8 @@ fn __action525< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40780,10 +40780,10 @@ fn __action526< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), - (_, comparisons, _): (TextSize, alloc::vec::Vec<(ast::CmpOp, ast::ParenthesizedExpr)>, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), + (_, comparisons, _): (TextSize, alloc::vec::Vec<(ast::CmpOp, crate::parser::ParenthesizedExpr)>, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { let (ops, comparators) = comparisons.into_iter().map(|(op, comparator)| (op, ast::Expr::from(comparator))).unzip(); @@ -40797,8 +40797,8 @@ fn __action527< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40810,11 +40810,11 @@ fn __action528< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, right, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBinOp { left: Box::new(left.into()), @@ -40830,8 +40830,8 @@ fn __action529< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40844,9 +40844,9 @@ fn __action530< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, op, _): (TextSize, ast::UnaryOp, TextSize), - (_, operand, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, operand, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprUnaryOp { operand: Box::new(operand.into()), @@ -40861,8 +40861,8 @@ fn __action531< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40874,11 +40874,11 @@ fn __action532< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, right, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBinOp { left: Box::new(left.into()), @@ -40894,8 +40894,8 @@ fn __action533< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40907,11 +40907,11 @@ fn __action534< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, right, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBinOp { left: Box::new(left.into()), @@ -40927,8 +40927,8 @@ fn __action535< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40940,11 +40940,11 @@ fn __action536< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, right, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBinOp { left: Box::new(left.into()), @@ -40960,8 +40960,8 @@ fn __action537< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -40974,9 +40974,9 @@ fn __action538< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, value, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, value, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { ast::ExprAwait { value: Box::new(value.into()), range: (location..end_location).into() }.into() @@ -40989,8 +40989,8 @@ fn __action539< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -41001,8 +41001,8 @@ fn __action540< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -41014,10 +41014,10 @@ fn __action541< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, func, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, func, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, arguments, _): (TextSize, ast::Arguments, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprCall { func: Box::new(func.into()), @@ -41033,12 +41033,12 @@ fn __action542< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, value, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, value, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, slice, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, slice, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprSubscript { value: Box::new(value.into()), @@ -41055,11 +41055,11 @@ fn __action543< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, value, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, value, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, attr, _): (TextSize, ast::Identifier, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprAttribute { value: Box::new(value.into()), @@ -41076,11 +41076,11 @@ fn __action544< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, op, _): (TextSize, ast::Operator, TextSize), - (_, right, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBinOp { left: Box::new(left.into()), @@ -41096,8 +41096,8 @@ fn __action545< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -41109,11 +41109,11 @@ fn __action546< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, op, _): (TextSize, ast::Operator, TextSize), - (_, right, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBinOp { left: Box::new(left.into()), @@ -41129,8 +41129,8 @@ fn __action547< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -41142,7 +41142,7 @@ fn __action548< source_code: &str, mode: Mode, (_, expr, _): (TextSize, ast::Expr, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { expr.into() } @@ -41156,7 +41156,7 @@ fn __action549< (_, location, _): (TextSize, TextSize, TextSize), (_, value, _): (TextSize, ast::Number, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprNumberLiteral { value, @@ -41173,7 +41173,7 @@ fn __action550< (_, location, _): (TextSize, TextSize, TextSize), (_, id, _): (TextSize, ast::Identifier, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprName { id: id.into(), @@ -41190,10 +41190,10 @@ fn __action551< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, elts, _): (TextSize, core::option::Option>, TextSize), + (_, elts, _): (TextSize, core::option::Option>, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { let elts = elts.into_iter().flatten().map(ast::Expr::from).collect(); @@ -41209,11 +41209,11 @@ fn __action552< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, elt, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, elt, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, generators, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { ast::ExprListComp { elt: Box::new(elt.into()), generators, range: (location..end_location).into() }.into() @@ -41228,15 +41228,15 @@ fn __action553< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, elts, _): (TextSize, Vec, TextSize), + (_, elts, _): (TextSize, Vec, TextSize), (_, trailing_comma, _): (TextSize, core::option::Option, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { if elts.len() == 1 && trailing_comma.is_none() { - ast::ParenthesizedExpr { + crate::parser::ParenthesizedExpr { expr: elts.into_iter().next().unwrap().into(), range: (location..end_location).into(), } @@ -41255,13 +41255,13 @@ fn __action554< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, left, _): (TextSize, core::option::Option>, TextSize), - (_, mid, _): (TextSize, ast::ParenthesizedExpr, TextSize), - (_, right, _): (TextSize, alloc::vec::Vec, TextSize), + (_, left, _): (TextSize, core::option::Option>, TextSize), + (_, mid, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, alloc::vec::Vec, TextSize), (_, trailing_comma, _): (TextSize, core::option::Option, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { { if left.is_none() && right.is_empty() && trailing_comma.is_none() { @@ -41271,7 +41271,7 @@ fn __action554< location: mid.start(), })?; } - Ok(ast::ParenthesizedExpr { + Ok(crate::parser::ParenthesizedExpr { expr: mid.into(), range: (location..end_location).into(), }) @@ -41292,7 +41292,7 @@ fn __action555< (_, _, _): (TextSize, token::Tok, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprTuple { elts: Vec::new(), @@ -41309,12 +41309,12 @@ fn __action556< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { - ast::ParenthesizedExpr { + crate::parser::ParenthesizedExpr { expr: e.into(), range: (location..end_location).into(), } @@ -41328,11 +41328,11 @@ fn __action557< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, elt, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, elt, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, generators, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprGeneratorExp { elt: Box::new(elt.into()), @@ -41350,10 +41350,10 @@ fn __action558< (_, _, _): (TextSize, token::Tok, TextSize), (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { { Err(LexicalError{ @@ -41371,10 +41371,10 @@ fn __action559< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, core::option::Option>, ast::ParenthesizedExpr)>>, TextSize), + (_, e, _): (TextSize, core::option::Option>, crate::parser::ParenthesizedExpr)>>, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { let (keys, values) = e @@ -41394,11 +41394,11 @@ fn __action560< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e1, _): (TextSize, (ast::ParenthesizedExpr, ast::ParenthesizedExpr), TextSize), + (_, e1, _): (TextSize, (crate::parser::ParenthesizedExpr, crate::parser::ParenthesizedExpr), TextSize), (_, generators, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { ast::ExprDictComp { @@ -41418,10 +41418,10 @@ fn __action561< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, elts, _): (TextSize, Vec, TextSize), + (_, elts, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { let elts = elts.into_iter().map(ast::Expr::from).collect(); @@ -41440,11 +41440,11 @@ fn __action562< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, elt, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, elt, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, generators, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprSetComp { elt: Box::new(elt.into()), @@ -41462,7 +41462,7 @@ fn __action563< (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBooleanLiteral { value: true, range: (location..end_location).into() }.into() } @@ -41476,7 +41476,7 @@ fn __action564< (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBooleanLiteral { value: false, range: (location..end_location).into() }.into() } @@ -41490,7 +41490,7 @@ fn __action565< (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprNoneLiteral { range: (location..end_location).into() }.into() } @@ -41504,7 +41504,7 @@ fn __action566< (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprEllipsisLiteral { range: (location..end_location).into() }.into() } @@ -41515,8 +41515,8 @@ fn __action567< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, Vec<(Option>, ast::ParenthesizedExpr)>, TextSize), -) -> core::option::Option>, ast::ParenthesizedExpr)>> + (_, __0, _): (TextSize, Vec<(Option>, crate::parser::ParenthesizedExpr)>, TextSize), +) -> core::option::Option>, crate::parser::ParenthesizedExpr)>> { Some(__0) } @@ -41529,7 +41529,7 @@ fn __action568< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> core::option::Option>, ast::ParenthesizedExpr)>> +) -> core::option::Option>, crate::parser::ParenthesizedExpr)>> { None } @@ -41542,7 +41542,7 @@ fn __action569< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> alloc::vec::Vec +) -> alloc::vec::Vec { alloc::vec![] } @@ -41553,8 +41553,8 @@ fn __action570< >( source_code: &str, mode: Mode, - (_, v, _): (TextSize, alloc::vec::Vec, TextSize), -) -> alloc::vec::Vec + (_, v, _): (TextSize, alloc::vec::Vec, TextSize), +) -> alloc::vec::Vec { v } @@ -41566,8 +41566,8 @@ fn __action571< source_code: &str, mode: Mode, (_, _, _): (TextSize, token::Tok, TextSize), - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -41578,8 +41578,8 @@ fn __action572< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, Vec, TextSize), -) -> core::option::Option> + (_, __0, _): (TextSize, Vec, TextSize), +) -> core::option::Option> { Some(__0) } @@ -41592,7 +41592,7 @@ fn __action573< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> core::option::Option> +) -> core::option::Option> { None } @@ -41603,9 +41603,9 @@ fn __action574< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, Vec, TextSize), + (_, __0, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), -) -> Vec +) -> Vec { __0 } @@ -41616,8 +41616,8 @@ fn __action575< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, Vec, TextSize), -) -> core::option::Option> + (_, __0, _): (TextSize, Vec, TextSize), +) -> core::option::Option> { Some(__0) } @@ -41630,7 +41630,7 @@ fn __action576< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> core::option::Option> +) -> core::option::Option> { None } @@ -41642,11 +41642,11 @@ fn __action577< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, op, _): (TextSize, ast::Operator, TextSize), - (_, right, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBinOp { left: Box::new(left.into()), @@ -41662,8 +41662,8 @@ fn __action578< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -41676,9 +41676,9 @@ fn __action579< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, op, _): (TextSize, ast::UnaryOp, TextSize), - (_, operand, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, operand, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprUnaryOp { operand: Box::new(operand.into()), @@ -41693,8 +41693,8 @@ fn __action580< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -41705,8 +41705,8 @@ fn __action581< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> alloc::vec::Vec + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> alloc::vec::Vec { alloc::vec![__0] } @@ -41717,9 +41717,9 @@ fn __action582< >( source_code: &str, mode: Mode, - (_, v, _): (TextSize, alloc::vec::Vec, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> alloc::vec::Vec + (_, v, _): (TextSize, alloc::vec::Vec, TextSize), + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> alloc::vec::Vec { { let mut v = v; v.push(e); v } } @@ -41731,11 +41731,11 @@ fn __action583< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, left, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, left, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, right, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBinOp { left: Box::new(left.into()), @@ -41751,8 +41751,8 @@ fn __action584< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -41765,9 +41765,9 @@ fn __action585< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, value, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, value, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { ast::ExprAwait { value: Box::new(value.into()), range: (location..end_location).into() }.into() @@ -41780,8 +41780,8 @@ fn __action586< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -41792,8 +41792,8 @@ fn __action587< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + (_, __0, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { __0 } @@ -41805,10 +41805,10 @@ fn __action588< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, func, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, func, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, arguments, _): (TextSize, ast::Arguments, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprCall { func: Box::new(func.into()), @@ -41824,12 +41824,12 @@ fn __action589< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, value, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, value, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, slice, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, slice, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprSubscript { value: Box::new(value.into()), @@ -41846,11 +41846,11 @@ fn __action590< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, value, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, value, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, attr, _): (TextSize, ast::Identifier, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprAttribute { value: Box::new(value.into()), @@ -41867,7 +41867,7 @@ fn __action591< source_code: &str, mode: Mode, (_, expr, _): (TextSize, ast::Expr, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { expr.into() } @@ -41881,7 +41881,7 @@ fn __action592< (_, location, _): (TextSize, TextSize, TextSize), (_, value, _): (TextSize, ast::Number, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprNumberLiteral { value, @@ -41898,7 +41898,7 @@ fn __action593< (_, location, _): (TextSize, TextSize, TextSize), (_, id, _): (TextSize, ast::Identifier, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprName { id: id.into(), @@ -41915,10 +41915,10 @@ fn __action594< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, elts, _): (TextSize, core::option::Option>, TextSize), + (_, elts, _): (TextSize, core::option::Option>, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { let elts = elts.into_iter().flatten().map(ast::Expr::from).collect(); @@ -41934,11 +41934,11 @@ fn __action595< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, elt, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, elt, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, generators, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { ast::ExprListComp { elt: Box::new(elt.into()), generators, range: (location..end_location).into() }.into() @@ -41953,13 +41953,13 @@ fn __action596< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, left, _): (TextSize, core::option::Option>, TextSize), - (_, mid, _): (TextSize, ast::ParenthesizedExpr, TextSize), - (_, right, _): (TextSize, alloc::vec::Vec, TextSize), + (_, left, _): (TextSize, core::option::Option>, TextSize), + (_, mid, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), + (_, right, _): (TextSize, alloc::vec::Vec, TextSize), (_, trailing_comma, _): (TextSize, core::option::Option, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { { if left.is_none() && right.is_empty() && trailing_comma.is_none() { @@ -41969,7 +41969,7 @@ fn __action596< location: mid.start(), })?; } - Ok(ast::ParenthesizedExpr { + Ok(crate::parser::ParenthesizedExpr { expr: mid.into(), range: (location..end_location).into(), }) @@ -41990,7 +41990,7 @@ fn __action597< (_, _, _): (TextSize, token::Tok, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprTuple { elts: Vec::new(), @@ -42007,12 +42007,12 @@ fn __action598< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { - ast::ParenthesizedExpr { + crate::parser::ParenthesizedExpr { expr: e.into(), range: (location..end_location).into(), } @@ -42026,11 +42026,11 @@ fn __action599< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, elt, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, elt, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, generators, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprGeneratorExp { elt: Box::new(elt.into()), @@ -42048,10 +42048,10 @@ fn __action600< (_, _, _): (TextSize, token::Tok, TextSize), (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, e, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { { Err(LexicalError{ @@ -42069,10 +42069,10 @@ fn __action601< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e, _): (TextSize, core::option::Option>, ast::ParenthesizedExpr)>>, TextSize), + (_, e, _): (TextSize, core::option::Option>, crate::parser::ParenthesizedExpr)>>, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { let (keys, values) = e @@ -42092,11 +42092,11 @@ fn __action602< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, e1, _): (TextSize, (ast::ParenthesizedExpr, ast::ParenthesizedExpr), TextSize), + (_, e1, _): (TextSize, (crate::parser::ParenthesizedExpr, crate::parser::ParenthesizedExpr), TextSize), (_, generators, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { ast::ExprDictComp { @@ -42116,10 +42116,10 @@ fn __action603< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, elts, _): (TextSize, Vec, TextSize), + (_, elts, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { { let elts = elts.into_iter().map(ast::Expr::from).collect(); @@ -42138,11 +42138,11 @@ fn __action604< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, elt, _): (TextSize, ast::ParenthesizedExpr, TextSize), + (_, elt, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, generators, _): (TextSize, Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprSetComp { elt: Box::new(elt.into()), @@ -42160,7 +42160,7 @@ fn __action605< (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBooleanLiteral { value: true, range: (location..end_location).into() }.into() } @@ -42174,7 +42174,7 @@ fn __action606< (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprBooleanLiteral { value: false, range: (location..end_location).into() }.into() } @@ -42188,7 +42188,7 @@ fn __action607< (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprNoneLiteral { range: (location..end_location).into() }.into() } @@ -42202,7 +42202,7 @@ fn __action608< (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { ast::ExprEllipsisLiteral { range: (location..end_location).into() }.into() } @@ -42215,11 +42215,11 @@ fn __action609< mode: Mode, __0: (TextSize, TextSize, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, Vec, TextSize), + __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __3.0; let __end0 = __3.2; @@ -42249,10 +42249,10 @@ fn __action610< mode: Mode, __0: (TextSize, TextSize, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, Vec, TextSize), + __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __3.0; @@ -42283,13 +42283,13 @@ fn __action611< mode: Mode, __0: (TextSize, TextSize, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, core::option::Option>, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), - __4: (TextSize, alloc::vec::Vec, TextSize), + __2: (TextSize, core::option::Option>, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __4: (TextSize, alloc::vec::Vec, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, token::Tok, TextSize), __7: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __5.0; let __end0 = __5.2; @@ -42321,12 +42321,12 @@ fn __action612< mode: Mode, __0: (TextSize, TextSize, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, core::option::Option>, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), - __4: (TextSize, alloc::vec::Vec, TextSize), + __2: (TextSize, core::option::Option>, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __4: (TextSize, alloc::vec::Vec, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __4.2; let __end0 = __5.0; @@ -42359,13 +42359,13 @@ fn __action613< mode: Mode, __0: (TextSize, TextSize, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, core::option::Option>, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), - __4: (TextSize, alloc::vec::Vec, TextSize), + __2: (TextSize, core::option::Option>, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __4: (TextSize, alloc::vec::Vec, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, token::Tok, TextSize), __7: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __5.0; let __end0 = __5.2; @@ -42397,12 +42397,12 @@ fn __action614< mode: Mode, __0: (TextSize, TextSize, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, core::option::Option>, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), - __4: (TextSize, alloc::vec::Vec, TextSize), + __2: (TextSize, core::option::Option>, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __4: (TextSize, alloc::vec::Vec, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __4.2; let __end0 = __5.0; @@ -42433,9 +42433,9 @@ fn __action615< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec<(Option>, ast::ParenthesizedExpr)>, TextSize), + __0: (TextSize, Vec<(Option>, crate::parser::ParenthesizedExpr)>, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> Vec<(Option>, ast::ParenthesizedExpr)> +) -> Vec<(Option>, crate::parser::ParenthesizedExpr)> { let __start0 = __1.0; let __end0 = __1.2; @@ -42459,8 +42459,8 @@ fn __action616< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec<(Option>, ast::ParenthesizedExpr)>, TextSize), -) -> Vec<(Option>, ast::ParenthesizedExpr)> + __0: (TextSize, Vec<(Option>, crate::parser::ParenthesizedExpr)>, TextSize), +) -> Vec<(Option>, crate::parser::ParenthesizedExpr)> { let __start0 = __0.2; let __end0 = __0.2; @@ -42485,9 +42485,9 @@ fn __action617< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> Vec +) -> Vec { let __start0 = __1.0; let __end0 = __1.2; @@ -42511,8 +42511,8 @@ fn __action618< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), -) -> Vec + __0: (TextSize, Vec, TextSize), +) -> Vec { let __start0 = __0.2; let __end0 = __0.2; @@ -42538,10 +42538,10 @@ fn __action619< source_code: &str, mode: Mode, __0: (TextSize, TextSize, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.0; let __end0 = __2.2; @@ -42568,9 +42568,9 @@ fn __action620< source_code: &str, mode: Mode, __0: (TextSize, TextSize, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __2.0; @@ -42598,10 +42598,10 @@ fn __action621< source_code: &str, mode: Mode, __0: (TextSize, TextSize, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.0; let __end0 = __2.2; @@ -42628,9 +42628,9 @@ fn __action622< source_code: &str, mode: Mode, __0: (TextSize, TextSize, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __2.0; @@ -42725,9 +42725,9 @@ fn __action625< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> Vec +) -> Vec { let __start0 = __1.0; let __end0 = __1.2; @@ -42751,8 +42751,8 @@ fn __action626< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), -) -> Vec + __0: (TextSize, Vec, TextSize), +) -> Vec { let __start0 = __0.2; let __end0 = __0.2; @@ -43000,7 +43000,7 @@ fn __action633< __0: (TextSize, TextSize, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, TextSize, TextSize), - __3: (TextSize, Vec, TextSize), + __3: (TextSize, Vec, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, TextSize, TextSize), __6: (TextSize, token::Tok, TextSize), @@ -43044,7 +43044,7 @@ fn __action634< __0: (TextSize, TextSize, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, TextSize, TextSize), - __3: (TextSize, Vec, TextSize), + __3: (TextSize, Vec, TextSize), __4: (TextSize, TextSize, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, token::Tok, TextSize), @@ -43925,9 +43925,9 @@ fn __action661< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> Vec +) -> Vec { let __start0 = __1.0; let __end0 = __1.2; @@ -43951,8 +43951,8 @@ fn __action662< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), -) -> Vec + __0: (TextSize, Vec, TextSize), +) -> Vec { let __start0 = __0.2; let __end0 = __0.2; @@ -43978,10 +43978,10 @@ fn __action663< source_code: &str, mode: Mode, __0: (TextSize, TextSize, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.0; let __end0 = __2.2; @@ -44008,9 +44008,9 @@ fn __action664< source_code: &str, mode: Mode, __0: (TextSize, TextSize, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __2.0; @@ -44483,7 +44483,7 @@ fn __action679< mode: Mode, __0: (TextSize, TextSize, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, core::option::Option<(TextSize, ast::ConversionFlag)>, TextSize), __5: (TextSize, core::option::Option, TextSize), @@ -44521,7 +44521,7 @@ fn __action680< mode: Mode, __0: (TextSize, TextSize, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, core::option::Option<(TextSize, ast::ConversionFlag)>, TextSize), __4: (TextSize, core::option::Option, TextSize), __5: (TextSize, token::Tok, TextSize), @@ -44560,9 +44560,9 @@ fn __action681< __0: (TextSize, TextSize, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, token::Tok, TextSize), - __5: (TextSize, ast::ParenthesizedExpr, TextSize), + __5: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __6: (TextSize, token::Tok, TextSize), __7: (TextSize, ast::Suite, TextSize), __8: (TextSize, core::option::Option, TextSize), @@ -44599,9 +44599,9 @@ fn __action682< mode: Mode, __0: (TextSize, TextSize, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, ast::Suite, TextSize), __7: (TextSize, core::option::Option, TextSize), @@ -44644,7 +44644,7 @@ fn __action683< __4: (TextSize, ast::Identifier, TextSize), __5: (TextSize, core::option::Option, TextSize), __6: (TextSize, ast::Parameters, TextSize), - __7: (TextSize, core::option::Option, TextSize), + __7: (TextSize, core::option::Option, TextSize), __8: (TextSize, token::Tok, TextSize), __9: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -44685,7 +44685,7 @@ fn __action684< __3: (TextSize, ast::Identifier, TextSize), __4: (TextSize, core::option::Option, TextSize), __5: (TextSize, ast::Parameters, TextSize), - __6: (TextSize, core::option::Option, TextSize), + __6: (TextSize, core::option::Option, TextSize), __7: (TextSize, token::Tok, TextSize), __8: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -44724,10 +44724,10 @@ fn __action685< __0: (TextSize, TextSize, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, token::Tok, TextSize), - __5: (TextSize, ast::ParenthesizedExpr, TextSize), - __6: (TextSize, alloc::vec::Vec, TextSize), + __5: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __6: (TextSize, alloc::vec::Vec, TextSize), __7: (TextSize, TextSize, TextSize), ) -> ast::Comprehension { @@ -44761,10 +44761,10 @@ fn __action686< mode: Mode, __0: (TextSize, TextSize, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), - __5: (TextSize, alloc::vec::Vec, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __5: (TextSize, alloc::vec::Vec, TextSize), __6: (TextSize, TextSize, TextSize), ) -> ast::Comprehension { @@ -45914,10 +45914,10 @@ fn __action723< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Suite, TextSize), -) -> (TextSize, ast::ParenthesizedExpr, ast::Suite) +) -> (TextSize, crate::parser::ParenthesizedExpr, ast::Suite) { let __start0 = __0.0; let __end0 = __0.0; @@ -45975,11 +45975,11 @@ fn __action725< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46007,11 +46007,11 @@ fn __action726< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46039,11 +46039,11 @@ fn __action727< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46071,10 +46071,10 @@ fn __action728< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46101,10 +46101,10 @@ fn __action729< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46163,11 +46163,11 @@ fn __action731< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46195,11 +46195,11 @@ fn __action732< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46260,8 +46260,8 @@ fn __action734< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), - __2: (TextSize, core::option::Option, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __2: (TextSize, core::option::Option, TextSize), __3: (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -46293,7 +46293,7 @@ fn __action735< mode: Mode, __0: (TextSize, ast::Number, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46321,7 +46321,7 @@ fn __action736< mode: Mode, __0: (TextSize, ast::Identifier, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46348,10 +46348,10 @@ fn __action737< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), + __1: (TextSize, core::option::Option>, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46380,11 +46380,11 @@ fn __action738< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46414,11 +46414,11 @@ fn __action739< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46448,10 +46448,10 @@ fn __action740< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46480,13 +46480,13 @@ fn __action741< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, core::option::Option>, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.0; let __end0 = __0.0; @@ -46518,12 +46518,12 @@ fn __action742< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, core::option::Option>, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.0; let __end0 = __0.0; @@ -46556,7 +46556,7 @@ fn __action743< __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46584,10 +46584,10 @@ fn __action744< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46616,11 +46616,11 @@ fn __action745< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46651,10 +46651,10 @@ fn __action746< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.2; let __end0 = __1.0; @@ -46684,10 +46684,10 @@ fn __action747< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, ast::ParenthesizedExpr)>>, TextSize), + __1: (TextSize, core::option::Option>, crate::parser::ParenthesizedExpr)>>, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46716,11 +46716,11 @@ fn __action748< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, (ast::ParenthesizedExpr, ast::ParenthesizedExpr), TextSize), + __1: (TextSize, (crate::parser::ParenthesizedExpr, crate::parser::ParenthesizedExpr), TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46750,10 +46750,10 @@ fn __action749< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46782,11 +46782,11 @@ fn __action750< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46817,7 +46817,7 @@ fn __action751< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46845,7 +46845,7 @@ fn __action752< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46873,7 +46873,7 @@ fn __action753< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46901,7 +46901,7 @@ fn __action754< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46929,7 +46929,7 @@ fn __action755< mode: Mode, __0: (TextSize, ast::Number, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46957,7 +46957,7 @@ fn __action756< mode: Mode, __0: (TextSize, ast::Identifier, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -46984,10 +46984,10 @@ fn __action757< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), + __1: (TextSize, core::option::Option>, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47016,11 +47016,11 @@ fn __action758< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47050,13 +47050,13 @@ fn __action759< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, core::option::Option>, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.0; let __end0 = __0.0; @@ -47088,12 +47088,12 @@ fn __action760< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, core::option::Option>, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.0; let __end0 = __0.0; @@ -47126,7 +47126,7 @@ fn __action761< __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47154,10 +47154,10 @@ fn __action762< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47186,11 +47186,11 @@ fn __action763< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47221,10 +47221,10 @@ fn __action764< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.2; let __end0 = __1.0; @@ -47254,10 +47254,10 @@ fn __action765< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, ast::ParenthesizedExpr)>>, TextSize), + __1: (TextSize, core::option::Option>, crate::parser::ParenthesizedExpr)>>, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47286,11 +47286,11 @@ fn __action766< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, (ast::ParenthesizedExpr, ast::ParenthesizedExpr), TextSize), + __1: (TextSize, (crate::parser::ParenthesizedExpr, crate::parser::ParenthesizedExpr), TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47320,10 +47320,10 @@ fn __action767< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47352,11 +47352,11 @@ fn __action768< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47387,7 +47387,7 @@ fn __action769< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47415,7 +47415,7 @@ fn __action770< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47443,7 +47443,7 @@ fn __action771< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47471,7 +47471,7 @@ fn __action772< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47497,10 +47497,10 @@ fn __action773< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Arguments, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47527,12 +47527,12 @@ fn __action774< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47561,11 +47561,11 @@ fn __action775< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, ast::Identifier, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47593,10 +47593,10 @@ fn __action776< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Arguments, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47623,12 +47623,12 @@ fn __action777< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47657,11 +47657,11 @@ fn __action778< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, ast::Identifier, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47690,9 +47690,9 @@ fn __action779< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47720,9 +47720,9 @@ fn __action780< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47875,10 +47875,10 @@ fn __action785< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), - __1: (TextSize, alloc::vec::Vec<(ast::CmpOp, ast::ParenthesizedExpr)>, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __1: (TextSize, alloc::vec::Vec<(ast::CmpOp, crate::parser::ParenthesizedExpr)>, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47905,10 +47905,10 @@ fn __action786< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), - __1: (TextSize, alloc::vec::Vec<(ast::CmpOp, ast::ParenthesizedExpr)>, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __1: (TextSize, alloc::vec::Vec<(ast::CmpOp, crate::parser::ParenthesizedExpr)>, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -47936,7 +47936,7 @@ fn __action787< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), __3: (TextSize, token::Tok, TextSize), ) -> ast::Decorator @@ -47968,7 +47968,7 @@ fn __action788< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -48056,7 +48056,7 @@ fn __action791< source_code: &str, mode: Mode, __0: (TextSize, ast::Identifier, TextSize), - __1: (TextSize, core::option::Option, TextSize), + __1: (TextSize, core::option::Option, TextSize), __2: (TextSize, TextSize, TextSize), ) -> ast::Parameter { @@ -48086,7 +48086,7 @@ fn __action792< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option, TextSize), + __1: (TextSize, core::option::Option, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Suite, TextSize), ) -> ast::ExceptHandler @@ -48118,7 +48118,7 @@ fn __action793< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, (ast::ParenthesizedExpr, ast::Identifier), TextSize), + __1: (TextSize, (crate::parser::ParenthesizedExpr, ast::Identifier), TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Suite, TextSize), ) -> ast::ExceptHandler @@ -48151,7 +48151,7 @@ fn __action794< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, ast::Suite, TextSize), ) -> ast::ExceptHandler @@ -48185,7 +48185,7 @@ fn __action795< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, (ast::ParenthesizedExpr, ast::Identifier), TextSize), + __2: (TextSize, (crate::parser::ParenthesizedExpr, ast::Identifier), TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, ast::Suite, TextSize), ) -> ast::ExceptHandler @@ -48217,11 +48217,11 @@ fn __action796< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -48249,11 +48249,11 @@ fn __action797< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -48281,8 +48281,8 @@ fn __action798< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), - __1: (TextSize, alloc::vec::Vec, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __1: (TextSize, alloc::vec::Vec, TextSize), __2: (TextSize, TextSize, TextSize), ) -> Result> { @@ -48311,9 +48311,9 @@ fn __action799< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), ) -> Result> { @@ -48343,10 +48343,10 @@ fn __action800< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), - __3: (TextSize, core::option::Option, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __3: (TextSize, core::option::Option, TextSize), __4: (TextSize, TextSize, TextSize), ) -> Result> { @@ -48504,7 +48504,7 @@ fn __action805< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, core::option::Option<(TextSize, ast::ConversionFlag)>, TextSize), __4: (TextSize, core::option::Option, TextSize), @@ -48542,7 +48542,7 @@ fn __action806< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, core::option::Option<(TextSize, ast::ConversionFlag)>, TextSize), __3: (TextSize, core::option::Option, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -48578,9 +48578,9 @@ fn __action807< source_code: &str, mode: Mode, __0: (TextSize, ast::UnaryOp, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -48608,9 +48608,9 @@ fn __action808< source_code: &str, mode: Mode, __0: (TextSize, ast::UnaryOp, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -48694,7 +48694,7 @@ fn __action811< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option, TextSize), + __1: (TextSize, core::option::Option, TextSize), __2: (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -48723,7 +48723,7 @@ fn __action812< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -48753,9 +48753,9 @@ fn __action813< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, ast::Suite, TextSize), __7: (TextSize, core::option::Option, TextSize), @@ -48792,9 +48792,9 @@ fn __action814< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, ast::Suite, TextSize), __6: (TextSize, core::option::Option, TextSize), @@ -48835,7 +48835,7 @@ fn __action815< __3: (TextSize, ast::Identifier, TextSize), __4: (TextSize, core::option::Option, TextSize), __5: (TextSize, ast::Parameters, TextSize), - __6: (TextSize, core::option::Option, TextSize), + __6: (TextSize, core::option::Option, TextSize), __7: (TextSize, token::Tok, TextSize), __8: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -48876,7 +48876,7 @@ fn __action816< __2: (TextSize, ast::Identifier, TextSize), __3: (TextSize, core::option::Option, TextSize), __4: (TextSize, ast::Parameters, TextSize), - __5: (TextSize, core::option::Option, TextSize), + __5: (TextSize, core::option::Option, TextSize), __6: (TextSize, token::Tok, TextSize), __7: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -48911,7 +48911,7 @@ fn __action817< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, core::option::Option>, TextSize), __2: (TextSize, TextSize, TextSize), ) -> (Option<(TextSize, TextSize, Option)>, ast::Expr) @@ -48943,7 +48943,7 @@ fn __action818< mode: Mode, __0: (TextSize, ast::Identifier, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), ) -> (Option<(TextSize, TextSize, Option)>, ast::Expr) { @@ -48974,7 +48974,7 @@ fn __action819< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), ) -> (Option<(TextSize, TextSize, Option)>, ast::Expr) { @@ -49004,7 +49004,7 @@ fn __action820< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), ) -> (Option<(TextSize, TextSize, Option)>, ast::Expr) { @@ -49033,10 +49033,10 @@ fn __action821< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -49063,9 +49063,9 @@ fn __action822< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -49091,10 +49091,10 @@ fn __action823< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -49121,9 +49121,9 @@ fn __action824< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -49208,10 +49208,10 @@ fn __action827< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Suite, TextSize), - __4: (TextSize, alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)>, TextSize), + __4: (TextSize, alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)>, TextSize), __5: (TextSize, core::option::Option<(TextSize, ast::Suite)>, TextSize), ) -> ast::Stmt { @@ -49491,7 +49491,7 @@ fn __action836< mode: Mode, __0: (TextSize, (IpyEscapeKind, String), TextSize), __1: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.0; let __end0 = __0.0; @@ -49545,7 +49545,7 @@ fn __action838< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, alloc::vec::Vec, TextSize), __2: (TextSize, TextSize, TextSize), ) -> Result> @@ -49580,9 +49580,9 @@ fn __action839< __2: (TextSize, TextSize, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, core::option::Option<(String, bool)>, TextSize), - __5: (TextSize, ast::ParenthesizedExpr, TextSize), + __5: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __6: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.0; let __end0 = __0.0; @@ -49707,7 +49707,7 @@ fn __action843< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, TextSize, TextSize), ) -> ast::Pattern { @@ -49735,7 +49735,7 @@ fn __action844< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, TextSize, TextSize), ) -> ast::Pattern { @@ -50306,7 +50306,7 @@ fn __action862< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -50344,7 +50344,7 @@ fn __action863< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -50396,7 +50396,7 @@ fn __action864< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -50448,7 +50448,7 @@ fn __action865< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, TextSize, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -50497,11 +50497,11 @@ fn __action866< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -50531,7 +50531,7 @@ fn __action867< mode: Mode, __0: (TextSize, ast::Identifier, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -50588,9 +50588,9 @@ fn __action869< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -50618,9 +50618,9 @@ fn __action870< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -50649,7 +50649,7 @@ fn __action871< mode: Mode, __0: (TextSize, ast::Number, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -50676,9 +50676,9 @@ fn __action872< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -50733,10 +50733,10 @@ fn __action874< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -50763,10 +50763,10 @@ fn __action875< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -52029,11 +52029,11 @@ fn __action916< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -52061,11 +52061,11 @@ fn __action917< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -52122,8 +52122,8 @@ fn __action919< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), - __2: (TextSize, core::option::Option, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __2: (TextSize, core::option::Option, TextSize), __3: (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -52351,11 +52351,11 @@ fn __action926< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -52383,11 +52383,11 @@ fn __action927< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -52417,10 +52417,10 @@ fn __action928< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), - __5: (TextSize, alloc::vec::Vec, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __5: (TextSize, alloc::vec::Vec, TextSize), __6: (TextSize, TextSize, TextSize), ) -> ast::Comprehension { @@ -52454,10 +52454,10 @@ fn __action929< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), - __4: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __4: (TextSize, alloc::vec::Vec, TextSize), __5: (TextSize, TextSize, TextSize), ) -> ast::Comprehension { @@ -52490,8 +52490,8 @@ fn __action930< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option, TextSize), -) -> Option + __1: (TextSize, core::option::Option, TextSize), +) -> Option { let __start0 = __0.0; let __end0 = __0.0; @@ -52518,9 +52518,9 @@ fn __action931< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -52578,7 +52578,7 @@ fn __action933< source_code: &str, mode: Mode, __0: (TextSize, ast::Identifier, TextSize), - __1: (TextSize, core::option::Option, TextSize), + __1: (TextSize, core::option::Option, TextSize), __2: (TextSize, TextSize, TextSize), ) -> ast::Parameter { @@ -52717,12 +52717,12 @@ fn __action938< >( source_code: &str, mode: Mode, - __0: (TextSize, core::option::Option, TextSize), + __0: (TextSize, core::option::Option, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, core::option::Option, TextSize), - __3: (TextSize, core::option::Option>, TextSize), + __2: (TextSize, core::option::Option, TextSize), + __3: (TextSize, core::option::Option>, TextSize), __4: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -52751,10 +52751,10 @@ fn __action939< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -52781,10 +52781,10 @@ fn __action940< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -52811,9 +52811,9 @@ fn __action941< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -52839,11 +52839,11 @@ fn __action942< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -52871,11 +52871,11 @@ fn __action943< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -52903,13 +52903,13 @@ fn __action944< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __5: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -52939,13 +52939,13 @@ fn __action945< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __5: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -53006,7 +53006,7 @@ fn __action947< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, alloc::vec::Vec, TextSize), __3: (TextSize, TextSize, TextSize), ) -> ast::Mod @@ -53177,7 +53177,7 @@ fn __action952< __1: (TextSize, ast::Expr, TextSize), __2: (TextSize, core::option::Option, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __5: (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -53210,7 +53210,7 @@ fn __action953< source_code: &str, mode: Mode, __0: (TextSize, ast::Identifier, TextSize), - __1: (TextSize, core::option::Option, TextSize), + __1: (TextSize, core::option::Option, TextSize), __2: (TextSize, TextSize, TextSize), ) -> ast::TypeParam { @@ -53366,7 +53366,7 @@ fn __action958< source_code: &str, mode: Mode, __0: (TextSize, ast::Identifier, TextSize), - __1: (TextSize, core::option::Option, TextSize), + __1: (TextSize, core::option::Option, TextSize), __2: (TextSize, TextSize, TextSize), ) -> ast::ParameterWithDefault { @@ -53452,7 +53452,7 @@ fn __action961< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Suite, TextSize), __4: (TextSize, core::option::Option, TextSize), @@ -53485,9 +53485,9 @@ fn __action962< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), ) -> ast::WithItem { @@ -53583,11 +53583,11 @@ fn __action965< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -53615,11 +53615,11 @@ fn __action966< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -53648,9 +53648,9 @@ fn __action967< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option, TextSize), + __1: (TextSize, core::option::Option, TextSize), __2: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -53679,9 +53679,9 @@ fn __action968< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -57182,8 +57182,8 @@ fn __action1079< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> core::option::Option + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> core::option::Option { let __start0 = __0.0; let __end0 = __1.2; @@ -57208,9 +57208,9 @@ fn __action1080< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -57240,7 +57240,7 @@ fn __action1081< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -57270,8 +57270,8 @@ fn __action1082< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> alloc::vec::Vec + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> alloc::vec::Vec { let __start0 = __0.0; let __end0 = __1.2; @@ -57295,10 +57295,10 @@ fn __action1083< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), + __0: (TextSize, alloc::vec::Vec, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> alloc::vec::Vec + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> alloc::vec::Vec { let __start0 = __1.0; let __end0 = __2.2; @@ -57324,12 +57324,12 @@ fn __action1084< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, core::option::Option>, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __2.2; let __end0 = __3.0; @@ -57360,13 +57360,13 @@ fn __action1085< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, core::option::Option>, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __3.0; let __end0 = __3.2; @@ -57396,11 +57396,11 @@ fn __action1086< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, core::option::Option>, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __2.2; let __end0 = __3.0; @@ -57430,12 +57430,12 @@ fn __action1087< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, core::option::Option>, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __3.0; let __end0 = __3.2; @@ -57464,12 +57464,12 @@ fn __action1088< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, core::option::Option>, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __2.2; let __end0 = __3.0; @@ -57500,13 +57500,13 @@ fn __action1089< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, core::option::Option>, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __3.0; let __end0 = __3.2; @@ -57536,11 +57536,11 @@ fn __action1090< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, core::option::Option>, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __2.2; let __end0 = __3.0; @@ -57570,12 +57570,12 @@ fn __action1091< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), - __3: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, core::option::Option>, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __3: (TextSize, alloc::vec::Vec, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __3.0; let __end0 = __3.2; @@ -57790,8 +57790,8 @@ fn __action1098< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> core::option::Option + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> core::option::Option { let __start0 = __0.0; let __end0 = __1.2; @@ -57822,7 +57822,7 @@ fn __action1099< __4: (TextSize, core::option::Option, TextSize), __5: (TextSize, ast::Parameters, TextSize), __6: (TextSize, token::Tok, TextSize), - __7: (TextSize, ast::ParenthesizedExpr, TextSize), + __7: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __8: (TextSize, token::Tok, TextSize), __9: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -57903,7 +57903,7 @@ fn __action1101< __3: (TextSize, core::option::Option, TextSize), __4: (TextSize, ast::Parameters, TextSize), __5: (TextSize, token::Tok, TextSize), - __6: (TextSize, ast::ParenthesizedExpr, TextSize), + __6: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __7: (TextSize, token::Tok, TextSize), __8: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -58030,8 +58030,8 @@ fn __action1105< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> core::option::Option + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> core::option::Option { let __start0 = __0.0; let __end0 = __1.2; @@ -58057,7 +58057,7 @@ fn __action1106< mode: Mode, __0: (TextSize, ast::Identifier, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), ) -> ast::Parameter { @@ -58115,7 +58115,7 @@ fn __action1108< mode: Mode, __0: (TextSize, ast::Identifier, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), ) -> ast::TypeParam { @@ -58173,7 +58173,7 @@ fn __action1110< mode: Mode, __0: (TextSize, ast::Identifier, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), ) -> ast::ParameterWithDefault { @@ -58230,8 +58230,8 @@ fn __action1112< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> core::option::Option + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> core::option::Option { let __start0 = __0.0; let __end0 = __1.2; @@ -58257,7 +58257,7 @@ fn __action1113< mode: Mode, __0: (TextSize, ast::Identifier, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, TextSize, TextSize), ) -> ast::Parameter { @@ -58414,7 +58414,7 @@ fn __action1119< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), ) -> ast::Mod { @@ -58444,7 +58444,7 @@ fn __action1120< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, alloc::vec::Vec, TextSize), __3: (TextSize, TextSize, TextSize), ) -> ast::Mod @@ -58645,9 +58645,9 @@ fn __action1127< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, ast::Suite, TextSize), __7: (TextSize, token::Tok, TextSize), @@ -58687,9 +58687,9 @@ fn __action1128< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -58724,9 +58724,9 @@ fn __action1129< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, ast::Suite, TextSize), __6: (TextSize, token::Tok, TextSize), @@ -58764,9 +58764,9 @@ fn __action1130< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -58952,7 +58952,7 @@ fn __action1135< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Suite, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -58988,7 +58988,7 @@ fn __action1136< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -59394,8 +59394,8 @@ fn __action1147< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> core::option::Option + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> core::option::Option { let __start0 = __0.0; let __end0 = __1.2; @@ -59420,9 +59420,9 @@ fn __action1148< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -59452,7 +59452,7 @@ fn __action1149< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, TextSize, TextSize), ) -> ast::Stmt { @@ -59482,10 +59482,10 @@ fn __action1150< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Suite, TextSize), -) -> alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)> +) -> alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)> { let __start0 = __0.0; let __end0 = __3.2; @@ -59511,12 +59511,12 @@ fn __action1151< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)>, TextSize), + __0: (TextSize, alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)>, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, ast::Suite, TextSize), -) -> alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)> +) -> alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)> { let __start0 = __1.0; let __end0 = __4.2; @@ -59544,7 +59544,7 @@ fn __action1152< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Suite, TextSize), __4: (TextSize, core::option::Option<(TextSize, ast::Suite)>, TextSize), @@ -59578,10 +59578,10 @@ fn __action1153< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Suite, TextSize), - __4: (TextSize, alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)>, TextSize), + __4: (TextSize, alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)>, TextSize), __5: (TextSize, core::option::Option<(TextSize, ast::Suite)>, TextSize), ) -> ast::Stmt { @@ -59640,7 +59640,7 @@ fn __action1155< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Suite, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -59676,7 +59676,7 @@ fn __action1156< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -59708,10 +59708,10 @@ fn __action1157< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Suite, TextSize), - __4: (TextSize, alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)>, TextSize), + __4: (TextSize, alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)>, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, token::Tok, TextSize), __7: (TextSize, ast::Suite, TextSize), @@ -59746,10 +59746,10 @@ fn __action1158< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Suite, TextSize), - __4: (TextSize, alloc::vec::Vec<(TextSize, ast::ParenthesizedExpr, ast::Suite)>, TextSize), + __4: (TextSize, alloc::vec::Vec<(TextSize, crate::parser::ParenthesizedExpr, ast::Suite)>, TextSize), ) -> ast::Stmt { let __start0 = __4.2; @@ -59779,9 +59779,9 @@ fn __action1159< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> alloc::vec::Vec +) -> alloc::vec::Vec { let __start0 = __0.0; let __end0 = __1.2; @@ -59805,10 +59805,10 @@ fn __action1160< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> alloc::vec::Vec +) -> alloc::vec::Vec { let __start0 = __1.0; let __end0 = __2.2; @@ -59939,9 +59939,9 @@ fn __action1165< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> alloc::vec::Vec +) -> alloc::vec::Vec { let __start0 = __0.0; let __end0 = __1.2; @@ -59965,10 +59965,10 @@ fn __action1166< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> alloc::vec::Vec +) -> alloc::vec::Vec { let __start0 = __1.0; let __end0 = __2.2; @@ -59993,9 +59993,9 @@ fn __action1167< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> core::option::Option> +) -> core::option::Option> { let __start0 = __0.0; let __end0 = __1.2; @@ -60020,13 +60020,13 @@ fn __action1168< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __1.0; let __end0 = __2.2; @@ -60056,11 +60056,11 @@ fn __action1169< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.2; let __end0 = __1.0; @@ -60090,14 +60090,14 @@ fn __action1170< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), - __4: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __4: (TextSize, alloc::vec::Vec, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, token::Tok, TextSize), __7: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __1.0; let __end0 = __2.2; @@ -60128,12 +60128,12 @@ fn __action1171< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.2; let __end0 = __1.0; @@ -60164,12 +60164,12 @@ fn __action1172< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __1.0; let __end0 = __2.2; @@ -60198,10 +60198,10 @@ fn __action1173< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.2; let __end0 = __1.0; @@ -60230,13 +60230,13 @@ fn __action1174< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), - __4: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __4: (TextSize, alloc::vec::Vec, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __1.0; let __end0 = __2.2; @@ -60266,11 +60266,11 @@ fn __action1175< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.2; let __end0 = __1.0; @@ -60300,13 +60300,13 @@ fn __action1176< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __1.0; let __end0 = __2.2; @@ -60336,11 +60336,11 @@ fn __action1177< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.2; let __end0 = __1.0; @@ -60370,14 +60370,14 @@ fn __action1178< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), - __4: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __4: (TextSize, alloc::vec::Vec, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, token::Tok, TextSize), __7: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __1.0; let __end0 = __2.2; @@ -60408,12 +60408,12 @@ fn __action1179< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.2; let __end0 = __1.0; @@ -60444,12 +60444,12 @@ fn __action1180< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __1.0; let __end0 = __2.2; @@ -60478,10 +60478,10 @@ fn __action1181< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.2; let __end0 = __1.0; @@ -60510,13 +60510,13 @@ fn __action1182< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), - __4: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __4: (TextSize, alloc::vec::Vec, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __1.0; let __end0 = __2.2; @@ -60546,11 +60546,11 @@ fn __action1183< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.2; let __end0 = __1.0; @@ -61220,7 +61220,7 @@ fn __action1206< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Identifier, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -61255,7 +61255,7 @@ fn __action1207< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, ast::Identifier, TextSize), __5: (TextSize, token::Tok, TextSize), @@ -61289,7 +61289,7 @@ fn __action1208< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, token::Tok, TextSize), ) -> Vec { @@ -61316,7 +61316,7 @@ fn __action1209< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, token::Tok, TextSize), ) -> Vec @@ -61346,7 +61346,7 @@ fn __action1210< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), ) -> Vec { @@ -61373,7 +61373,7 @@ fn __action1211< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, token::Tok, TextSize), ) -> core::option::Option> { @@ -61400,7 +61400,7 @@ fn __action1212< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::WithItem, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -61466,7 +61466,7 @@ fn __action1214< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::WithItem, TextSize), __4: (TextSize, alloc::vec::Vec, TextSize), @@ -61536,7 +61536,7 @@ fn __action1216< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::WithItem, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -61598,7 +61598,7 @@ fn __action1218< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::WithItem, TextSize), __4: (TextSize, alloc::vec::Vec, TextSize), @@ -61664,8 +61664,8 @@ fn __action1220< source_code: &str, mode: Mode, __0: (TextSize, ast::CmpOp, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> alloc::vec::Vec<(ast::CmpOp, ast::ParenthesizedExpr)> + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> alloc::vec::Vec<(ast::CmpOp, crate::parser::ParenthesizedExpr)> { let __start0 = __0.0; let __end0 = __1.2; @@ -61689,10 +61689,10 @@ fn __action1221< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec<(ast::CmpOp, ast::ParenthesizedExpr)>, TextSize), + __0: (TextSize, alloc::vec::Vec<(ast::CmpOp, crate::parser::ParenthesizedExpr)>, TextSize), __1: (TextSize, ast::CmpOp, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> alloc::vec::Vec<(ast::CmpOp, ast::ParenthesizedExpr)> + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> alloc::vec::Vec<(ast::CmpOp, crate::parser::ParenthesizedExpr)> { let __start0 = __1.0; let __end0 = __2.2; @@ -61889,10 +61889,10 @@ fn __action1228< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -61919,10 +61919,10 @@ fn __action1229< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -61949,10 +61949,10 @@ fn __action1230< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -61979,9 +61979,9 @@ fn __action1231< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __0: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -62007,9 +62007,9 @@ fn __action1232< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __0: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -62065,10 +62065,10 @@ fn __action1234< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -62095,10 +62095,10 @@ fn __action1235< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -62156,9 +62156,9 @@ fn __action1237< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Stmt { let __start0 = __3.2; @@ -62188,7 +62188,7 @@ fn __action1238< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Stmt { let __start0 = __1.2; @@ -62216,7 +62216,7 @@ fn __action1239< source_code: &str, mode: Mode, __0: (TextSize, ast::Number, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -62242,7 +62242,7 @@ fn __action1240< source_code: &str, mode: Mode, __0: (TextSize, ast::Identifier, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -62268,9 +62268,9 @@ fn __action1241< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), + __1: (TextSize, core::option::Option>, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -62298,10 +62298,10 @@ fn __action1242< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __3.2; let __end0 = __3.2; @@ -62330,10 +62330,10 @@ fn __action1243< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __3.2; let __end0 = __3.2; @@ -62362,9 +62362,9 @@ fn __action1244< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -62392,12 +62392,12 @@ fn __action1245< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __5.2; let __end0 = __5.2; @@ -62428,10 +62428,10 @@ fn __action1246< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __3.2; let __end0 = __3.2; @@ -62460,13 +62460,13 @@ fn __action1247< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), - __4: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __4: (TextSize, alloc::vec::Vec, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __6.2; let __end0 = __6.2; @@ -62498,11 +62498,11 @@ fn __action1248< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __4.2; let __end0 = __4.2; @@ -62532,11 +62532,11 @@ fn __action1249< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __4.2; let __end0 = __4.2; @@ -62566,9 +62566,9 @@ fn __action1250< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __2.2; let __end0 = __2.2; @@ -62596,12 +62596,12 @@ fn __action1251< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), - __4: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __4: (TextSize, alloc::vec::Vec, TextSize), __5: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __5.2; let __end0 = __5.2; @@ -62632,10 +62632,10 @@ fn __action1252< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __3.2; let __end0 = __3.2; @@ -62665,7 +62665,7 @@ fn __action1253< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -62692,9 +62692,9 @@ fn __action1254< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -62722,10 +62722,10 @@ fn __action1255< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __3.2; let __end0 = __3.2; @@ -62755,9 +62755,9 @@ fn __action1256< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __3.2; let __end0 = __3.2; @@ -62786,9 +62786,9 @@ fn __action1257< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, ast::ParenthesizedExpr)>>, TextSize), + __1: (TextSize, core::option::Option>, crate::parser::ParenthesizedExpr)>>, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -62816,10 +62816,10 @@ fn __action1258< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, (ast::ParenthesizedExpr, ast::ParenthesizedExpr), TextSize), + __1: (TextSize, (crate::parser::ParenthesizedExpr, crate::parser::ParenthesizedExpr), TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __3.2; let __end0 = __3.2; @@ -62848,9 +62848,9 @@ fn __action1259< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -62878,10 +62878,10 @@ fn __action1260< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __3.2; let __end0 = __3.2; @@ -62910,7 +62910,7 @@ fn __action1261< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -62936,7 +62936,7 @@ fn __action1262< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -62962,7 +62962,7 @@ fn __action1263< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -62988,7 +62988,7 @@ fn __action1264< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -63014,7 +63014,7 @@ fn __action1265< source_code: &str, mode: Mode, __0: (TextSize, ast::Number, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -63040,7 +63040,7 @@ fn __action1266< source_code: &str, mode: Mode, __0: (TextSize, ast::Identifier, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -63066,9 +63066,9 @@ fn __action1267< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, TextSize), + __1: (TextSize, core::option::Option>, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -63096,10 +63096,10 @@ fn __action1268< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __3.2; let __end0 = __3.2; @@ -63128,12 +63128,12 @@ fn __action1269< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __5.2; let __end0 = __5.2; @@ -63164,10 +63164,10 @@ fn __action1270< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __3.2; let __end0 = __3.2; @@ -63196,13 +63196,13 @@ fn __action1271< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), - __4: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __4: (TextSize, alloc::vec::Vec, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __6.2; let __end0 = __6.2; @@ -63234,11 +63234,11 @@ fn __action1272< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __4.2; let __end0 = __4.2; @@ -63268,11 +63268,11 @@ fn __action1273< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __4.2; let __end0 = __4.2; @@ -63302,9 +63302,9 @@ fn __action1274< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __2.2; let __end0 = __2.2; @@ -63332,12 +63332,12 @@ fn __action1275< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), - __4: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __4: (TextSize, alloc::vec::Vec, TextSize), __5: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __5.2; let __end0 = __5.2; @@ -63368,10 +63368,10 @@ fn __action1276< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), - __2: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __2: (TextSize, alloc::vec::Vec, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __3.2; let __end0 = __3.2; @@ -63401,7 +63401,7 @@ fn __action1277< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -63428,9 +63428,9 @@ fn __action1278< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -63458,10 +63458,10 @@ fn __action1279< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __3.2; let __end0 = __3.2; @@ -63491,9 +63491,9 @@ fn __action1280< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __3.2; let __end0 = __3.2; @@ -63522,9 +63522,9 @@ fn __action1281< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option>, ast::ParenthesizedExpr)>>, TextSize), + __1: (TextSize, core::option::Option>, crate::parser::ParenthesizedExpr)>>, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -63552,10 +63552,10 @@ fn __action1282< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, (ast::ParenthesizedExpr, ast::ParenthesizedExpr), TextSize), + __1: (TextSize, (crate::parser::ParenthesizedExpr, crate::parser::ParenthesizedExpr), TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __3.2; let __end0 = __3.2; @@ -63584,9 +63584,9 @@ fn __action1283< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -63614,10 +63614,10 @@ fn __action1284< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, Vec, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __3.2; let __end0 = __3.2; @@ -63646,7 +63646,7 @@ fn __action1285< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -63672,7 +63672,7 @@ fn __action1286< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -63698,7 +63698,7 @@ fn __action1287< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -63724,7 +63724,7 @@ fn __action1288< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -63749,9 +63749,9 @@ fn __action1289< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Arguments, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -63777,11 +63777,11 @@ fn __action1290< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __3.2; let __end0 = __3.2; @@ -63809,10 +63809,10 @@ fn __action1291< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, ast::Identifier, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -63839,9 +63839,9 @@ fn __action1292< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Arguments, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -63867,11 +63867,11 @@ fn __action1293< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __3.2; let __end0 = __3.2; @@ -63899,10 +63899,10 @@ fn __action1294< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, ast::Identifier, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -63930,8 +63930,8 @@ fn __action1295< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -63958,8 +63958,8 @@ fn __action1296< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -64067,9 +64067,9 @@ fn __action1300< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), - __1: (TextSize, alloc::vec::Vec<(ast::CmpOp, ast::ParenthesizedExpr)>, TextSize), -) -> ast::ParenthesizedExpr + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __1: (TextSize, alloc::vec::Vec<(ast::CmpOp, crate::parser::ParenthesizedExpr)>, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -64095,9 +64095,9 @@ fn __action1301< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), - __1: (TextSize, alloc::vec::Vec<(ast::CmpOp, ast::ParenthesizedExpr)>, TextSize), -) -> ast::ParenthesizedExpr + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __1: (TextSize, alloc::vec::Vec<(ast::CmpOp, crate::parser::ParenthesizedExpr)>, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -64124,7 +64124,7 @@ fn __action1302< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), ) -> ast::Decorator { @@ -64154,7 +64154,7 @@ fn __action1303< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), ) -> ast::Stmt { let __start0 = __1.2; @@ -64237,7 +64237,7 @@ fn __action1306< mode: Mode, __0: (TextSize, ast::Identifier, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Parameter { let __start0 = __2.2; @@ -64291,10 +64291,10 @@ fn __action1308< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -64321,10 +64321,10 @@ fn __action1309< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -64351,8 +64351,8 @@ fn __action1310< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), - __1: (TextSize, alloc::vec::Vec, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __1: (TextSize, alloc::vec::Vec, TextSize), ) -> Result> { let __start0 = __1.2; @@ -64379,9 +64379,9 @@ fn __action1311< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> Result> { let __start0 = __2.2; @@ -64409,10 +64409,10 @@ fn __action1312< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), - __3: (TextSize, core::option::Option, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __3: (TextSize, core::option::Option, TextSize), ) -> Result> { let __start0 = __3.2; @@ -64524,7 +64524,7 @@ fn __action1316< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, core::option::Option<(TextSize, ast::ConversionFlag)>, TextSize), __4: (TextSize, core::option::Option, TextSize), @@ -64560,7 +64560,7 @@ fn __action1317< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, core::option::Option<(TextSize, ast::ConversionFlag)>, TextSize), __3: (TextSize, core::option::Option, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -64594,8 +64594,8 @@ fn __action1318< source_code: &str, mode: Mode, __0: (TextSize, ast::UnaryOp, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -64622,8 +64622,8 @@ fn __action1319< source_code: &str, mode: Mode, __0: (TextSize, ast::UnaryOp, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -64702,7 +64702,7 @@ fn __action1322< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option, TextSize), + __1: (TextSize, core::option::Option, TextSize), ) -> ast::Stmt { let __start0 = __1.2; @@ -64729,7 +64729,7 @@ fn __action1323< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Stmt { let __start0 = __0.2; @@ -64755,7 +64755,7 @@ fn __action1324< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, core::option::Option>, TextSize), ) -> (Option<(TextSize, TextSize, Option)>, ast::Expr) { @@ -64785,7 +64785,7 @@ fn __action1325< mode: Mode, __0: (TextSize, ast::Identifier, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> (Option<(TextSize, TextSize, Option)>, ast::Expr) { let __start0 = __2.2; @@ -64814,7 +64814,7 @@ fn __action1326< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> (Option<(TextSize, TextSize, Option)>, ast::Expr) { let __start0 = __1.2; @@ -64842,7 +64842,7 @@ fn __action1327< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> (Option<(TextSize, TextSize, Option)>, ast::Expr) { let __start0 = __1.2; @@ -64869,9 +64869,9 @@ fn __action1328< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -64897,8 +64897,8 @@ fn __action1329< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), -) -> ast::ParenthesizedExpr + __0: (TextSize, Vec, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -64923,9 +64923,9 @@ fn __action1330< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -64951,8 +64951,8 @@ fn __action1331< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), -) -> ast::ParenthesizedExpr + __0: (TextSize, Vec, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -65318,7 +65318,7 @@ fn __action1344< source_code: &str, mode: Mode, __0: (TextSize, (IpyEscapeKind, String), TextSize), -) -> Result> +) -> Result> { let __start0 = __0.2; let __end0 = __0.2; @@ -65369,7 +65369,7 @@ fn __action1346< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, alloc::vec::Vec, TextSize), ) -> Result> { @@ -65401,8 +65401,8 @@ fn __action1347< __1: (TextSize, core::option::Option, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, core::option::Option<(String, bool)>, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Result> + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Result> { let __start0 = __1.2; let __end0 = __2.0; @@ -65519,7 +65519,7 @@ fn __action1351< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Pattern { let __start0 = __0.2; @@ -65545,7 +65545,7 @@ fn __action1352< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Pattern { let __start0 = __0.2; @@ -66048,7 +66048,7 @@ fn __action1369< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -66088,7 +66088,7 @@ fn __action1370< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -66128,7 +66128,7 @@ fn __action1371< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -66165,10 +66165,10 @@ fn __action1372< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -66196,7 +66196,7 @@ fn __action1373< source_code: &str, mode: Mode, __0: (TextSize, ast::Identifier, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -66250,8 +66250,8 @@ fn __action1375< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -66278,8 +66278,8 @@ fn __action1376< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -66306,7 +66306,7 @@ fn __action1377< source_code: &str, mode: Mode, __0: (TextSize, ast::Number, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -66332,8 +66332,8 @@ fn __action1378< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -66385,9 +66385,9 @@ fn __action1380< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __0: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -66413,9 +66413,9 @@ fn __action1381< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __0: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -66443,7 +66443,7 @@ fn __action1382< mode: Mode, __0: (TextSize, ast::ParameterWithDefault, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::ParameterWithDefault { let __start0 = __2.2; @@ -66473,7 +66473,7 @@ fn __action1383< mode: Mode, __0: (TextSize, ast::ParameterWithDefault, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::ParameterWithDefault { let __start0 = __2.2; @@ -69341,10 +69341,10 @@ fn __action1473< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -69371,10 +69371,10 @@ fn __action1474< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -69428,9 +69428,9 @@ fn __action1476< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Stmt { let __start0 = __3.2; @@ -69460,7 +69460,7 @@ fn __action1477< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Stmt { let __start0 = __1.2; @@ -69673,10 +69673,10 @@ fn __action1484< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -69703,10 +69703,10 @@ fn __action1485< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -69735,10 +69735,10 @@ fn __action1486< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), - __5: (TextSize, alloc::vec::Vec, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __5: (TextSize, alloc::vec::Vec, TextSize), ) -> ast::Comprehension { let __start0 = __5.2; @@ -69770,10 +69770,10 @@ fn __action1487< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), - __4: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __4: (TextSize, alloc::vec::Vec, TextSize), ) -> ast::Comprehension { let __start0 = __4.2; @@ -69804,8 +69804,8 @@ fn __action1488< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -69861,7 +69861,7 @@ fn __action1490< mode: Mode, __0: (TextSize, ast::Identifier, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Parameter { let __start0 = __2.2; @@ -69993,11 +69993,11 @@ fn __action1495< >( source_code: &str, mode: Mode, - __0: (TextSize, core::option::Option, TextSize), + __0: (TextSize, core::option::Option, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, core::option::Option, TextSize), - __3: (TextSize, core::option::Option>, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, core::option::Option, TextSize), + __3: (TextSize, core::option::Option>, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __3.2; let __end0 = __3.2; @@ -70025,9 +70025,9 @@ fn __action1496< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -70053,9 +70053,9 @@ fn __action1497< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), + __0: (TextSize, Vec, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -70081,8 +70081,8 @@ fn __action1498< >( source_code: &str, mode: Mode, - __0: (TextSize, Vec, TextSize), -) -> ast::ParenthesizedExpr + __0: (TextSize, Vec, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -70107,10 +70107,10 @@ fn __action1499< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -70137,10 +70137,10 @@ fn __action1500< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -70167,12 +70167,12 @@ fn __action1501< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __4.2; let __end0 = __4.2; @@ -70201,12 +70201,12 @@ fn __action1502< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __4.2; let __end0 = __4.2; @@ -70264,7 +70264,7 @@ fn __action1504< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Mod { let __start0 = __1.2; @@ -70292,7 +70292,7 @@ fn __action1505< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, alloc::vec::Vec, TextSize), ) -> ast::Mod { @@ -70655,7 +70655,7 @@ fn __action1515< __1: (TextSize, ast::Expr, TextSize), __2: (TextSize, core::option::Option, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Stmt { let __start0 = __4.2; @@ -70687,7 +70687,7 @@ fn __action1516< mode: Mode, __0: (TextSize, ast::Identifier, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::TypeParam { let __start0 = __2.2; @@ -70861,7 +70861,7 @@ fn __action1522< mode: Mode, __0: (TextSize, ast::Identifier, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::ParameterWithDefault { let __start0 = __2.2; @@ -70967,9 +70967,9 @@ fn __action1526< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::WithItem { let __start0 = __2.2; @@ -70997,10 +70997,10 @@ fn __action1527< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -71027,10 +71027,10 @@ fn __action1528< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -71058,8 +71058,8 @@ fn __action1529< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, core::option::Option, TextSize), -) -> ast::ParenthesizedExpr + __1: (TextSize, core::option::Option, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.2; let __end0 = __1.2; @@ -71087,8 +71087,8 @@ fn __action1530< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -71187,7 +71187,7 @@ fn __action1533< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> Result> { let __start0 = __0.2; @@ -71213,8 +71213,8 @@ fn __action1534< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), - __1: (TextSize, alloc::vec::Vec, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __1: (TextSize, alloc::vec::Vec, TextSize), ) -> Result> { let __start0 = __1.0; @@ -71239,10 +71239,10 @@ fn __action1535< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> Result> { let __start0 = __3.0; @@ -71269,9 +71269,9 @@ fn __action1536< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> Result> { let __start0 = __2.2; @@ -71731,7 +71731,7 @@ fn __action1553< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, Vec, TextSize), ) -> (Option<(TextSize, TextSize, Option)>, ast::Expr) { @@ -71757,7 +71757,7 @@ fn __action1554< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> (Option<(TextSize, TextSize, Option)>, ast::Expr) { let __start0 = __0.2; @@ -71785,9 +71785,9 @@ fn __action1555< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Comprehension { let __start0 = __4.2; @@ -71819,10 +71819,10 @@ fn __action1556< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), - __5: (TextSize, alloc::vec::Vec, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __5: (TextSize, alloc::vec::Vec, TextSize), ) -> ast::Comprehension { let __start0 = __5.0; @@ -71852,9 +71852,9 @@ fn __action1557< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Comprehension { let __start0 = __3.2; @@ -71884,10 +71884,10 @@ fn __action1558< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), - __4: (TextSize, alloc::vec::Vec, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __4: (TextSize, alloc::vec::Vec, TextSize), ) -> ast::Comprehension { let __start0 = __4.0; @@ -72061,7 +72061,7 @@ fn __action1563< __3: (TextSize, core::option::Option, TextSize), __4: (TextSize, ast::Parameters, TextSize), __5: (TextSize, token::Tok, TextSize), - __6: (TextSize, ast::ParenthesizedExpr, TextSize), + __6: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __7: (TextSize, token::Tok, TextSize), __8: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -72104,7 +72104,7 @@ fn __action1564< __4: (TextSize, core::option::Option, TextSize), __5: (TextSize, ast::Parameters, TextSize), __6: (TextSize, token::Tok, TextSize), - __7: (TextSize, ast::ParenthesizedExpr, TextSize), + __7: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __8: (TextSize, token::Tok, TextSize), __9: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -72220,7 +72220,7 @@ fn __action1567< __2: (TextSize, core::option::Option, TextSize), __3: (TextSize, ast::Parameters, TextSize), __4: (TextSize, token::Tok, TextSize), - __5: (TextSize, ast::ParenthesizedExpr, TextSize), + __5: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __6: (TextSize, token::Tok, TextSize), __7: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -72261,7 +72261,7 @@ fn __action1568< __3: (TextSize, core::option::Option, TextSize), __4: (TextSize, ast::Parameters, TextSize), __5: (TextSize, token::Tok, TextSize), - __6: (TextSize, ast::ParenthesizedExpr, TextSize), + __6: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __7: (TextSize, token::Tok, TextSize), __8: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -72368,9 +72368,9 @@ fn __action1571< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec<(Option>, ast::ParenthesizedExpr)>, TextSize), + __1: (TextSize, Vec<(Option>, crate::parser::ParenthesizedExpr)>, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.0; let __end0 = __1.2; @@ -72397,7 +72397,7 @@ fn __action1572< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __1.0; @@ -72424,9 +72424,9 @@ fn __action1573< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec<(Option>, ast::ParenthesizedExpr)>, TextSize), + __1: (TextSize, Vec<(Option>, crate::parser::ParenthesizedExpr)>, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.0; let __end0 = __1.2; @@ -72453,7 +72453,7 @@ fn __action1574< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __1.0; @@ -72532,7 +72532,7 @@ fn __action1577< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, (TextSize, ast::ConversionFlag), TextSize), __4: (TextSize, core::option::Option, TextSize), @@ -72566,7 +72566,7 @@ fn __action1578< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, core::option::Option, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -72600,7 +72600,7 @@ fn __action1579< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, (TextSize, ast::ConversionFlag), TextSize), __3: (TextSize, core::option::Option, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -72632,7 +72632,7 @@ fn __action1580< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, core::option::Option, TextSize), __3: (TextSize, token::Tok, TextSize), ) -> Result> @@ -72664,7 +72664,7 @@ fn __action1581< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, (TextSize, ast::ConversionFlag), TextSize), __4: (TextSize, ast::Expr, TextSize), @@ -72698,7 +72698,7 @@ fn __action1582< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, (TextSize, ast::ConversionFlag), TextSize), __4: (TextSize, token::Tok, TextSize), @@ -72732,7 +72732,7 @@ fn __action1583< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Expr, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -72764,7 +72764,7 @@ fn __action1584< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, token::Tok, TextSize), ) -> Result> @@ -72796,7 +72796,7 @@ fn __action1585< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, (TextSize, ast::ConversionFlag), TextSize), __3: (TextSize, ast::Expr, TextSize), __4: (TextSize, token::Tok, TextSize), @@ -72828,7 +72828,7 @@ fn __action1586< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, (TextSize, ast::ConversionFlag), TextSize), __3: (TextSize, token::Tok, TextSize), ) -> Result> @@ -72860,7 +72860,7 @@ fn __action1587< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, ast::Expr, TextSize), __3: (TextSize, token::Tok, TextSize), ) -> Result> @@ -72890,7 +72890,7 @@ fn __action1588< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), ) -> Result> { @@ -73302,9 +73302,9 @@ fn __action1603< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.0; let __end0 = __1.2; @@ -73331,7 +73331,7 @@ fn __action1604< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __1.0; @@ -73358,9 +73358,9 @@ fn __action1605< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Vec, TextSize), + __1: (TextSize, Vec, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.0; let __end0 = __1.2; @@ -73387,7 +73387,7 @@ fn __action1606< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __1.0; @@ -77633,8 +77633,8 @@ fn __action1727< __1: (TextSize, ast::Parameters, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, core::option::Option<(String, bool)>, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Result> + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Result> { let __start0 = __1.0; let __end0 = __1.2; @@ -77664,8 +77664,8 @@ fn __action1728< __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, core::option::Option<(String, bool)>, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Result> + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Result> { let __start0 = __0.2; let __end0 = __1.0; @@ -77693,11 +77693,11 @@ fn __action1729< >( source_code: &str, mode: Mode, - __0: (TextSize, core::option::Option, TextSize), + __0: (TextSize, core::option::Option, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, core::option::Option, TextSize), - __3: (TextSize, Option, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, core::option::Option, TextSize), + __3: (TextSize, Option, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __3.0; let __end0 = __3.2; @@ -77723,10 +77723,10 @@ fn __action1730< >( source_code: &str, mode: Mode, - __0: (TextSize, core::option::Option, TextSize), + __0: (TextSize, core::option::Option, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, core::option::Option, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, core::option::Option, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __2.2; let __end0 = __2.2; @@ -77754,7 +77754,7 @@ fn __action1731< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, ast::Suite, TextSize), ) -> ast::ExceptHandler @@ -77814,8 +77814,8 @@ fn __action1733< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Option + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Option { let __start0 = __1.0; let __end0 = __1.2; @@ -77840,7 +77840,7 @@ fn __action1734< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), -) -> Option +) -> Option { let __start0 = __0.2; let __end0 = __0.2; @@ -77865,11 +77865,11 @@ fn __action1735< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), - __3: (TextSize, Option, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __3: (TextSize, Option, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.2; @@ -77903,10 +77903,10 @@ fn __action1736< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, Option, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, Option, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.2; @@ -77942,9 +77942,9 @@ fn __action1737< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), - __2: (TextSize, Option, TextSize), -) -> ast::ParenthesizedExpr + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __2: (TextSize, Option, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -77980,8 +77980,8 @@ fn __action1738< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, Option, TextSize), -) -> ast::ParenthesizedExpr + __1: (TextSize, Option, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -78017,10 +78017,10 @@ fn __action1739< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.2; @@ -78053,9 +78053,9 @@ fn __action1740< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.2; @@ -78090,8 +78090,8 @@ fn __action1741< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -78126,7 +78126,7 @@ fn __action1742< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.0; @@ -78163,9 +78163,9 @@ fn __action1743< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, ast::Suite, TextSize), __7: (TextSize, token::Tok, TextSize), @@ -78205,9 +78205,9 @@ fn __action1744< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -78240,9 +78240,9 @@ fn __action1745< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, ast::Suite, TextSize), __6: (TextSize, token::Tok, TextSize), @@ -78280,9 +78280,9 @@ fn __action1746< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -78313,8 +78313,8 @@ fn __action1747< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> core::option::Option + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> core::option::Option { let __start0 = __0.0; let __end0 = __0.2; @@ -78337,8 +78337,8 @@ fn __action1748< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.2; @@ -78361,8 +78361,8 @@ fn __action1749< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.0; let __end0 = __0.2; @@ -78386,7 +78386,7 @@ fn __action1750< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Mod { let __start0 = __1.0; @@ -78412,7 +78412,7 @@ fn __action1751< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, alloc::vec::Vec, TextSize), ) -> ast::Mod { @@ -78440,7 +78440,7 @@ fn __action1752< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Stmt { let __start0 = __1.0; @@ -78492,8 +78492,8 @@ fn __action1754< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> ast::ParenthesizedExpr + __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> crate::parser::ParenthesizedExpr { let __start0 = __1.0; let __end0 = __1.2; @@ -78518,7 +78518,7 @@ fn __action1755< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), -) -> ast::ParenthesizedExpr +) -> crate::parser::ParenthesizedExpr { let __start0 = __0.2; let __end0 = __0.2; @@ -78543,7 +78543,7 @@ fn __action1756< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> Result> { let __start0 = __0.0; @@ -78567,8 +78567,8 @@ fn __action1757< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), - __1: (TextSize, alloc::vec::Vec, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), + __1: (TextSize, alloc::vec::Vec, TextSize), ) -> Result> { let __start0 = __0.0; @@ -78593,9 +78593,9 @@ fn __action1758< >( source_code: &str, mode: Mode, - __0: (TextSize, ast::ParenthesizedExpr, TextSize), + __0: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __1: (TextSize, ast::Operator, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> Result> { let __start0 = __0.0; @@ -78899,7 +78899,7 @@ fn __action1767< __3: (TextSize, ast::TypeParams, TextSize), __4: (TextSize, ast::Parameters, TextSize), __5: (TextSize, token::Tok, TextSize), - __6: (TextSize, ast::ParenthesizedExpr, TextSize), + __6: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __7: (TextSize, token::Tok, TextSize), __8: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -78938,7 +78938,7 @@ fn __action1768< __2: (TextSize, ast::Identifier, TextSize), __3: (TextSize, ast::Parameters, TextSize), __4: (TextSize, token::Tok, TextSize), - __5: (TextSize, ast::ParenthesizedExpr, TextSize), + __5: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __6: (TextSize, token::Tok, TextSize), __7: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -78980,7 +78980,7 @@ fn __action1769< __4: (TextSize, ast::TypeParams, TextSize), __5: (TextSize, ast::Parameters, TextSize), __6: (TextSize, token::Tok, TextSize), - __7: (TextSize, ast::ParenthesizedExpr, TextSize), + __7: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __8: (TextSize, token::Tok, TextSize), __9: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -79021,7 +79021,7 @@ fn __action1770< __3: (TextSize, ast::Identifier, TextSize), __4: (TextSize, ast::Parameters, TextSize), __5: (TextSize, token::Tok, TextSize), - __6: (TextSize, ast::ParenthesizedExpr, TextSize), + __6: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __7: (TextSize, token::Tok, TextSize), __8: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -79210,7 +79210,7 @@ fn __action1775< __2: (TextSize, ast::TypeParams, TextSize), __3: (TextSize, ast::Parameters, TextSize), __4: (TextSize, token::Tok, TextSize), - __5: (TextSize, ast::ParenthesizedExpr, TextSize), + __5: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __6: (TextSize, token::Tok, TextSize), __7: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -79247,7 +79247,7 @@ fn __action1776< __1: (TextSize, ast::Identifier, TextSize), __2: (TextSize, ast::Parameters, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -79287,7 +79287,7 @@ fn __action1777< __3: (TextSize, ast::TypeParams, TextSize), __4: (TextSize, ast::Parameters, TextSize), __5: (TextSize, token::Tok, TextSize), - __6: (TextSize, ast::ParenthesizedExpr, TextSize), + __6: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __7: (TextSize, token::Tok, TextSize), __8: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -79326,7 +79326,7 @@ fn __action1778< __2: (TextSize, ast::Identifier, TextSize), __3: (TextSize, ast::Parameters, TextSize), __4: (TextSize, token::Tok, TextSize), - __5: (TextSize, ast::ParenthesizedExpr, TextSize), + __5: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __6: (TextSize, token::Tok, TextSize), __7: (TextSize, ast::Suite, TextSize), ) -> ast::Stmt @@ -79505,7 +79505,7 @@ fn __action1783< __1: (TextSize, ast::Expr, TextSize), __2: (TextSize, ast::TypeParams, TextSize), __3: (TextSize, token::Tok, TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Stmt { let __start0 = __2.0; @@ -79536,7 +79536,7 @@ fn __action1784< __0: (TextSize, token::Tok, TextSize), __1: (TextSize, ast::Expr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), ) -> ast::Stmt { let __start0 = __1.2; @@ -79569,8 +79569,8 @@ fn __action1785< __1: (TextSize, ast::Parameters, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, (String, bool), TextSize), - __4: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Result> + __4: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Result> { let __start0 = __3.0; let __end0 = __3.2; @@ -79600,8 +79600,8 @@ fn __action1786< __0: (TextSize, token::Tok, TextSize), __1: (TextSize, ast::Parameters, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Result> + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Result> { let __start0 = __2.2; let __end0 = __3.0; @@ -79632,8 +79632,8 @@ fn __action1787< __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), __2: (TextSize, (String, bool), TextSize), - __3: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Result> + __3: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Result> { let __start0 = __2.0; let __end0 = __2.2; @@ -79661,8 +79661,8 @@ fn __action1788< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, token::Tok, TextSize), - __2: (TextSize, ast::ParenthesizedExpr, TextSize), -) -> Result> + __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), +) -> Result> { let __start0 = __1.2; let __end0 = __2.0; From 0bda1913d103b5db841f966621aa43b48662e808 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Mon, 4 Dec 2023 14:38:54 +0900 Subject: [PATCH 103/197] Create dedicated `is_*_enabled` functions for each preview style (#8988) --- crates/ruff_python_formatter/src/context.rs | 5 +++++ .../src/expression/binary_like.rs | 5 +++-- .../src/expression/mod.rs | 10 +++++----- crates/ruff_python_formatter/src/lib.rs | 1 + crates/ruff_python_formatter/src/options.rs | 2 +- .../src/other/arguments.rs | 8 +++++--- crates/ruff_python_formatter/src/preview.rs | 19 +++++++++++++++++++ 7 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 crates/ruff_python_formatter/src/preview.rs diff --git a/crates/ruff_python_formatter/src/context.rs b/crates/ruff_python_formatter/src/context.rs index eb8fe7edf4155..2e6cdc0d2ed51 100644 --- a/crates/ruff_python_formatter/src/context.rs +++ b/crates/ruff_python_formatter/src/context.rs @@ -74,6 +74,11 @@ impl<'a> PyFormatContext<'a> { ..self } } + + /// Returns `true` if preview mode is enabled. + pub(crate) const fn is_preview(&self) -> bool { + self.options.preview().is_enabled() + } } impl FormatContext for PyFormatContext<'_> { diff --git a/crates/ruff_python_formatter/src/expression/binary_like.rs b/crates/ruff_python_formatter/src/expression/binary_like.rs index 149449d61cb04..9a9feea584831 100644 --- a/crates/ruff_python_formatter/src/expression/binary_like.rs +++ b/crates/ruff_python_formatter/src/expression/binary_like.rs @@ -3,7 +3,7 @@ use std::ops::{Deref, Index}; use smallvec::SmallVec; -use ruff_formatter::{write, FormatContext}; +use ruff_formatter::write; use ruff_python_ast::{ Expr, ExprAttribute, ExprBinOp, ExprBoolOp, ExprCompare, ExprUnaryOp, UnaryOp, }; @@ -21,6 +21,7 @@ use crate::expression::parentheses::{ use crate::expression::string::{AnyString, FormatString, StringLayout}; use crate::expression::OperatorPrecedence; use crate::prelude::*; +use crate::preview::is_fix_power_op_line_length_enabled; #[derive(Copy, Clone, Debug)] pub(super) enum BinaryLike<'a> { @@ -719,7 +720,7 @@ impl Format> for FlatBinaryExpressionSlice<'_> { { hard_line_break().fmt(f)?; } else if is_pow { - if f.context().options().preview().is_enabled() { + if is_fix_power_op_line_length_enabled(f.context()) { in_parentheses_only_if_group_breaks(&space()).fmt(f)?; } } else { diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index 06cbe3bc2cebd..1fb97009e4b64 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -21,7 +21,7 @@ use crate::expression::parentheses::{ OptionalParentheses, Parentheses, Parenthesize, }; use crate::prelude::*; -use crate::PyFormatOptions; +use crate::preview::is_hug_parens_with_braces_and_square_brackets_enabled; mod binary_like; pub(crate) mod expr_attribute; @@ -129,7 +129,7 @@ impl FormatRule> for FormatExpr { let node_comments = comments.leading_dangling_trailing(expression); if !node_comments.has_leading() && !node_comments.has_trailing() { parenthesized("(", &format_expr, ")") - .with_indent(!is_expression_huggable(expression, f.options())) + .with_indent(!is_expression_huggable(expression, f.context())) .fmt(f) } else { format_with_parentheses_comments(expression, &node_comments, f) @@ -448,7 +448,7 @@ impl Format> for MaybeParenthesizeExpression<'_> { OptionalParentheses::Never => match parenthesize { Parenthesize::IfBreaksOrIfRequired => { parenthesize_if_expands(&expression.format().with_options(Parentheses::Never)) - .with_indent(!is_expression_huggable(expression, f.options())) + .with_indent(!is_expression_huggable(expression, f.context())) .fmt(f) } @@ -1061,8 +1061,8 @@ pub(crate) fn has_own_parentheses( /// ] /// ) /// ``` -pub(crate) fn is_expression_huggable(expr: &Expr, options: &PyFormatOptions) -> bool { - if !options.preview().is_enabled() { +pub(crate) fn is_expression_huggable(expr: &Expr, context: &PyFormatContext) -> bool { + if !is_hug_parens_with_braces_and_square_brackets_enabled(context) { return false; } diff --git a/crates/ruff_python_formatter/src/lib.rs b/crates/ruff_python_formatter/src/lib.rs index e9a3c34757da9..ce3988dd54693 100644 --- a/crates/ruff_python_formatter/src/lib.rs +++ b/crates/ruff_python_formatter/src/lib.rs @@ -32,6 +32,7 @@ mod options; pub(crate) mod other; pub(crate) mod pattern; mod prelude; +mod preview; mod shared_traits; pub(crate) mod statement; pub(crate) mod type_param; diff --git a/crates/ruff_python_formatter/src/options.rs b/crates/ruff_python_formatter/src/options.rs index 261dfeab190ff..8306afd82c431 100644 --- a/crates/ruff_python_formatter/src/options.rs +++ b/crates/ruff_python_formatter/src/options.rs @@ -119,7 +119,7 @@ impl PyFormatOptions { self.docstring_code } - pub fn preview(&self) -> PreviewMode { + pub const fn preview(&self) -> PreviewMode { self.preview } diff --git a/crates/ruff_python_formatter/src/other/arguments.rs b/crates/ruff_python_formatter/src/other/arguments.rs index a48596cac0eb3..d57e168c89459 100644 --- a/crates/ruff_python_formatter/src/other/arguments.rs +++ b/crates/ruff_python_formatter/src/other/arguments.rs @@ -9,6 +9,7 @@ use crate::expression::is_expression_huggable; use crate::expression::parentheses::{empty_parenthesized, parenthesized, Parentheses}; use crate::other::commas; use crate::prelude::*; +use crate::preview::is_hug_parens_with_braces_and_square_brackets_enabled; #[derive(Default)] pub struct FormatArguments; @@ -177,8 +178,7 @@ fn is_single_argument_parenthesized(argument: &Expr, call_end: TextSize, source: /// Hugging should only be applied to single-argument collections, like lists, or starred versions /// of those collections. fn is_argument_huggable(item: &Arguments, context: &PyFormatContext) -> bool { - let options = context.options(); - if !options.preview().is_enabled() { + if !is_hug_parens_with_braces_and_square_brackets_enabled(context) { return false; } @@ -192,7 +192,7 @@ fn is_argument_huggable(item: &Arguments, context: &PyFormatContext) -> bool { }; // If the expression itself isn't huggable, then we can't hug it. - if !is_expression_huggable(arg, options) { + if !is_expression_huggable(arg, context) { return false; } @@ -202,6 +202,8 @@ fn is_argument_huggable(item: &Arguments, context: &PyFormatContext) -> bool { return false; } + let options = context.options(); + // If the expression has a trailing comma, then we can't hug it. if options.magic_trailing_comma().is_respect() && commas::has_magic_trailing_comma(TextRange::new(arg.end(), item.end()), options, context) diff --git a/crates/ruff_python_formatter/src/preview.rs b/crates/ruff_python_formatter/src/preview.rs new file mode 100644 index 0000000000000..8354e83a64d4a --- /dev/null +++ b/crates/ruff_python_formatter/src/preview.rs @@ -0,0 +1,19 @@ +//! Helpers to test if a specific preview style is enabled or not. +//! +//! The motivation for these functions isn't to avoid code duplication but to ease promoting preview styles +//! to stable. The challenge with directly using [`is_preview`](PyFormatContext::is_preview) is that it is unclear +//! for which specific feature this preview check is for. Having named functions simplifies the promotion: +//! Simply delete the function and let Rust tell you which checks you have to remove. +use crate::PyFormatContext; + +/// Returns `true` if the [`fix_power_op_line_length`](https://github.com/astral-sh/ruff/issues/8938) preview style is enabled. +pub(crate) const fn is_fix_power_op_line_length_enabled(context: &PyFormatContext) -> bool { + context.is_preview() +} + +/// Returns `true` if the [`hug_parens_with_braces_and_square_brackets`](https://github.com/astral-sh/ruff/issues/8279) preview style is enabled. +pub(crate) const fn is_hug_parens_with_braces_and_square_brackets_enabled( + context: &PyFormatContext, +) -> bool { + context.is_preview() +} From b91b09b96173d54086f7ed45c6ef25c2d4bf8536 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 09:24:53 +0000 Subject: [PATCH 104/197] Bump schemars from 0.8.15 to 0.8.16 (#8990) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee526538f941e..b8af530d69289 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2618,9 +2618,9 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f7b0ce13155372a76ee2e1c5ffba1fe61ede73fbea5630d61eee6fac4929c0c" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" dependencies = [ "dyn-clone", "schemars_derive", @@ -2630,9 +2630,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e85e2a16b12bdb763244c69ab79363d71db2b4b918a2def53f80b02e0574b13c" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 606769499258d..3328c0c98968a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ proc-macro2 = { version = "1.0.70" } quote = { version = "1.0.23" } regex = { version = "1.10.2" } rustc-hash = { version = "1.1.0" } -schemars = { version = "0.8.15" } +schemars = { version = "0.8.16" } serde = { version = "1.0.190", features = ["derive"] } serde_json = { version = "1.0.108" } shellexpand = { version = "3.0.0" } From 54de990621c6297670f5e841551cb237e9d0fffb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 19:49:34 +0900 Subject: [PATCH 105/197] Bump fs-err from 2.10.0 to 2.11.0 (#8991) --- Cargo.lock | 4 ++-- crates/ruff_shrinking/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b8af530d69289..c546f20a69906 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -857,9 +857,9 @@ dependencies = [ [[package]] name = "fs-err" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5fd9bcbe8b1087cbd395b51498c01bc997cef73e778a80b77a811af5e2d29f" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" dependencies = [ "autocfg", ] diff --git a/crates/ruff_shrinking/Cargo.toml b/crates/ruff_shrinking/Cargo.toml index caa568c997f35..f93e1e2f5c64e 100644 --- a/crates/ruff_shrinking/Cargo.toml +++ b/crates/ruff_shrinking/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] anyhow = { workspace = true } clap = { workspace = true } -fs-err = "2.10.0" +fs-err = "2.11.0" regex = { workspace = true } ruff_python_ast = { path = "../ruff_python_ast" } ruff_python_parser = { path = "../ruff_python_parser" } From cb6c37abd93e0ba654f700d0f95f2267d16f8a84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 19:50:08 +0900 Subject: [PATCH 106/197] Bump js-sys from 0.3.65 to 0.3.66 (#8992) --- Cargo.lock | 24 ++++++++++++------------ crates/ruff_wasm/Cargo.toml | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c546f20a69906..4f60e82900e44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1170,9 +1170,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.65" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] @@ -3461,9 +3461,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3471,9 +3471,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", @@ -3498,9 +3498,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3508,9 +3508,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", @@ -3521,9 +3521,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "wasm-bindgen-test" diff --git a/crates/ruff_wasm/Cargo.toml b/crates/ruff_wasm/Cargo.toml index a4998df0fb852..d7b3190658cd6 100644 --- a/crates/ruff_wasm/Cargo.toml +++ b/crates/ruff_wasm/Cargo.toml @@ -38,7 +38,7 @@ log = { workspace = true } serde = { workspace = true } serde-wasm-bindgen = { version = "0.6.1" } wasm-bindgen = { version = "0.2.84" } -js-sys = { version = "0.3.65" } +js-sys = { version = "0.3.66" } [dev-dependencies] wasm-bindgen-test = { version = "0.3.38" } From df69dc9f8d5531ab7e4651cebcf4c7e00bcec352 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 10:16:39 -0500 Subject: [PATCH 107/197] Bump url from 2.4.1 to 2.5.0 (#8994) --- Cargo.lock | 16 ++++++++-------- crates/ruff_benchmark/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f60e82900e44..1789df8dfdb7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -848,9 +848,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -987,9 +987,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1622,9 +1622,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petgraph" @@ -3350,9 +3350,9 @@ dependencies = [ [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", diff --git a/crates/ruff_benchmark/Cargo.toml b/crates/ruff_benchmark/Cargo.toml index 96d3476da697c..59d3f3bdb48de 100644 --- a/crates/ruff_benchmark/Cargo.toml +++ b/crates/ruff_benchmark/Cargo.toml @@ -34,7 +34,7 @@ harness = false once_cell.workspace = true serde.workspace = true serde_json.workspace = true -url = "2.3.1" +url = "2.5.0" ureq = "2.8.0" criterion = { version = "0.5.1", default-features = false } codspeed-criterion-compat = { version="2.3.3", default-features = false, optional = true} From f5d4676c13643352dfc65a8a2d3a591377a0b4a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 09:53:25 -0600 Subject: [PATCH 108/197] Bump ureq from 2.8.0 to 2.9.1 (#8993) --- Cargo.lock | 4 ++-- crates/ruff_benchmark/Cargo.toml | 2 +- crates/ruff_cli/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1789df8dfdb7c..0aa607423cb3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3334,9 +3334,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "ureq" -version = "2.8.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5ccd538d4a604753ebc2f17cd9946e89b77bf87f6a8e2309667c6f2e87855e3" +checksum = "f8cdd25c339e200129fe4de81451814e5228c9b771d57378817d6117cc2b3f97" dependencies = [ "base64", "flate2", diff --git a/crates/ruff_benchmark/Cargo.toml b/crates/ruff_benchmark/Cargo.toml index 59d3f3bdb48de..60f1b5011e56c 100644 --- a/crates/ruff_benchmark/Cargo.toml +++ b/crates/ruff_benchmark/Cargo.toml @@ -35,7 +35,7 @@ once_cell.workspace = true serde.workspace = true serde_json.workspace = true url = "2.5.0" -ureq = "2.8.0" +ureq = "2.9.1" criterion = { version = "0.5.1", default-features = false } codspeed-criterion-compat = { version="2.3.3", default-features = false, optional = true} diff --git a/crates/ruff_cli/Cargo.toml b/crates/ruff_cli/Cargo.toml index 84bfcb5f6683f..12bb66e10fea8 100644 --- a/crates/ruff_cli/Cargo.toml +++ b/crates/ruff_cli/Cargo.toml @@ -69,7 +69,7 @@ insta = { workspace = true, features = ["filters", "json"] } insta-cmd = { version = "0.4.0" } tempfile = "3.8.1" test-case = { workspace = true } -ureq = { version = "2.8.0", features = [] } +ureq = { version = "2.9.1", features = [] } [target.'cfg(target_os = "windows")'.dependencies] mimalloc = "0.1.39" From 060a25df09f444cb157f2f818767a28bd8b9e1cb Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Mon, 4 Dec 2023 11:28:09 -0600 Subject: [PATCH 109/197] Rename semantic model flag `LITERAL` to `TYPING_LITERAL` (#8997) This PR renames the semantic model flag `LITERAL` to `TYPING_LITERAL` to better reflect its purpose. The main motivation behind this change is to avoid any confusion with the "literal" terminology used in the AST for literal nodes like string, bytes, numbers, etc. --- crates/ruff_linter/src/checkers/ast/mod.rs | 6 +++--- crates/ruff_python_semantic/src/model.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 11e8e704aa02f..31069ac6c55fd 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -816,7 +816,7 @@ where fn visit_expr(&mut self, expr: &'b Expr) { // Step 0: Pre-processing if !self.semantic.in_f_string() - && !self.semantic.in_literal() + && !self.semantic.in_typing_literal() && !self.semantic.in_deferred_type_definition() && self.semantic.in_type_definition() && self.semantic.future_annotations() @@ -1198,7 +1198,7 @@ where ) { // Ex) Literal["Class"] Some(typing::SubscriptKind::Literal) => { - self.semantic.flags |= SemanticModelFlags::LITERAL; + self.semantic.flags |= SemanticModelFlags::TYPING_LITERAL; self.visit_expr(slice); self.visit_expr_context(ctx); @@ -1239,7 +1239,7 @@ where } Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { if self.semantic.in_type_definition() - && !self.semantic.in_literal() + && !self.semantic.in_typing_literal() && !self.semantic.in_f_string() { self.deferred.string_type_definitions.push(( diff --git a/crates/ruff_python_semantic/src/model.rs b/crates/ruff_python_semantic/src/model.rs index 42617ddaf7396..9cb3cebaa07ff 100644 --- a/crates/ruff_python_semantic/src/model.rs +++ b/crates/ruff_python_semantic/src/model.rs @@ -1359,8 +1359,8 @@ impl<'a> SemanticModel<'a> { } /// Return `true` if the model is in a `typing::Literal` annotation. - pub const fn in_literal(&self) -> bool { - self.flags.intersects(SemanticModelFlags::LITERAL) + pub const fn in_typing_literal(&self) -> bool { + self.flags.intersects(SemanticModelFlags::TYPING_LITERAL) } /// Return `true` if the model is in a subscript expression. @@ -1576,7 +1576,7 @@ bitflags! { /// def f(x: Literal["A", "B", "C"]): /// ... /// ``` - const LITERAL = 1 << 9; + const TYPING_LITERAL = 1 << 9; /// The model is in a subscript expression. /// From b90027d037ac86c9b2fffcaa26ee717243f52791 Mon Sep 17 00:00:00 2001 From: Philipp A Date: Mon, 4 Dec 2023 19:03:09 +0100 Subject: [PATCH 110/197] [`pylint`] Implement `too-many-positional` (`PLR0917`) (#8995) ## Summary Adds a rule that bans too many positional (i.e. not keyword-only) parameters in function definitions. Fixes https://github.com/astral-sh/ruff/issues/8946 Rule ID code taken from https://github.com/pylint-dev/pylint/pull/9278 ## Test Plan 1. fixtures file checking multiple OKs/fails 2. parametrized test file --- .../fixtures/pylint/too_many_positional.py | 30 +++++++ .../pylint/too_many_positional_params.py | 10 +++ .../src/checkers/ast/analyze/statement.rs | 3 + crates/ruff_linter/src/codes.rs | 1 + crates/ruff_linter/src/rules/pylint/mod.rs | 17 ++++ .../ruff_linter/src/rules/pylint/rules/mod.rs | 2 + .../rules/pylint/rules/too_many_positional.rs | 79 +++++++++++++++++++ .../ruff_linter/src/rules/pylint/settings.rs | 2 + ...tests__PLR0917_too_many_positional.py.snap | 25 ++++++ ...s__pylint__tests__max_positional_args.snap | 22 ++++++ crates/ruff_workspace/src/options.rs | 8 ++ ruff.schema.json | 10 +++ 12 files changed, 209 insertions(+) create mode 100644 crates/ruff_linter/resources/test/fixtures/pylint/too_many_positional.py create mode 100644 crates/ruff_linter/resources/test/fixtures/pylint/too_many_positional_params.py create mode 100644 crates/ruff_linter/src/rules/pylint/rules/too_many_positional.rs create mode 100644 crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0917_too_many_positional.py.snap create mode 100644 crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__max_positional_args.snap diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/too_many_positional.py b/crates/ruff_linter/resources/test/fixtures/pylint/too_many_positional.py new file mode 100644 index 0000000000000..3c0fe2a2f5fb4 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/pylint/too_many_positional.py @@ -0,0 +1,30 @@ +def f(x, y, z, t, u, v, w, r): # Too many positional arguments (8/3) + pass + + +def f(x): # OK + pass + + +def f(x, y, z, _t, _u, _v, _w, r): # OK (underscore-prefixed names are ignored + pass + + +def f(x, y, z, *, u=1, v=1, r=1): # OK + pass + + +def f(x=1, y=1, z=1): # OK + pass + + +def f(x, y, z, /, u, v, w): # Too many positional arguments (6/3) + pass + + +def f(x, y, z, *, u, v, w): # OK + pass + + +def f(x, y, z, a, b, c, *, u, v, w): # Too many positional arguments (6/3) + pass diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/too_many_positional_params.py b/crates/ruff_linter/resources/test/fixtures/pylint/too_many_positional_params.py new file mode 100644 index 0000000000000..dae87b5737a2c --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/pylint/too_many_positional_params.py @@ -0,0 +1,10 @@ +# Too many positional arguments (7/4) for max_positional=4 +# OK for dummy_variable_rgx ~ "skip_.*" +def f(w, x, y, z, skip_t, skip_u, skip_v): + pass + + +# Too many positional arguments (7/4) for max_args=4 +# Too many positional arguments (7/3) for dummy_variable_rgx ~ "skip_.*" +def f(w, x, y, z, t, u, v): + pass diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 4b79a9ec7da14..0f05d6165b22e 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -250,6 +250,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if checker.enabled(Rule::TooManyArguments) { pylint::rules::too_many_arguments(checker, function_def); } + if checker.enabled(Rule::TooManyPositional) { + pylint::rules::too_many_positional(checker, parameters, stmt); + } if checker.enabled(Rule::TooManyReturnStatements) { if let Some(diagnostic) = pylint::rules::too_many_return_statements( stmt, diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index cb1f907b658e0..fd0b85727bbec 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -254,6 +254,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Pylint, "R0913") => (RuleGroup::Stable, rules::pylint::rules::TooManyArguments), (Pylint, "R0915") => (RuleGroup::Stable, rules::pylint::rules::TooManyStatements), (Pylint, "R0916") => (RuleGroup::Preview, rules::pylint::rules::TooManyBooleanExpressions), + (Pylint, "R0917") => (RuleGroup::Preview, rules::pylint::rules::TooManyPositional), (Pylint, "R1701") => (RuleGroup::Stable, rules::pylint::rules::RepeatedIsinstanceCalls), (Pylint, "R1704") => (RuleGroup::Preview, rules::pylint::rules::RedefinedArgumentFromLocal), (Pylint, "R1711") => (RuleGroup::Stable, rules::pylint::rules::UselessReturn), diff --git a/crates/ruff_linter/src/rules/pylint/mod.rs b/crates/ruff_linter/src/rules/pylint/mod.rs index 20920043f97b6..3933e07bf9e02 100644 --- a/crates/ruff_linter/src/rules/pylint/mod.rs +++ b/crates/ruff_linter/src/rules/pylint/mod.rs @@ -94,6 +94,7 @@ mod tests { #[test_case(Rule::RedefinedLoopName, Path::new("redefined_loop_name.py"))] #[test_case(Rule::ReturnInInit, Path::new("return_in_init.py"))] #[test_case(Rule::TooManyArguments, Path::new("too_many_arguments.py"))] + #[test_case(Rule::TooManyPositional, Path::new("too_many_positional.py"))] #[test_case(Rule::TooManyBranches, Path::new("too_many_branches.py"))] #[test_case( Rule::TooManyReturnStatements, @@ -249,6 +250,22 @@ mod tests { Ok(()) } + #[test] + fn max_positional_args() -> Result<()> { + let diagnostics = test_path( + Path::new("pylint/too_many_positional_params.py"), + &LinterSettings { + pylint: pylint::settings::Settings { + max_positional_args: 4, + ..pylint::settings::Settings::default() + }, + ..LinterSettings::for_rule(Rule::TooManyPositional) + }, + )?; + assert_messages!(diagnostics); + Ok(()) + } + #[test] fn max_branches() -> Result<()> { let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/pylint/rules/mod.rs b/crates/ruff_linter/src/rules/pylint/rules/mod.rs index 02ae6796a5dfb..aaedd82e2f790 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/mod.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/mod.rs @@ -55,6 +55,7 @@ pub(crate) use sys_exit_alias::*; pub(crate) use too_many_arguments::*; pub(crate) use too_many_boolean_expressions::*; pub(crate) use too_many_branches::*; +pub(crate) use too_many_positional::*; pub(crate) use too_many_public_methods::*; pub(crate) use too_many_return_statements::*; pub(crate) use too_many_statements::*; @@ -131,6 +132,7 @@ mod sys_exit_alias; mod too_many_arguments; mod too_many_boolean_expressions; mod too_many_branches; +mod too_many_positional; mod too_many_public_methods; mod too_many_return_statements; mod too_many_statements; diff --git a/crates/ruff_linter/src/rules/pylint/rules/too_many_positional.rs b/crates/ruff_linter/src/rules/pylint/rules/too_many_positional.rs new file mode 100644 index 0000000000000..369b6c63bc6e9 --- /dev/null +++ b/crates/ruff_linter/src/rules/pylint/rules/too_many_positional.rs @@ -0,0 +1,79 @@ +use ruff_diagnostics::{Diagnostic, Violation}; +use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::{identifier::Identifier, Parameters, Stmt}; + +use crate::checkers::ast::Checker; + +/// ## What it does +/// Checks for function definitions that include too many positional arguments. +/// +/// By default, this rule allows up to five arguments, as configured by the +/// [`pylint.max-positional-args`] option. +/// +/// ## Why is this bad? +/// Functions with many arguments are harder to understand, maintain, and call. +/// This is especially true for functions with many positional arguments, as +/// providing arguments positionally is more error-prone and less clear to +/// readers than providing arguments by name. +/// +/// Consider refactoring functions with many arguments into smaller functions +/// with fewer arguments, using objects to group related arguments, or +/// migrating to keyword-only arguments. +/// +/// ## Example +/// ```python +/// def plot(x, y, z, color, mark, add_trendline): +/// ... +/// +/// +/// plot(1, 2, 3, "r", "*", True) +/// ``` +/// +/// Use instead: +/// ```python +/// def plot(x, y, z, *, color, mark, add_trendline): +/// ... +/// +/// +/// plot(1, 2, 3, color="r", mark="*", add_trendline=True) +/// ``` +/// +/// ## Options +/// - `pylint.max-positional-args` +#[violation] +pub struct TooManyPositional { + c_pos: usize, + max_pos: usize, +} + +impl Violation for TooManyPositional { + #[derive_message_formats] + fn message(&self) -> String { + let TooManyPositional { c_pos, max_pos } = self; + format!("Too many positional arguments: ({c_pos}/{max_pos})") + } +} + +/// PLR0917 +pub(crate) fn too_many_positional(checker: &mut Checker, parameters: &Parameters, stmt: &Stmt) { + let num_positional_args = parameters + .args + .iter() + .chain(¶meters.posonlyargs) + .filter(|arg| { + !checker + .settings + .dummy_variable_rgx + .is_match(&arg.parameter.name) + }) + .count(); + if num_positional_args > checker.settings.pylint.max_positional_args { + checker.diagnostics.push(Diagnostic::new( + TooManyPositional { + c_pos: num_positional_args, + max_pos: checker.settings.pylint.max_positional_args, + }, + stmt.identifier(), + )); + } +} diff --git a/crates/ruff_linter/src/rules/pylint/settings.rs b/crates/ruff_linter/src/rules/pylint/settings.rs index cb9846b11e056..020390704c7f8 100644 --- a/crates/ruff_linter/src/rules/pylint/settings.rs +++ b/crates/ruff_linter/src/rules/pylint/settings.rs @@ -39,6 +39,7 @@ pub struct Settings { pub allow_magic_value_types: Vec, pub allow_dunder_method_names: FxHashSet, pub max_args: usize, + pub max_positional_args: usize, pub max_returns: usize, pub max_bool_expr: usize, pub max_branches: usize, @@ -52,6 +53,7 @@ impl Default for Settings { allow_magic_value_types: vec![ConstantType::Str, ConstantType::Bytes], allow_dunder_method_names: FxHashSet::default(), max_args: 5, + max_positional_args: 5, max_returns: 6, max_bool_expr: 5, max_branches: 12, diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0917_too_many_positional.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0917_too_many_positional.py.snap new file mode 100644 index 0000000000000..4578419f43545 --- /dev/null +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR0917_too_many_positional.py.snap @@ -0,0 +1,25 @@ +--- +source: crates/ruff_linter/src/rules/pylint/mod.rs +--- +too_many_positional.py:1:5: PLR0917 Too many positional arguments: (8/5) + | +1 | def f(x, y, z, t, u, v, w, r): # Too many positional arguments (8/3) + | ^ PLR0917 +2 | pass + | + +too_many_positional.py:21:5: PLR0917 Too many positional arguments: (6/5) + | +21 | def f(x, y, z, /, u, v, w): # Too many positional arguments (6/3) + | ^ PLR0917 +22 | pass + | + +too_many_positional.py:29:5: PLR0917 Too many positional arguments: (6/5) + | +29 | def f(x, y, z, a, b, c, *, u, v, w): # Too many positional arguments (6/3) + | ^ PLR0917 +30 | pass + | + + diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__max_positional_args.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__max_positional_args.snap new file mode 100644 index 0000000000000..98c964820770c --- /dev/null +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__max_positional_args.snap @@ -0,0 +1,22 @@ +--- +source: crates/ruff_linter/src/rules/pylint/mod.rs +--- +too_many_positional_params.py:3:5: PLR0917 Too many positional arguments: (7/4) + | +1 | # Too many positional arguments (7/4) for max_positional=4 +2 | # OK for dummy_variable_rgx ~ "skip_.*" +3 | def f(w, x, y, z, skip_t, skip_u, skip_v): + | ^ PLR0917 +4 | pass + | + +too_many_positional_params.py:9:5: PLR0917 Too many positional arguments: (7/4) + | + 7 | # Too many positional arguments (7/4) for max_args=4 + 8 | # Too many positional arguments (7/3) for dummy_variable_rgx ~ "skip_.*" + 9 | def f(w, x, y, z, t, u, v): + | ^ PLR0917 +10 | pass + | + + diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index 05f4522710cd9..f87a5223d9aed 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -2635,6 +2635,11 @@ pub struct PylintOptions { #[option(default = r"5", value_type = "int", example = r"max-args = 5")] pub max_args: Option, + /// Maximum number of positional arguments allowed for a function or method definition + /// (see: `PLR0917`). + #[option(default = r"3", value_type = "int", example = r"max-pos-args = 3")] + pub max_positional_args: Option, + /// Maximum number of statements allowed for a function or method body (see: /// `PLR0915`). #[option(default = r"50", value_type = "int", example = r"max-statements = 50")] @@ -2663,6 +2668,9 @@ impl PylintOptions { .unwrap_or(defaults.allow_magic_value_types), allow_dunder_method_names: self.allow_dunder_method_names.unwrap_or_default(), max_args: self.max_args.unwrap_or(defaults.max_args), + max_positional_args: self + .max_positional_args + .unwrap_or(defaults.max_positional_args), max_bool_expr: self.max_bool_expr.unwrap_or(defaults.max_bool_expr), max_returns: self.max_returns.unwrap_or(defaults.max_returns), max_branches: self.max_branches.unwrap_or(defaults.max_branches), diff --git a/ruff.schema.json b/ruff.schema.json index b0584cad84735..d962edc15e141 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -2369,6 +2369,15 @@ "format": "uint", "minimum": 0.0 }, + "max-positional-args": { + "description": "Maximum number of positional arguments allowed for a function or method definition (see: `PLR0917`).", + "type": [ + "integer", + "null" + ], + "format": "uint", + "minimum": 0.0 + }, "max-public-methods": { "description": "Maximum number of public methods allowed for a class (see: `PLR0904`).", "type": [ @@ -3117,6 +3126,7 @@ "PLR0913", "PLR0915", "PLR0916", + "PLR0917", "PLR1", "PLR17", "PLR170", From 93258e8d5b9f681623eea6efdc154e399af0c378 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 4 Dec 2023 14:02:10 -0500 Subject: [PATCH 111/197] Default `max-positional-args` to `max-args` (#8998) --- crates/ruff_workspace/src/options.rs | 3 +++ ruff.schema.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index f87a5223d9aed..442b8d7d2e16d 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -2637,6 +2637,8 @@ pub struct PylintOptions { /// Maximum number of positional arguments allowed for a function or method definition /// (see: `PLR0917`). + /// + /// If not specified, defaults to the value of `max-args`. #[option(default = r"3", value_type = "int", example = r"max-pos-args = 3")] pub max_positional_args: Option, @@ -2670,6 +2672,7 @@ impl PylintOptions { max_args: self.max_args.unwrap_or(defaults.max_args), max_positional_args: self .max_positional_args + .or(self.max_args) .unwrap_or(defaults.max_positional_args), max_bool_expr: self.max_bool_expr.unwrap_or(defaults.max_bool_expr), max_returns: self.max_returns.unwrap_or(defaults.max_returns), diff --git a/ruff.schema.json b/ruff.schema.json index d962edc15e141..3bd21232a2551 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -2370,7 +2370,7 @@ "minimum": 0.0 }, "max-positional-args": { - "description": "Maximum number of positional arguments allowed for a function or method definition (see: `PLR0917`).", + "description": "Maximum number of positional arguments allowed for a function or method definition (see: `PLR0917`).\n\nIf not specified, defaults to the value of `max-args`.", "type": [ "integer", "null" From 8d9912a83a4eb41d38b2d75d05b06ca6093a7f2d Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 4 Dec 2023 16:28:23 -0500 Subject: [PATCH 112/197] Bump version to v0.1.7 (#8999) --- CHANGELOG.md | 94 +++++++++++++++++++++++++++++++ Cargo.lock | 8 +-- README.md | 2 +- crates/flake8_to_ruff/Cargo.toml | 2 +- crates/ruff_cli/Cargo.toml | 2 +- crates/ruff_linter/Cargo.toml | 2 +- crates/ruff_shrinking/Cargo.toml | 2 +- docs/integrations.md | 6 +- pyproject.toml | 2 +- scripts/benchmarks/pyproject.toml | 2 +- 10 files changed, 108 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 766439b59e989..b5be1f46ffe6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,99 @@ # Changelog +## 0.1.7 + +### Preview features + +- Implement multiline dictionary and list hugging for preview style ([#8293](https://github.com/astral-sh/ruff/pull/8293)) +- Implement the `fix_power_op_line_length` preview style ([#8947](https://github.com/astral-sh/ruff/pull/8947)) +- Use Python version to determine typing rewrite safety ([#8919](https://github.com/astral-sh/ruff/pull/8919)) +- \[`flake8-annotations`\] Enable auto-return-type involving `Optional` and `Union` annotations ([#8885](https://github.com/astral-sh/ruff/pull/8885)) +- \[`flake8-bandit`\] Implement `django-raw-sql` (`S611`) ([#8651](https://github.com/astral-sh/ruff/pull/8651)) +- \[`flake8-bandit`\] Implement `tarfile-unsafe-members` (`S202`) ([#8829](https://github.com/astral-sh/ruff/pull/8829)) +- \[`flake8-pyi`\] Implement fix for `unnecessary-literal-union` (`PYI030`) ([#7934](https://github.com/astral-sh/ruff/pull/7934)) +- \[`flake8-simplify`\] Extend `dict-get-with-none-default` (`SIM910`) to non-literals ([#8762](https://github.com/astral-sh/ruff/pull/8762)) +- \[`pylint`\] - add `unnecessary-list-index-lookup` (`PLR1736`) + autofix ([#7999](https://github.com/astral-sh/ruff/pull/7999)) +- \[`pylint`\] - implement R0202 and R0203 with autofixes ([#8335](https://github.com/astral-sh/ruff/pull/8335)) +- \[`pylint`\] Implement `repeated-keyword` (`PLe1132`) ([#8706](https://github.com/astral-sh/ruff/pull/8706)) +- \[`pylint`\] Implement `too-many-positional` (`PLR0917`) ([#8995](https://github.com/astral-sh/ruff/pull/8995)) +- \[`pylint`\] Implement `unnecessary-dict-index-lookup` (`PLR1733`) ([#8036](https://github.com/astral-sh/ruff/pull/8036)) +- \[`refurb`\] Implement `redundant-log-base` (`FURB163`) ([#8842](https://github.com/astral-sh/ruff/pull/8842)) + +### Rule changes + +- \[`flake8-boolean-trap`\] Allow booleans in `@override` methods ([#8882](https://github.com/astral-sh/ruff/pull/8882)) +- \[`flake8-bugbear`\] Avoid `B015`,`B018` for last expression in a cell ([#8815](https://github.com/astral-sh/ruff/pull/8815)) +- \[`flake8-pie`\] Allow ellipses for enum values in stub files ([#8825](https://github.com/astral-sh/ruff/pull/8825)) +- \[`flake8-pyi`\] Check PEP 695 type aliases for `snake-case-type-alias` and `t-suffixed-type-alias` ([#8966](https://github.com/astral-sh/ruff/pull/8966)) +- \[`flake8-pyi`\] Check for kwarg and vararg `NoReturn` type annotations ([#8948](https://github.com/astral-sh/ruff/pull/8948)) +- \[`flake8-simplify`\] Omit select context managers from `SIM117` ([#8801](https://github.com/astral-sh/ruff/pull/8801)) +- \[`pep8-naming`\] Allow Django model loads in `non-lowercase-variable-in-function` (`N806`) ([#8917](https://github.com/astral-sh/ruff/pull/8917)) +- \[`pycodestyle`\] Avoid `E703` for last expression in a cell ([#8821](https://github.com/astral-sh/ruff/pull/8821)) +- \[`pycodestyle`\] Update `E402` to work at cell level for notebooks ([#8872](https://github.com/astral-sh/ruff/pull/8872)) +- \[`pydocstyle`\] Avoid `D100` for Jupyter Notebooks ([#8816](https://github.com/astral-sh/ruff/pull/8816)) +- \[`pylint`\] Implement fix for `unspecified-encoding` (`PLW1514`) ([#8928](https://github.com/astral-sh/ruff/pull/8928)) + +### Formatter + +- Avoid unstable formatting in ellipsis-only body with trailing comment ([#8984](https://github.com/astral-sh/ruff/pull/8984)) +- Inline trailing comments for type alias similar to assignments ([#8941](https://github.com/astral-sh/ruff/pull/8941)) +- Insert trailing comma when function breaks with single argument ([#8921](https://github.com/astral-sh/ruff/pull/8921)) + +### CLI + +- Update `ruff check` and `ruff format` to default to the current directory ([#8791](https://github.com/astral-sh/ruff/pull/8791)) +- Stop at the first resolved parent configuration ([#8864](https://github.com/astral-sh/ruff/pull/8864)) + +### Configuration + +- \[`pylint`\] Default `max-positional-args` to `max-args` ([#8998](https://github.com/astral-sh/ruff/pull/8998)) +- \[`pylint`\] Add `allow-dunder-method-names` setting for `bad-dunder-method-name` (`PLW3201`) ([#8812](https://github.com/astral-sh/ruff/pull/8812)) +- \[`isort`\] Add support for `from-first` setting ([#8663](https://github.com/astral-sh/ruff/pull/8663)) +- \[`isort`\] Add support for `length-sort` settings ([#8841](https://github.com/astral-sh/ruff/pull/8841)) + +### Bug fixes + +- Add support for `@functools.singledispatch` ([#8934](https://github.com/astral-sh/ruff/pull/8934)) +- Avoid off-by-one error in stripping noqa following multi-byte char ([#8979](https://github.com/astral-sh/ruff/pull/8979)) +- Avoid off-by-one error in with-item named expressions ([#8915](https://github.com/astral-sh/ruff/pull/8915)) +- Avoid syntax error via invalid ur string prefix ([#8971](https://github.com/astral-sh/ruff/pull/8971)) +- Avoid underflow in `get_model` matching ([#8965](https://github.com/astral-sh/ruff/pull/8965)) +- Avoid unnecessary index diagnostics when value is modified ([#8970](https://github.com/astral-sh/ruff/pull/8970)) +- Convert over-indentation rule to use number of characters ([#8983](https://github.com/astral-sh/ruff/pull/8983)) +- Detect implicit returns in auto-return-types ([#8952](https://github.com/astral-sh/ruff/pull/8952)) +- Fix start >= end error in over-indentation ([#8982](https://github.com/astral-sh/ruff/pull/8982)) +- Ignore `@overload` and `@override` methods for too-many-arguments checks ([#8954](https://github.com/astral-sh/ruff/pull/8954)) +- Lexer start of line is false only for `Mode::Expression` ([#8880](https://github.com/astral-sh/ruff/pull/8880)) +- Mark `pydantic_settings.BaseSettings` as having default copy semantics ([#8793](https://github.com/astral-sh/ruff/pull/8793)) +- Respect dictionary unpacking in `NamedTuple` assignments ([#8810](https://github.com/astral-sh/ruff/pull/8810)) +- Respect local subclasses in `flake8-type-checking` ([#8768](https://github.com/astral-sh/ruff/pull/8768)) +- Support type alias statements in simple statement positions ([#8916](https://github.com/astral-sh/ruff/pull/8916)) +- \[`flake8-annotations`\] Avoid filtering out un-representable types in return annotation ([#8881](https://github.com/astral-sh/ruff/pull/8881)) +- \[`flake8-pie`\] Retain extra ellipses in protocols and abstract methods ([#8769](https://github.com/astral-sh/ruff/pull/8769)) +- \[`flake8-pyi`\] Respect local enum subclasses in `simple-defaults` (`PYI052`) ([#8767](https://github.com/astral-sh/ruff/pull/8767)) +- \[`flake8-trio`\] Use correct range for `TRIO115` fix ([#8933](https://github.com/astral-sh/ruff/pull/8933)) +- \[`flake8-trio`\] Use full arguments range for zero-sleep-call ([#8936](https://github.com/astral-sh/ruff/pull/8936)) +- \[`isort`\] fix: mark `__main__` as first-party import ([#8805](https://github.com/astral-sh/ruff/pull/8805)) +- \[`pep8-naming`\] Avoid `N806` errors for type alias statements ([#8785](https://github.com/astral-sh/ruff/pull/8785)) +- \[`perflint`\] Avoid `PERF101` if there's an append in loop body ([#8809](https://github.com/astral-sh/ruff/pull/8809)) +- \[`pycodestyle`\] Allow space-before-colon after end-of-slice ([#8838](https://github.com/astral-sh/ruff/pull/8838)) +- \[`pydocstyle`\] Avoid non-character breaks in `over-indentation` (`D208`) ([#8866](https://github.com/astral-sh/ruff/pull/8866)) +- \[`pydocstyle`\] Ignore underlines when determining docstring logical lines ([#8929](https://github.com/astral-sh/ruff/pull/8929)) +- \[`pylint`\] Extend `self-assigning-variable` to multi-target assignments ([#8839](https://github.com/astral-sh/ruff/pull/8839)) +- \[`tryceratops`\] Avoid repeated triggers in nested `tryceratops` diagnostics ([#8772](https://github.com/astral-sh/ruff/pull/8772)) + +### Documentation + +- Add advice for fixing RUF008 when mutability is not desired ([#8853](https://github.com/astral-sh/ruff/pull/8853)) +- Added the command to run ruff using pkgx to the installation.md ([#8955](https://github.com/astral-sh/ruff/pull/8955)) +- Document fix safety for flake8-comprehensions and some pyupgrade rules ([#8918](https://github.com/astral-sh/ruff/pull/8918)) +- Fix doc formatting for zero-sleep-call ([#8937](https://github.com/astral-sh/ruff/pull/8937)) +- Remove duplicate imports from os-stat documentation ([#8930](https://github.com/astral-sh/ruff/pull/8930)) +- Replace generated reference to MkDocs ([#8806](https://github.com/astral-sh/ruff/pull/8806)) +- Update Arch Linux package URL in installation.md ([#8802](https://github.com/astral-sh/ruff/pull/8802)) +- \[`flake8-pyi`\] Fix error in `t-suffixed-type-alias` (`PYI043`) example ([#8963](https://github.com/astral-sh/ruff/pull/8963)) +- \[`flake8-pyi`\] Improve motivation for `custom-type-var-return-type` (`PYI019`) ([#8766](https://github.com/astral-sh/ruff/pull/8766)) + ## 0.1.6 ### Preview features diff --git a/Cargo.lock b/Cargo.lock index 0aa607423cb3e..0f2c658a7ac7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -808,7 +808,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flake8-to-ruff" -version = "0.1.6" +version = "0.1.7" dependencies = [ "anyhow", "clap", @@ -2062,7 +2062,7 @@ dependencies = [ [[package]] name = "ruff_cli" -version = "0.1.6" +version = "0.1.7" dependencies = [ "annotate-snippets 0.9.2", "anyhow", @@ -2198,7 +2198,7 @@ dependencies = [ [[package]] name = "ruff_linter" -version = "0.1.6" +version = "0.1.7" dependencies = [ "aho-corasick", "annotate-snippets 0.9.2", @@ -2450,7 +2450,7 @@ dependencies = [ [[package]] name = "ruff_shrinking" -version = "0.1.6" +version = "0.1.7" dependencies = [ "anyhow", "clap", diff --git a/README.md b/README.md index 2cb126aea6b94..82884d86df3aa 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff ```yaml - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.6 + rev: v0.1.7 hooks: # Run the linter. - id: ruff diff --git a/crates/flake8_to_ruff/Cargo.toml b/crates/flake8_to_ruff/Cargo.toml index b17abde1a880d..cf87a0c39a90e 100644 --- a/crates/flake8_to_ruff/Cargo.toml +++ b/crates/flake8_to_ruff/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "flake8-to-ruff" -version = "0.1.6" +version = "0.1.7" description = """ Convert Flake8 configuration files to Ruff configuration files. """ diff --git a/crates/ruff_cli/Cargo.toml b/crates/ruff_cli/Cargo.toml index 12bb66e10fea8..21fa5ddacd64a 100644 --- a/crates/ruff_cli/Cargo.toml +++ b/crates/ruff_cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ruff_cli" -version = "0.1.6" +version = "0.1.7" publish = false authors = { workspace = true } edition = { workspace = true } diff --git a/crates/ruff_linter/Cargo.toml b/crates/ruff_linter/Cargo.toml index 6f129984ffb8b..fcbc1121a0912 100644 --- a/crates/ruff_linter/Cargo.toml +++ b/crates/ruff_linter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ruff_linter" -version = "0.1.6" +version = "0.1.7" publish = false authors = { workspace = true } edition = { workspace = true } diff --git a/crates/ruff_shrinking/Cargo.toml b/crates/ruff_shrinking/Cargo.toml index f93e1e2f5c64e..c390d646fa5df 100644 --- a/crates/ruff_shrinking/Cargo.toml +++ b/crates/ruff_shrinking/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ruff_shrinking" -version = "0.1.6" +version = "0.1.7" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/docs/integrations.md b/docs/integrations.md index c9babce79c06a..831fcd3f18315 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -14,7 +14,7 @@ Ruff can be used as a [pre-commit](https://pre-commit.com) hook via [`ruff-pre-c ```yaml - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.6 + rev: v0.1.7 hooks: # Run the linter. - id: ruff @@ -27,7 +27,7 @@ To enable lint fixes, add the `--fix` argument to the lint hook: ```yaml - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.6 + rev: v0.1.7 hooks: # Run the linter. - id: ruff @@ -41,7 +41,7 @@ To run the hooks over Jupyter Notebooks too, add `jupyter` to the list of allowe ```yaml - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.6 + rev: v0.1.7 hooks: # Run the linter. - id: ruff diff --git a/pyproject.toml b/pyproject.toml index 3d9facb8c9692..981dca4ca291b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "ruff" -version = "0.1.6" +version = "0.1.7" description = "An extremely fast Python linter and code formatter, written in Rust." authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }] readme = "README.md" diff --git a/scripts/benchmarks/pyproject.toml b/scripts/benchmarks/pyproject.toml index fedde2ac9d22a..669c6f794d7b4 100644 --- a/scripts/benchmarks/pyproject.toml +++ b/scripts/benchmarks/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "scripts" -version = "0.1.6" +version = "0.1.7" description = "" authors = ["Charles Marsh "] From b7ffd73edd38a1d878c4b607340414ed4779ec5b Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 4 Dec 2023 18:38:01 -0500 Subject: [PATCH 113/197] Ignore `@overrides` and `@overloads` for `too-many-positional` (#9000) Same as `too-many-arguments`. --- .../src/checkers/ast/analyze/statement.rs | 2 +- .../rules/pylint/rules/too_many_positional.rs | 21 ++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 0f05d6165b22e..afb80e227a539 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -251,7 +251,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { pylint::rules::too_many_arguments(checker, function_def); } if checker.enabled(Rule::TooManyPositional) { - pylint::rules::too_many_positional(checker, parameters, stmt); + pylint::rules::too_many_positional(checker, function_def); } if checker.enabled(Rule::TooManyReturnStatements) { if let Some(diagnostic) = pylint::rules::too_many_return_statements( diff --git a/crates/ruff_linter/src/rules/pylint/rules/too_many_positional.rs b/crates/ruff_linter/src/rules/pylint/rules/too_many_positional.rs index 369b6c63bc6e9..bc424441c0b7d 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/too_many_positional.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/too_many_positional.rs @@ -1,6 +1,7 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{identifier::Identifier, Parameters, Stmt}; +use ruff_python_ast::{self as ast, identifier::Identifier}; +use ruff_python_semantic::analyze::visibility; use crate::checkers::ast::Checker; @@ -55,11 +56,12 @@ impl Violation for TooManyPositional { } /// PLR0917 -pub(crate) fn too_many_positional(checker: &mut Checker, parameters: &Parameters, stmt: &Stmt) { - let num_positional_args = parameters +pub(crate) fn too_many_positional(checker: &mut Checker, function_def: &ast::StmtFunctionDef) { + let num_positional_args = function_def + .parameters .args .iter() - .chain(¶meters.posonlyargs) + .chain(&function_def.parameters.posonlyargs) .filter(|arg| { !checker .settings @@ -67,13 +69,22 @@ pub(crate) fn too_many_positional(checker: &mut Checker, parameters: &Parameters .is_match(&arg.parameter.name) }) .count(); + if num_positional_args > checker.settings.pylint.max_positional_args { + // Allow excessive arguments in `@override` or `@overload` methods, since they're required + // to adhere to the parent signature. + if visibility::is_override(&function_def.decorator_list, checker.semantic()) + || visibility::is_overload(&function_def.decorator_list, checker.semantic()) + { + return; + } + checker.diagnostics.push(Diagnostic::new( TooManyPositional { c_pos: num_positional_args, max_pos: checker.settings.pylint.max_positional_args, }, - stmt.identifier(), + function_def.identifier(), )); } } From fe54ef08aa5876b3a3be283514c3a66e2181a82e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 00:00:40 +0000 Subject: [PATCH 114/197] Bump CodSpeedHQ/action from 1 to 2 (#8989) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 32d803aa1407c..749caccb064c0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -502,7 +502,7 @@ jobs: run: cargo codspeed build --features codspeed -p ruff_benchmark - name: "Run benchmarks" - uses: CodSpeedHQ/action@v1 + uses: CodSpeedHQ/action@v2 with: run: cargo codspeed run token: ${{ secrets.CODSPEED_TOKEN }} From fd49fb935f408c11b47b9311b2e808191256e853 Mon Sep 17 00:00:00 2001 From: Ofek Lev Date: Tue, 5 Dec 2023 13:55:15 -0500 Subject: [PATCH 115/197] Fix example for PLR0203 (#9011) --- .../ruff_linter/src/rules/pylint/rules/no_method_decorator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/src/rules/pylint/rules/no_method_decorator.rs b/crates/ruff_linter/src/rules/pylint/rules/no_method_decorator.rs index d2dc1ea329484..60439119fd703 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/no_method_decorator.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/no_method_decorator.rs @@ -53,7 +53,7 @@ impl AlwaysFixableViolation for NoClassmethodDecorator { /// ## Example /// ```python /// class Foo: -/// def bar(cls): +/// def bar(arg1, arg2): /// ... /// /// bar = staticmethod(bar) @@ -63,7 +63,7 @@ impl AlwaysFixableViolation for NoClassmethodDecorator { /// ```python /// class Foo: /// @staticmethod -/// def bar(cls): +/// def bar(arg1, arg2): /// ... /// ``` #[violation] From c48ba690eb58bf147cc1d67da04fea41a3cd52a4 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Tue, 5 Dec 2023 14:14:44 -0500 Subject: [PATCH 116/197] add support for formatting reStructuredText code snippets (#9003) (This is not possible to actually use until https://github.com/astral-sh/ruff/pull/8854 is merged.) ruff_python_formatter: add reStructuredText docstring formatting support This commit makes use of the refactoring done in prior commits to slot in reStructuredText support. Essentially, we add a new type of code example and look for *both* literal blocks and code block directives. Literal blocks are treated as Python by default because it seems to be a [common practice](https://github.com/adamchainz/blacken-docs/issues/195). That is, literal blocks like this: ``` def example(): """ Here's an example:: foo( 1 ) All done. """ pass ``` Will get reformatted. And code blocks (via reStructuredText directives) will also get reformatted: ``` def example(): """ Here's an example: .. code-block:: python foo( 1 ) All done. """ pass ``` When looking for a code block, it is possible for it to become invalid. In which case, we back out of looking for a code example and print the lines out as they are. As with doctest formatting, if reformatting the code would result in invalid Python or if the code collected from the block is invalid, then formatting is also skipped. A number of tests have been added to check both the formatting and resetting behavior. Mixed indentation is also tested a fair bit, since one of my initial attempts at dealing with mixed indentation ended up not working. I recommend working through this PR commit-by-commit. There is in particular a somewhat gnarly refactoring before reST support is added. Closes #8859 --- crates/ruff_python_formatter/Cargo.toml | 1 + .../fixtures/ruff/docstring_code_examples.py | 505 ++ .../src/expression/string/docstring.rs | 685 +- .../ruff_python_formatter/tests/normalizer.rs | 19 +- .../format@docstring_code_examples.py.snap | 7477 +++++++++++++---- 5 files changed, 7121 insertions(+), 1566 deletions(-) diff --git a/crates/ruff_python_formatter/Cargo.toml b/crates/ruff_python_formatter/Cargo.toml index 5bc38d4960f15..1c8825b3aff35 100644 --- a/crates/ruff_python_formatter/Cargo.toml +++ b/crates/ruff_python_formatter/Cargo.toml @@ -28,6 +28,7 @@ countme = "3.0.1" itertools = { workspace = true } memchr = { workspace = true } once_cell = { workspace = true } +regex = { workspace = true } rustc-hash = { workspace = true } serde = { workspace = true, optional = true } schemars = { workspace = true, optional = true } diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py index 6f5fc0b30bb61..296da3d816545 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py @@ -67,6 +67,27 @@ def doctest_last_line_continued(): pass +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x )""" + pass + + +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + ... more( y )""" + pass + + # Test that a doctest is correctly identified and formatted with a blank # continuation line. def doctest_blank_continued(): @@ -323,3 +344,487 @@ def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): >>> x = '\"\"\"' """ pass + + +############################################################################### +# reStructuredText CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# reStructuredText formatted code blocks. +# +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +############################################################################### + + +def rst_literal_simple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_literal_simple_continued(): + """ + Do cool stuff:: + + def cool_stuff( x ): + print( f"hi {x}" ); + + Done. + """ + pass + + +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + """ + pass + + +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: + + cool_stuff( 1 )""" + pass + + +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: + + def cool_stuff( x ): + print( f"hi {x}" ); + + def other_stuff( y ): + print( y ) + + Done. + """ + pass + + +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: + + + + cool_stuff( 1 ) + + + + Done. + """ + pass + + +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: + + + cool_stuff( 1 ) + + + + """ + pass + + +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + + cool_stuff( 2 ) + + Done. + """ + pass + + +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. +# +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ + Do cool stuff. + + :: + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_simple(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_case_insensitive(): + """ + .. cOdE-bLoCk:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_sourcecode(): + """ + .. sourcecode:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + + cool_stuff( 1 ) + cool_stuff( 2 ) + cool_stuff( 3 ) + cool_stuff( 4 ) + + Done. + """ + pass + + +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. +# +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python + + >>> cool_stuff( 1 ) + + Done. + """ + pass diff --git a/crates/ruff_python_formatter/src/expression/string/docstring.rs b/crates/ruff_python_formatter/src/expression/string/docstring.rs index bed24c34191c0..41f350bd4deb2 100644 --- a/crates/ruff_python_formatter/src/expression/string/docstring.rs +++ b/crates/ruff_python_formatter/src/expression/string/docstring.rs @@ -1,8 +1,14 @@ -use std::borrow::Cow; +// This gives tons of false positives in this file because of +// "reStructuredText." +#![allow(clippy::doc_markdown)] + +use std::{borrow::Cow, collections::VecDeque}; + +use {once_cell::sync::Lazy, regex::Regex}; -use ruff_python_trivia::PythonWhitespace; use { - ruff_formatter::{write, Printed}, + ruff_formatter::{write, IndentStyle, Printed}, + ruff_python_trivia::{is_python_whitespace, PythonWhitespace}, ruff_source_file::Locator, ruff_text_size::{Ranged, TextLen, TextRange, TextSize}, }; @@ -182,6 +188,7 @@ pub(super) fn format(normalized: &NormalizedString, f: &mut PyFormatter) -> Form DocstringLinePrinter { f, + action_queue: VecDeque::new(), offset, stripped_indentation_length, already_normalized, @@ -218,17 +225,34 @@ fn contains_unescaped_newline(haystack: &str) -> bool { /// An abstraction for printing each line of a docstring. struct DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { f: &'fmt mut PyFormatter<'ast, 'buf>, + + /// A queue of actions to perform. + /// + /// Whenever we process a line, it is possible for it to generate multiple + /// actions to take. The most basic, and most common case, is for the line + /// to just simply be printed as-is. But in some cases, a line is part of + /// a code example that we'd like to reformat. In those cases, the actions + /// can be more complicated. + /// + /// Actions are pushed on to the end of the queue and popped from the + /// beginning. + action_queue: VecDeque>, + /// The source offset of the beginning of the line that is currently being /// printed. offset: TextSize, + /// Indentation alignment based on the least indented line in the /// docstring. stripped_indentation_length: TextSize, + /// Whether the docstring is overall already considered normalized. When it /// is, the formatter can take a fast path. already_normalized: bool, + /// The quote style used by the docstring being printed. quote_style: QuoteStyle, + /// The current code example detected in the docstring. code_example: CodeExample<'src>, } @@ -253,7 +277,8 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { self.offset += line.line.text_len() + "\n".text_len(); self.add_one(line)?; } - Ok(()) + self.code_example.finish(&mut self.action_queue); + self.run_action_queue() } /// Adds the given line to this printer. @@ -273,34 +298,40 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { { return self.print_one(&line.as_output()); } - match self.code_example.add(line) { - CodeExampleAddAction::Print { original } => self.print_one(&original.as_output())?, - CodeExampleAddAction::Kept => {} - CodeExampleAddAction::Reset { code, original } => { - for codeline in code { - self.print_one(&codeline.original.as_output())?; + self.code_example.add(line, &mut self.action_queue); + self.run_action_queue() + } + + /// Process any actions in this printer's queue until the queue is empty. + fn run_action_queue(&mut self) -> FormatResult<()> { + while let Some(action) = self.action_queue.pop_front() { + match action { + CodeExampleAddAction::Print { original } => { + self.print_one(&original.as_output())?; } - self.print_one(&original.as_output())?; - } - CodeExampleAddAction::Format { mut kind, original } => { - let Some(formatted_lines) = self.format(kind.code())? else { - // If formatting failed in a way that should not be - // allowed, we back out what we're doing and print the - // original lines we found as-is as if we did nothing. - for codeline in kind.code() { + CodeExampleAddAction::Kept => {} + CodeExampleAddAction::Reset { code } => { + for codeline in code { self.print_one(&codeline.original.as_output())?; } - if let Some(original) = original { - self.print_one(&original.as_output())?; - } - return Ok(()); - }; + } + CodeExampleAddAction::Format { mut kind } => { + let Some(formatted_lines) = self.format(kind.code())? else { + // Since we've failed to emit these lines, we need to + // put them back in the queue but have them jump to the + // front of the queue to get processed before any other + // action. + self.action_queue.push_front(CodeExampleAddAction::Reset { + code: kind.into_code(), + }); + continue; + }; - self.already_normalized = false; - match kind { - CodeExampleKind::Doctest(CodeExampleDoctest { ps1_indent, .. }) => { - let mut lines = formatted_lines.into_iter(); - if let Some(first) = lines.next() { + self.already_normalized = false; + match kind { + CodeExampleKind::Doctest(CodeExampleDoctest { ps1_indent, .. }) => { + let mut lines = formatted_lines.into_iter(); + let Some(first) = lines.next() else { continue }; self.print_one( &first.map(|line| std::format!("{ps1_indent}>>> {line}")), )?; @@ -310,11 +341,21 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { )?; } } + CodeExampleKind::Rst(litblock) => { + let Some(min_indent) = litblock.min_indent else { + continue; + }; + // This looks suspicious, but it's consistent with the whitespace + // normalization that will occur anyway. + let indent = " ".repeat(min_indent.to_usize()); + for docline in formatted_lines { + self.print_one( + &docline.map(|line| std::format!("{indent}{line}")), + )?; + } + } } } - if let Some(original) = original { - self.print_one(&original.as_output())?; - } } } Ok(()) @@ -395,32 +436,37 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { /// routine is silent about it. So from the user's perspective, this will /// fail silently. Ideally, this would at least emit a warning message, /// but at time of writing, it wasn't clear to me how to best do that. - /// - /// # Panics - /// - /// This panics when the given slice is empty. fn format( &mut self, code: &[CodeExampleLine<'_>], ) -> FormatResult>>> { use ruff_python_parser::AsMode; - let offset = code - .get(0) - .expect("code blob must be non-empty") - .original - .offset; - let last_line_is_last = code - .last() - .expect("code blob must be non-empty") - .original - .is_last(); + let (Some(unformatted_first), Some(unformatted_last)) = (code.first(), code.last()) else { + return Ok(None); + }; let codeblob = code .iter() .map(|line| line.code) .collect::>() .join("\n"); - let printed = match docstring_format_source(self.f.options(), self.quote_style, &codeblob) { + let options = self + .f + .options() + .clone() + // It's perhaps a little odd to be hard-coding the indent + // style here, but I believe it is necessary as a result + // of the whitespace normalization otherwise done in + // docstrings. Namely, tabs are rewritten with ASCII + // spaces. If code examples in docstrings are formatted + // with tabs and those tabs end up getting rewritten, this + // winds up screwing with the indentation in ways that + // results in formatting no longer being idempotent. Since + // tabs will get erased anyway, we just clobber them here + // instead of later, and as a result, get more consistent + // results. + .with_indent_style(IndentStyle::Space); + let printed = match docstring_format_source(options, self.quote_style, &codeblob) { Ok(printed) => printed, Err(FormatModuleError::FormatError(err)) => return Err(err), Err( @@ -461,12 +507,12 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { .lines() .map(|line| OutputDocstringLine { line: Cow::Owned(line.to_string()), - offset, + offset: unformatted_first.original.offset, is_last: false, }) .collect::>(); - if let Some(last) = lines.last_mut() { - last.is_last = last_line_is_last; + if let Some(reformatted_last) = lines.last_mut() { + reformatted_last.is_last = unformatted_last.original.is_last(); } Ok(Some(lines)) } @@ -485,8 +531,10 @@ struct InputDocstringLine<'src> { /// unformatted line in a docstring, and owned when it corresponds to a /// reformatted line (e.g., from a code snippet) in a docstring. line: &'src str, + /// The offset into the source document which this line corresponds to. offset: TextSize, + /// For any input line that isn't the last line, this contains a reference /// to the line immediately following this one. /// @@ -525,9 +573,11 @@ struct OutputDocstringLine<'src> { /// a line from a reformatted code snippet. In other cases, it is borrowed /// from the input docstring line as-is. line: Cow<'src, str>, + /// The offset into the source document which this line corresponds to. /// Currently, this is an estimate. offset: TextSize, + /// Whether this is the last line in a docstring or not. This is determined /// by whether the last line in the code snippet was also the last line in /// the docstring. If it was, then it follows that the last line in the @@ -568,38 +618,51 @@ impl<'src> CodeExample<'src> { /// Attempt to add an original line from a docstring to this code example. /// /// Based on the line and the internal state of whether a code example is - /// currently being collected or not, this will return an "action" for - /// the caller to perform. The typical case is a "print" action, which - /// instructs the caller to just print the line as though it were not part - /// of a code snippet. - fn add(&mut self, original: InputDocstringLine<'src>) -> CodeExampleAddAction<'src> { + /// currently being collected or not, this will push an "action" to the + /// given queue for the caller to perform. The typical case is a "print" + /// action, which instructs the caller to just print the line as though it + /// were not part of a code snippet. + fn add( + &mut self, + original: InputDocstringLine<'src>, + queue: &mut VecDeque>, + ) { match self.kind.take() { // There's no existing code example being built, so we look for // the start of one or otherwise tell the caller we couldn't find // anything. - None => match self.add_start(original) { - None => CodeExampleAddAction::Kept, - Some(original) => CodeExampleAddAction::Print { original }, - }, - Some(CodeExampleKind::Doctest(mut doctest)) => { - if doctest.add_code_line(original) { - // Stay with the doctest kind while we accumulate all - // PS2 prompts. - self.kind = Some(CodeExampleKind::Doctest(doctest)); - return CodeExampleAddAction::Kept; - } - let original = self.add_start(original); - CodeExampleAddAction::Format { - kind: CodeExampleKind::Doctest(doctest), - original, - } + None => { + self.add_start(original, queue); + } + Some(CodeExampleKind::Doctest(doctest)) => { + let Some(doctest) = doctest.add_code_line(original, queue) else { + self.add_start(original, queue); + return; + }; + self.kind = Some(CodeExampleKind::Doctest(doctest)); + } + Some(CodeExampleKind::Rst(litblock)) => { + let Some(litblock) = litblock.add_code_line(original, queue) else { + self.add_start(original, queue); + return; + }; + self.kind = Some(CodeExampleKind::Rst(litblock)); } } } + /// Finish the code example by generating any final actions if applicable. + /// + /// This typically adds an action when the end of a code example coincides + /// with the end of the docstring. + fn finish(&mut self, queue: &mut VecDeque>) { + let Some(kind) = self.kind.take() else { return }; + queue.push_back(CodeExampleAddAction::Format { kind }); + } + /// Looks for the start of a code example. If one was found, then the given /// line is kept and added as part of the code example. Otherwise, the line - /// is returned unchanged and no code example was found. + /// is pushed onto the queue unchanged to be printed as-is. /// /// # Panics /// @@ -609,13 +672,18 @@ impl<'src> CodeExample<'src> { fn add_start( &mut self, original: InputDocstringLine<'src>, - ) -> Option> { + queue: &mut VecDeque>, + ) { assert!(self.kind.is_none(), "expected no existing code example"); if let Some(doctest) = CodeExampleDoctest::new(original) { self.kind = Some(CodeExampleKind::Doctest(doctest)); - return None; + queue.push_back(CodeExampleAddAction::Kept); + } else if let Some(litblock) = CodeExampleRst::new(original) { + self.kind = Some(CodeExampleKind::Rst(litblock)); + queue.push_back(CodeExampleAddAction::Print { original }); + } else { + queue.push_back(CodeExampleAddAction::Print { original }); } - Some(original) } } @@ -633,6 +701,12 @@ enum CodeExampleKind<'src> { /// /// [regex matching]: https://github.com/python/cpython/blob/0ff6368519ed7542ad8b443de01108690102420a/Lib/doctest.py#L611-L622 Doctest(CodeExampleDoctest<'src>), + /// Code found from a reStructuredText "[literal block]" or "[code block + /// directive]". + /// + /// [literal block]: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks + /// [code block directive]: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block + Rst(CodeExampleRst<'src>), } impl<'src> CodeExampleKind<'src> { @@ -643,6 +717,20 @@ impl<'src> CodeExampleKind<'src> { fn code(&mut self) -> &[CodeExampleLine<'src>] { match *self { CodeExampleKind::Doctest(ref doctest) => &doctest.lines, + CodeExampleKind::Rst(ref mut litblock) => litblock.indented_code(), + } + } + + /// Consume this code example and return only the lines that have been + /// accrued so far. + /// + /// This is useful when the code example being collected has been + /// determined to be invalid, and one wants to "give up" and print the + /// original lines through unchanged without attempting formatting. + fn into_code(self) -> Vec> { + match self { + CodeExampleKind::Doctest(doctest) => doctest.lines, + CodeExampleKind::Rst(litblock) => litblock.lines, } } } @@ -652,6 +740,7 @@ impl<'src> CodeExampleKind<'src> { struct CodeExampleDoctest<'src> { /// The lines that have been seen so far that make up the doctest. lines: Vec>, + /// The indent observed in the first doctest line. /// /// More precisely, this corresponds to the whitespace observed before @@ -681,19 +770,24 @@ impl<'src> CodeExampleDoctest<'src> { Some(doctest) } - /// Looks for a valid doctest PS2 prompt in the line given. + /// Looks for a valid doctest PS2 prompt in the line given. If one is + /// found, it is added to this code example and ownership of the example is + /// returned to the caller. In this case, callers should continue trying to + /// add PS2 prompt lines. /// - /// If one is found, then the code portion of the line following the PS2 prompt - /// is returned. + /// But if one isn't found, then the given line is not part of the code + /// example and ownership of this example is not returned. /// - /// Callers must provide a string containing the original indentation of the - /// PS1 prompt that started the doctest containing the potential PS2 prompt - /// in the line given. If the line contains a PS2 prompt, its indentation must - /// match the indentation used for the corresponding PS1 prompt (otherwise - /// `None` will be returned). - fn add_code_line(&mut self, original: InputDocstringLine<'src>) -> bool { + /// In either case, relevant actions will be added to the given queue to + /// process. + fn add_code_line( + mut self, + original: InputDocstringLine<'src>, + queue: &mut VecDeque>, + ) -> Option> { let Some((ps2_indent, ps2_after)) = original.line.split_once("...") else { - return false; + queue.push_back(self.into_format_action()); + return None; }; // PS2 prompts must have the same indentation as their // corresponding PS1 prompt.[1] While the 'doctest' Python @@ -702,7 +796,8 @@ impl<'src> CodeExampleDoctest<'src> { // // [1]: https://github.com/python/cpython/blob/0ff6368519ed7542ad8b443de01108690102420a/Lib/doctest.py#L733 if self.ps1_indent != ps2_indent { - return false; + queue.push_back(self.into_format_action()); + return None; } // PS2 prompts must be followed by an ASCII space character unless // it's an otherwise empty line[1]. @@ -710,11 +805,354 @@ impl<'src> CodeExampleDoctest<'src> { // [1]: https://github.com/python/cpython/blob/0ff6368519ed7542ad8b443de01108690102420a/Lib/doctest.py#L809-L812 let code = match ps2_after.strip_prefix(' ') { None if ps2_after.is_empty() => "", - None => return false, + None => { + queue.push_back(self.into_format_action()); + return None; + } Some(code) => code, }; self.lines.push(CodeExampleLine { original, code }); - true + queue.push_back(CodeExampleAddAction::Kept); + Some(self) + } + + /// Consume this doctest and turn it into a formatting action. + fn into_format_action(self) -> CodeExampleAddAction<'src> { + CodeExampleAddAction::Format { + kind: CodeExampleKind::Doctest(self), + } + } +} + +/// State corresponding to a single reStructuredText literal block or +/// code-block directive. +/// +/// While a literal block and code-block directive are technically two +/// different reStructuredText constructs, we use one type to represent +/// both because they are exceptionally similar. Basically, they are +/// the same with two main differences: +/// +/// 1. Literal blocks are began with a line that ends with `::`. Code block +/// directives are began with a line like `.. code-block:: python`. +/// 2. Code block directives permit a list of options as a "field list" +/// immediately after the opening line. Literal blocks have no options. +/// +/// Otherwise, everything else, including the indentation structure, is the +/// same. +#[derive(Debug)] +struct CodeExampleRst<'src> { + /// The lines that have been seen so far that make up the block. + lines: Vec>, + + /// The indent of the line "opening" this block measured via + /// `indentation_length`. + /// + /// It can either be the indent of a line ending with `::` (for a literal + /// block) or the indent of a line starting with `.. ` (a directive). + /// + /// The content body of a block needs to be indented more than the line + /// opening the block, so we use this indentation to look for indentation + /// that is "more than" it. + opening_indent: TextSize, + + /// The minimum indent of the block measured via `indentation_length`. + /// + /// This is `None` until the first such line is seen. If no such line is + /// found, then we consider it an invalid block and bail out of trying to + /// find a code snippet. Otherwise, we update this indentation as we see + /// lines in the block with less indentation. (Usually, the minimum is the + /// indentation of the first block, but this is not required.) + /// + /// By construction, all lines part of the block must have at least this + /// indentation. Additionally, it is guaranteed that the indentation length + /// of the opening indent is strictly less than the indentation of the + /// minimum indent. Namely, the block ends once we find a line that has + /// been unindented to at most the indent of the opening line. + /// + /// When the code snippet has been extracted, it is re-built before being + /// reformatted. The minimum indent is stripped from each line when it is + /// re-built. + min_indent: Option, + + /// Whether this is a directive block or not. When not a directive, this is + /// a literal block. The main difference between them is that they start + /// differently. A literal block is started merely by trailing a line with + /// `::`. A directive block is started with `.. code-block:: python`. + /// + /// The other difference is that directive blocks can have options + /// (represented as a reStructuredText "field list") after the beginning of + /// the directive and before the body content of the directive. + is_directive: bool, +} + +impl<'src> CodeExampleRst<'src> { + /// Looks for the start of a reStructuredText [literal block] or [code + /// block directive]. + /// + /// If the start of a block is found, then this returns a correctly + /// initialized reStructuredText block. Callers should print the line as + /// given as it is not retained as part of the block. + /// + /// [literal block]: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks + /// [code block directive]: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block + fn new(original: InputDocstringLine<'src>) -> Option { + let (opening_indent, rest) = indent_with_suffix(original.line); + if rest.starts_with(".. ") { + if let Some(litblock) = CodeExampleRst::new_code_block(original) { + return Some(litblock); + } + // In theory, we could still have something that looks like a literal block, + // but if the line starts with `.. `, then it seems like it probably shouldn't + // be a literal block. For example: + // + // .. code-block:: + // + // cool_stuff( 1 ) + // + // The above is not valid because the `language` argument is missing from + // the `code-block` directive. Because of how we handle it here, the above + // is not treated as a code snippet. + return None; + } + // At this point, we know we didn't find a code block, so the only + // thing we can hope for is a literal block which must end with a `::`. + if !rest.trim_end().ends_with("::") { + return None; + } + Some(CodeExampleRst { + lines: vec![], + opening_indent: indentation_length(opening_indent), + min_indent: None, + is_directive: false, + }) + } + + /// Attempts to create a new reStructuredText code example from a + /// `code-block` or `sourcecode` directive. If one couldn't be found, then + /// `None` is returned. + fn new_code_block(original: InputDocstringLine<'src>) -> Option { + // This regex attempts to parse the start of a reStructuredText code + // block [directive]. From the reStructuredText spec: + // + // > Directives are indicated by an explicit markup start (".. ") + // > followed by the directive type, two colons, and whitespace + // > (together called the "directive marker"). Directive types + // > are case-insensitive single words (alphanumerics plus + // > isolated internal hyphens, underscores, plus signs, colons, + // > and periods; no whitespace). + // + // The language names matched here (e.g., `python` or `py`) are taken + // from the [Pygments lexer names], which is referenced from the docs + // for the [code-block] directive. + // + // [directives]: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#directives + // [Pygments lexer names]: https://pygments.org/docs/lexers/ + // [code-block]: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block + static DIRECTIVE_START: Lazy = Lazy::new(|| { + Regex::new( + r"(?m)^\s*\.\. \s*(?i:code-block|sourcecode)::\s*(?i:python|py|python3|py3)$", + ) + .unwrap() + }); + if !DIRECTIVE_START.is_match(original.line) { + return None; + } + Some(CodeExampleRst { + lines: vec![], + opening_indent: indentation_length(original.line), + min_indent: None, + is_directive: true, + }) + } + + /// Returns the code collected in this example as a sequence of lines. + /// + /// The lines returned have the minimum indentation stripped from their + /// prefix in-place. Based on the definition of minimum indentation, this + /// implies there is at least one line in the slice returned with no + /// whitespace prefix. + fn indented_code(&mut self) -> &[CodeExampleLine<'src>] { + let Some(min_indent) = self.min_indent else { + return &[]; + }; + for line in &mut self.lines { + line.code = if line.original.line.trim().is_empty() { + "" + } else { + indentation_trim(min_indent, line.original.line) + }; + } + &self.lines + } + + /// Attempts to add the given line from a docstring to the reStructuredText + /// code snippet being collected. + /// + /// This takes ownership of `self`, and if ownership is returned to the + /// caller, that means the caller should continue trying to add lines to + /// this code snippet. Otherwise, if ownership is not returned, then this + /// implies at least one action was added to the give queue to either reset + /// the code block or format. That is, the code snippet was either found to + /// be invalid or it was completed and should be reformatted. + /// + /// Note that actions may be added even if ownership is returned. For + /// example, empty lines immediately preceding the actual code snippet will + /// be returned back as an action to print them verbatim, but the caller + /// should still continue to try to add lines to this code snippet. + fn add_code_line( + mut self, + original: InputDocstringLine<'src>, + queue: &mut VecDeque>, + ) -> Option> { + // If we haven't started populating the minimum indent yet, then + // we haven't found the first code line and may need to find and + // pass through leading empty lines. + let Some(min_indent) = self.min_indent else { + return self.add_first_line(original, queue); + }; + let (indent, rest) = indent_with_suffix(original.line); + if rest.is_empty() { + // This is the standard way we close a block: when we see + // an empty line followed by an unindented non-empty line. + if let Some(next) = original.next { + let (next_indent, next_rest) = indent_with_suffix(next); + if !next_rest.is_empty() && indentation_length(next_indent) <= self.opening_indent { + self.push_format_action(queue); + return None; + } + } else { + self.push_format_action(queue); + return None; + } + self.push(original); + queue.push_back(CodeExampleAddAction::Kept); + return Some(self); + } + let indent_len = indentation_length(indent); + if indent_len <= self.opening_indent { + // If we find an unindented non-empty line at the same (or less) + // indentation of the opening line at this point, then we know it + // must be wrong because we didn't see it immediately following an + // empty line. + queue.push_back(self.into_reset_action()); + return None; + } else if indent_len < min_indent { + // While the minimum indent is usually the indentation of the first + // line in a code snippet, it is not guaranteed to be the case. + // And indeed, reST is happy to let blocks have a first line whose + // indentation is greater than a subsequent line in the block. The + // only real restriction is that every line in the block must be + // indented at least past the indentation of the `::` line. + self.min_indent = Some(indent_len); + } + self.push(original); + queue.push_back(CodeExampleAddAction::Kept); + Some(self) + } + + /// Looks for the first line in a literal or code block. + /// + /// If a first line is found, then this returns true. Otherwise, an empty + /// line has been found and the caller should pass it through to the + /// docstring unchanged. (Empty lines are allowed to precede a + /// block. And there must be at least one of them.) + /// + /// If the given line is invalid for a reStructuredText block (i.e., no + /// empty lines seen between the opening line), then an error variant is + /// returned. In this case, callers should bail out of parsing this code + /// example. + /// + /// When this returns `true`, it is guaranteed that `self.min_indent` is + /// set to a non-None value. + /// + /// # Panics + /// + /// Callers must only call this when the first indentation has not yet been + /// found. If it has, then this panics. + fn add_first_line( + mut self, + original: InputDocstringLine<'src>, + queue: &mut VecDeque>, + ) -> Option> { + assert!(self.min_indent.is_none()); + + // While the rst spec isn't completely clear on this point, through + // experimentation, I found that multiple empty lines before the first + // non-empty line are ignored. + let (indent, rest) = indent_with_suffix(original.line); + if rest.is_empty() { + queue.push_back(CodeExampleAddAction::Print { original }); + return Some(self); + } + // Ignore parameters in field lists. These can only occur in + // directives, not literal blocks. + if self.is_directive && is_rst_option(rest) { + queue.push_back(CodeExampleAddAction::Print { original }); + return Some(self); + } + let min_indent = indentation_length(indent); + // At this point, we found a non-empty line. The only thing we require + // is that its indentation is strictly greater than the indentation of + // the line containing the `::`. Otherwise, we treat this as an invalid + // block and bail. + if min_indent <= self.opening_indent { + queue.push_back(self.into_reset_action()); + return None; + } + self.min_indent = Some(min_indent); + self.push(original); + queue.push_back(CodeExampleAddAction::Kept); + Some(self) + } + + /// Pushes the given line as part of this code example. + fn push(&mut self, original: InputDocstringLine<'src>) { + // N.B. We record the code portion as identical to the original line. + // When we go to reformat the code lines, we change them by removing + // the `min_indent`. This design is necessary because the true value of + // `min_indent` isn't known until the entire block has been parsed. + let code = original.line; + self.lines.push(CodeExampleLine { original, code }); + } + + /// Consume this block and add actions to the give queue for formatting. + /// + /// This may trim lines from the end of the block and add them to the queue + /// for printing as-is. For example, this happens when there are trailing + /// empty lines, as we would like to preserve those since they aren't + /// generally treated as part of the code block. + fn push_format_action(mut self, queue: &mut VecDeque>) { + let has_non_whitespace = |line: &CodeExampleLine| { + line.original + .line + .chars() + .any(|ch| !is_python_whitespace(ch)) + }; + let first_trailing_empty_line = self + .lines + .iter() + .rposition(has_non_whitespace) + .map_or(0, |i| i + 1); + let trailing_lines = self.lines.split_off(first_trailing_empty_line); + queue.push_back(CodeExampleAddAction::Format { + kind: CodeExampleKind::Rst(self), + }); + queue.extend( + trailing_lines + .into_iter() + .map(|line| CodeExampleAddAction::Print { + original: line.original, + }), + ); + } + + /// Consume this block and turn it into a reset action. + /// + /// This occurs when we started collecting a code example from something + /// that looked like a block, but later determined that it wasn't a valid + /// block. + fn into_reset_action(self) -> CodeExampleAddAction<'src> { + CodeExampleAddAction::Reset { code: self.lines } } } @@ -737,6 +1175,7 @@ struct CodeExampleLine<'src> { /// example, contain a `>>> ` or `... ` prefix if this code example is a /// doctest. original: InputDocstringLine<'src>, + /// The code extracted from the line. code: &'src str, } @@ -763,20 +1202,10 @@ enum CodeExampleAddAction<'src> { Kept, /// The line added indicated that the code example is finished and should /// be formatted and printed. The line added is not treated as part of - /// the code example. If the line added indicated the start of another - /// code example, then is won't be returned to the caller here. Otherwise, - /// callers should pass it through to the formatter as-is. + /// the code example. Format { /// The kind of code example that was found. - /// - /// This is guaranteed to have a non-empty code snippet. kind: CodeExampleKind<'src>, - /// When set, the line is considered not part of any code example and - /// should be formatted as if the [`Print`] action were returned. - /// Otherwise, if there is no line, then either one does not exist - /// or it is part of another code example and should be treated as a - /// [`Kept`] action. - original: Option>, }, /// This occurs when adding a line to an existing code example /// results in that code example becoming invalid. In this case, @@ -787,9 +1216,6 @@ enum CodeExampleAddAction<'src> { /// The lines of code that we collected but should be printed back to /// the docstring as-is and not formatted. code: Vec>, - /// The line that was added and triggered this reset to occur. It - /// should be written back to the docstring as-is after the code lines. - original: InputDocstringLine<'src>, }, } @@ -804,7 +1230,7 @@ enum CodeExampleAddAction<'src> { /// explicitly sets the context to indicate that formatting is taking place /// inside of a docstring. fn docstring_format_source( - options: &crate::PyFormatOptions, + options: crate::PyFormatOptions, docstring_quote_style: QuoteStyle, source: &str, ) -> Result { @@ -818,7 +1244,7 @@ fn docstring_format_source( let comments = crate::Comments::from_ast(&module, source_code, &comment_ranges); let locator = Locator::new(source); - let ctx = PyFormatContext::new(options.clone(), locator.contents(), comments) + let ctx = PyFormatContext::new(options, locator.contents(), comments) .in_docstring(docstring_quote_style); let formatted = crate::format!(ctx, [module.format()])?; formatted @@ -855,6 +1281,59 @@ fn indentation_length(line: &str) -> TextSize { TextSize::new(indentation) } +/// Trims at most `indent_len` indentation from the beginning of `line`. +/// +/// This treats indentation in precisely the same way as `indentation_length`. +/// As such, it is expected that `indent_len` is computed from +/// `indentation_length`. This is useful when one needs to trim some minimum +/// level of indentation from a code snippet collected from a docstring before +/// attempting to reformat it. +fn indentation_trim(indent_len: TextSize, line: &str) -> &str { + let mut seen_indent_len = 0u32; + let mut trimmed = line; + for char in line.chars() { + if seen_indent_len >= indent_len.to_u32() { + return trimmed; + } + if char == '\t' { + // Pad to the next multiple of tab_width + seen_indent_len += 8 - (seen_indent_len.rem_euclid(8)); + trimmed = &trimmed[1..]; + } else if char.is_whitespace() { + seen_indent_len += u32::from(char.text_len()); + trimmed = &trimmed[char.len_utf8()..]; + } else { + break; + } + } + line +} + +/// Returns the indentation of the given line and everything following it. +fn indent_with_suffix(line: &str) -> (&str, &str) { + let suffix = line.trim_whitespace_start(); + let indent_len = line + .len() + .checked_sub(suffix.len()) + .expect("suffix <= line"); + let indent = &line[..indent_len]; + (indent, suffix) +} + +/// Returns true if this line looks like a reStructuredText option in a +/// field list. +/// +/// That is, a line that looks like `:name: optional-value`. +fn is_rst_option(line: &str) -> bool { + let line = line.trim_start(); + if !line.starts_with(':') { + return false; + } + line.chars() + .take_while(|&ch| !is_python_whitespace(ch)) + .any(|ch| ch == ':') +} + #[cfg(test)] mod tests { use ruff_text_size::TextSize; diff --git a/crates/ruff_python_formatter/tests/normalizer.rs b/crates/ruff_python_formatter/tests/normalizer.rs index d0f2ba0b9c234..8f01694468dcb 100644 --- a/crates/ruff_python_formatter/tests/normalizer.rs +++ b/crates/ruff_python_formatter/tests/normalizer.rs @@ -60,7 +60,7 @@ impl Transformer for Normalizer { } fn visit_string_literal(&self, string_literal: &mut ast::StringLiteral) { - static STRIP_CODE_SNIPPETS: Lazy = Lazy::new(|| { + static STRIP_DOC_TESTS: Lazy = Lazy::new(|| { Regex::new( r#"(?mx) ( @@ -75,14 +75,27 @@ impl Transformer for Normalizer { ) .unwrap() }); + static STRIP_RST_BLOCKS: Lazy = Lazy::new(|| { + // This is kind of unfortunate, but it's pretty tricky (likely + // impossible) to detect a reStructuredText block with a simple + // regex. So we just look for the start of a block and remove + // everything after it. Talk about a hammer. + Regex::new(r#"::(?s:.*)"#).unwrap() + }); // Start by (1) stripping everything that looks like a code // snippet, since code snippets may be completely reformatted if // they are Python code. - string_literal.value = STRIP_CODE_SNIPPETS + string_literal.value = STRIP_DOC_TESTS + .replace_all( + &string_literal.value, + "\n", + ) + .into_owned(); + string_literal.value = STRIP_RST_BLOCKS .replace_all( &string_literal.value, - "\n", + "\n", ) .into_owned(); // Normalize a string by (2) stripping any leading and trailing space from each diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap index 5eeafa914fb93..cae50ad8c6d91 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap @@ -73,6 +73,27 @@ def doctest_last_line_continued(): pass +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x )""" + pass + + +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + ... more( y )""" + pass + + # Test that a doctest is correctly identified and formatted with a blank # continuation line. def doctest_blank_continued(): @@ -329,358 +350,498 @@ def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): >>> x = '\"\"\"' """ pass -``` -## Outputs -### Output 1 -``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled -``` -```python ############################################################################### -# DOCTEST CODE EXAMPLES +# reStructuredText CODE EXAMPLES # # This section shows examples of docstrings that contain code snippets in -# Python's "doctest" format. +# reStructuredText formatted code blocks. # -# See: https://docs.python.org/3/library/doctest.html +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 ############################################################################### -# The simplest doctest to ensure basic formatting works. -def doctest_simple(): + +def rst_literal_simple(): """ - Do cool stuff. + Do cool stuff:: - >>> cool_stuff( 1 ) - 2 + cool_stuff( 1 ) + + Done. """ pass -# Another simple test, but one where the Python code -# extends over multiple lines. -def doctest_simple_continued(): +def rst_literal_simple_continued(): """ - Do cool stuff. + Do cool stuff:: - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 + def cool_stuff( x ): + print( f"hi {x}" ); + + Done. """ pass -# Test that we support multiple directly adjacent -# doctests. -def doctest_adjacent(): +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): """ - Do cool stuff. + Do cool stuff:: - >>> cool_stuff( x ) - >>> cool_stuff( y ) - 2 + cool_stuff( 1 ) """ pass -# Test that a doctest on the last non-whitespace line of a docstring -# reformats correctly. -def doctest_last_line(): +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): """ - Do cool stuff. + Do cool stuff:: - >>> cool_stuff( x ) - """ + cool_stuff( 1 )""" pass -# Test that a doctest that continues to the last non-whitespace line of -# a docstring reformats correctly. -def doctest_last_line_continued(): +def rst_literal_with_blank_lines(): """ - Do cool stuff. + Do cool stuff:: - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); + def cool_stuff( x ): + print( f"hi {x}" ); + + def other_stuff( y ): + print( y ) + + Done. """ pass -# Test that a doctest is correctly identified and formatted with a blank -# continuation line. -def doctest_blank_continued(): +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): """ - Do cool stuff. + Do cool stuff:: - >>> def cool_stuff ( x ): - ... print( x ) - ... - ... print( x ) + + + cool_stuff( 1 ) + + + + Done. """ pass -# Tests that a blank PS2 line at the end of a doctest can get dropped. -# It is treated as part of the Python snippet which will trim the -# trailing whitespace. -def doctest_blank_end(): +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): """ - Do cool stuff. + Do cool stuff:: + + + cool_stuff( 1 ) + + - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... """ pass -# Tests that a blank PS2 line at the end of a doctest can get dropped -# even when there is text following it. -def doctest_blank_end_then_some_text(): +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): """ - Do cool stuff. + Do cool stuff:: - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... + cool_stuff( 1 ) - And say something else. + + cool_stuff( 2 ) + + Done. """ pass -# Test that a doctest containing a triple quoted string gets formatted -# correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): """ - Do cool stuff. + Do cool stuff:: - >>> x = '''tricksy''' + if True: + cool_stuff( ''' + hiya''' ) + + Done. """ pass -# Test that a doctest containing a triple quoted f-string gets -# formatted correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): """ - Do cool stuff. + Do cool stuff:: - >>> x = f'''tricksy''' + cool_stuff( 1 ) + + Done. """ pass -# Another nested multi-line string case, but with triple escaped double -# quotes inside a triple single quoted string. -def doctest_with_triple_escaped_double(): +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): """ - Do cool stuff. + Do cool stuff:: - >>> x = '''\"\"\"''' + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. """ pass -# Tests that inverting the triple quoting works as expected. -def doctest_with_triple_inverted(): - ''' - Do cool stuff. - - >>> x = """tricksy""" - ''' - pass +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + cool_stuff( 1 ) -# Tests that inverting the triple quoting with an f-string works as -# expected. -def doctest_with_triple_inverted_fstring(): - ''' - Do cool stuff. + Done. + """ + pass - >>> x = f"""tricksy""" - ''' - pass +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: -# Tests nested doctests are ignored. That is, we don't format doctests -# recursively. We only recognize "top level" doctests. -# -# This restriction primarily exists to avoid needing to deal with -# nesting quotes. It also seems like a generally sensible restriction, -# although it could be lifted if necessary I believe. -def doctest_nested_doctest_not_formatted(): - ''' - Do cool stuff. + cool_stuff( 1 ) + cool_stuff( 2 ) - >>> def nested( x ): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass - ''' - pass + Done. + """ + pass -# Tests that the starting column does not matter. -def doctest_varying_start_column(): +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): """ - Do cool stuff. + Do cool stuff:: - >>> assert ("Easy!") - >>> import math - >>> math.floor( 1.9 ) - 1 + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. """ pass -# Tests that long lines get wrapped... appropriately. +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. # -# The docstring code formatter uses the same line width settings as for -# formatting other code. This means that a line in the docstring can -# actually extend past the configured line limit. +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. # -# It's not quite clear whether this is desirable or not. We could in -# theory compute the intendation length of a code snippet and then -# adjust the line-width setting on a recursive call to the formatter. -# But there are assuredly pathological cases to consider. Another path -# would be to expose another formatter option for controlling the -# line-width of code snippets independently. -def doctest_long_lines(): +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): """ - Do cool stuff. + Do cool stuff:: - This won't get wrapped even though it exceeds our configured - line width because it doesn't exceed the line width within this - docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + cool_stuff( 1 ) + cool_stuff( 2 ) - But this one is long enough to get wrapped. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) + Done. """ - # This demostrates a normal line that will get wrapped but won't - # get wrapped in the docstring above because of how the line-width - # setting gets reset at the first column in each code snippet. - foo, bar, quux = this_is_a_long_line( - lion, giraffe, hippo, zeba, lemur, penguin, monkey - ) + pass -# Checks that a simple but invalid doctest gets skipped. -def doctest_skipped_simple(): +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): """ Do cool stuff. - >>> cool-stuff( x ): - 2 + :: + + cool_stuff( 1 ) + + Done. """ pass -# Checks that a simple doctest that is continued over multiple lines, -# but is invalid, gets skipped. -def doctest_skipped_simple_continued(): +def rst_directive_simple(): """ - Do cool stuff. + .. code-block:: python - >>> def cool-stuff( x ): - ... print( f"hi {x}" ); - 2 + cool_stuff( 1 ) + + Done. """ pass -# Checks that a doctest with improper indentation gets skipped. -def doctest_skipped_inconsistent_indent(): +def rst_directive_case_insensitive(): """ - Do cool stuff. + .. cOdE-bLoCk:: python - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 + cool_stuff( 1 ) + + Done. """ pass -# Checks that a doctest with some proper indentation and some improper -# indentation is "partially" formatted. That is, the part that appears -# before the inconsistent indentation is formatted. This requires that -# the part before it is valid Python. -def doctest_skipped_partial_inconsistent_indent(): +def rst_directive_sourcecode(): """ - Do cool stuff. + .. sourcecode:: python - >>> def cool_stuff( x ): - ... print( x ) - ... print( f"hi {x}" ); - hi 2 + cool_stuff( 1 ) + + Done. """ pass -# Checks that a doctest with improper triple single quoted string gets -# skipped. That is, the code snippet is itself invalid Python, so it is -# left as is. -def doctest_skipped_triple_incorrect(): +def rst_directive_options(): """ - Do cool stuff. + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah - >>> foo( x ) - ... '''tri'''cksy''' + cool_stuff( 1 ) + cool_stuff( 2 ) + cool_stuff( 3 ) + cool_stuff( 4 ) + + Done. """ pass -# Tests that a doctest on a single line is skipped. -def doctest_skipped_one_line(): - ">>> foo( x )" +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon + + >>> cool_stuff( 1 ) + + Done. + """ pass -# f-strings are not considered docstrings[1], so any doctests -# inside of them should not be formatted. -# -# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals -def doctest_skipped_fstring(): - f""" - Do cool stuff. +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: - >>> cool_stuff( 1 ) - 2 + cool_stuff( 1 ) + + Done. """ pass -# Test that a doctest containing a triple quoted string at least -# does not result in invalid Python code. Ideally this would format -# correctly, but at time of writing it does not. -def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): """ - Do cool stuff. + Do cool stuff:: - >>> x = '\"\"\"' + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. """ pass -``` -### Output 2 +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. +# +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python + + >>> cool_stuff( 1 ) + + Done. + """ + pass +``` + +## Outputs +### Output 1 ``` indent-style = space line-width = 88 -indent-width = 2 +indent-width = 4 quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect @@ -700,161 +861,182 @@ preview = Disabled # The simplest doctest to ensure basic formatting works. def doctest_simple(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff( 1 ) - 2 - """ - pass + >>> cool_stuff( 1 ) + 2 + """ + pass # Another simple test, but one where the Python code # extends over multiple lines. def doctest_simple_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass # Test that we support multiple directly adjacent # doctests. def doctest_adjacent(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff( x ) - >>> cool_stuff( y ) - 2 - """ - pass + >>> cool_stuff( x ) + >>> cool_stuff( y ) + 2 + """ + pass # Test that a doctest on the last non-whitespace line of a docstring # reformats correctly. def doctest_last_line(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff( x ) - """ - pass + >>> cool_stuff( x ) + """ + pass # Test that a doctest that continues to the last non-whitespace line of # a docstring reformats correctly. def doctest_last_line_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - """ - pass + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + """ + pass + + +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x )""" + pass + + +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + ... more( y )""" + pass # Test that a doctest is correctly identified and formatted with a blank # continuation line. def doctest_blank_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff ( x ): - ... print( x ) - ... - ... print( x ) - """ - pass + >>> def cool_stuff ( x ): + ... print( x ) + ... + ... print( x ) + """ + pass # Tests that a blank PS2 line at the end of a doctest can get dropped. # It is treated as part of the Python snippet which will trim the # trailing whitespace. def doctest_blank_end(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... - """ - pass + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + """ + pass # Tests that a blank PS2 line at the end of a doctest can get dropped # even when there is text following it. def doctest_blank_end_then_some_text(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... - And say something else. - """ - pass + And say something else. + """ + pass # Test that a doctest containing a triple quoted string gets formatted # correctly and doesn't result in invalid syntax. def doctest_with_triple_single(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = '''tricksy''' - """ - pass + >>> x = '''tricksy''' + """ + pass # Test that a doctest containing a triple quoted f-string gets # formatted correctly and doesn't result in invalid syntax. def doctest_with_triple_single(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = f'''tricksy''' - """ - pass + >>> x = f'''tricksy''' + """ + pass # Another nested multi-line string case, but with triple escaped double # quotes inside a triple single quoted string. def doctest_with_triple_escaped_double(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = '''\"\"\"''' - """ - pass + >>> x = '''\"\"\"''' + """ + pass # Tests that inverting the triple quoting works as expected. def doctest_with_triple_inverted(): - ''' - Do cool stuff. + ''' + Do cool stuff. - >>> x = """tricksy""" - ''' - pass + >>> x = """tricksy""" + ''' + pass # Tests that inverting the triple quoting with an f-string works as # expected. def doctest_with_triple_inverted_fstring(): - ''' - Do cool stuff. + ''' + Do cool stuff. - >>> x = f"""tricksy""" - ''' - pass + >>> x = f"""tricksy""" + ''' + pass # Tests nested doctests are ignored. That is, we don't format doctests @@ -864,30 +1046,30 @@ def doctest_with_triple_inverted_fstring(): # nesting quotes. It also seems like a generally sensible restriction, # although it could be lifted if necessary I believe. def doctest_nested_doctest_not_formatted(): - ''' - Do cool stuff. - - >>> def nested( x ): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass - ''' - pass - + ''' + Do cool stuff. -# Tests that the starting column does not matter. -def doctest_varying_start_column(): - """ - Do cool stuff. + >>> def nested( x ): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass - >>> assert ("Easy!") - >>> import math - >>> math.floor( 1.9 ) - 1 - """ - pass + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert ("Easy!") + >>> import math + >>> math.floor( 1.9 ) + 1 + """ + pass # Tests that long lines get wrapped... appropriately. @@ -903,59 +1085,59 @@ def doctest_varying_start_column(): # would be to expose another formatter option for controlling the # line-width of code snippets independently. def doctest_long_lines(): - """ - Do cool stuff. + """ + Do cool stuff. - This won't get wrapped even though it exceeds our configured - line width because it doesn't exceed the line width within this - docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) - But this one is long enough to get wrapped. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) - """ - # This demostrates a normal line that will get wrapped but won't - # get wrapped in the docstring above because of how the line-width - # setting gets reset at the first column in each code snippet. - foo, bar, quux = this_is_a_long_line( - lion, giraffe, hippo, zeba, lemur, penguin, monkey - ) + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) # Checks that a simple but invalid doctest gets skipped. def doctest_skipped_simple(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool-stuff( x ): - 2 - """ - pass + >>> cool-stuff( x ): + 2 + """ + pass # Checks that a simple doctest that is continued over multiple lines, # but is invalid, gets skipped. def doctest_skipped_simple_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool-stuff( x ): - ... print( f"hi {x}" ); - 2 - """ - pass + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass # Checks that a doctest with improper indentation gets skipped. def doctest_skipped_inconsistent_indent(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass # Checks that a doctest with some proper indentation and some improper @@ -963,34 +1145,34 @@ def doctest_skipped_inconsistent_indent(): # before the inconsistent indentation is formatted. This requires that # the part before it is valid Python. def doctest_skipped_partial_inconsistent_indent(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( x ) - ... print( f"hi {x}" ); - hi 2 - """ - pass + >>> def cool_stuff( x ): + ... print( x ) + ... print( f"hi {x}" ); + hi 2 + """ + pass # Checks that a doctest with improper triple single quoted string gets # skipped. That is, the code snippet is itself invalid Python, so it is # left as is. def doctest_skipped_triple_incorrect(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> foo( x ) - ... '''tri'''cksy''' - """ - pass + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass # Tests that a doctest on a single line is skipped. def doctest_skipped_one_line(): - ">>> foo( x )" - pass + ">>> foo( x )" + pass # f-strings are not considered docstrings[1], so any doctests @@ -998,381 +1180,3920 @@ def doctest_skipped_one_line(): # # [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals def doctest_skipped_fstring(): - f""" + f""" Do cool stuff. >>> cool_stuff( 1 ) 2 """ - pass + pass # Test that a doctest containing a triple quoted string at least # does not result in invalid Python code. Ideally this would format # correctly, but at time of writing it does not. def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): - """ - Do cool stuff. - - >>> x = '\"\"\"' - """ - pass -``` + """ + Do cool stuff. + >>> x = '\"\"\"' + """ + pass -### Output 3 -``` -indent-style = tab -line-width = 88 -indent-width = 8 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled -``` -```python ############################################################################### -# DOCTEST CODE EXAMPLES +# reStructuredText CODE EXAMPLES # # This section shows examples of docstrings that contain code snippets in -# Python's "doctest" format. +# reStructuredText formatted code blocks. # -# See: https://docs.python.org/3/library/doctest.html +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 ############################################################################### -# The simplest doctest to ensure basic formatting works. -def doctest_simple(): - """ - Do cool stuff. - >>> cool_stuff( 1 ) - 2 - """ - pass +def rst_literal_simple(): + """ + Do cool stuff:: + cool_stuff( 1 ) -# Another simple test, but one where the Python code -# extends over multiple lines. -def doctest_simple_continued(): - """ - Do cool stuff. + Done. + """ + pass - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass +def rst_literal_simple_continued(): + """ + Do cool stuff:: -# Test that we support multiple directly adjacent -# doctests. -def doctest_adjacent(): - """ - Do cool stuff. + def cool_stuff( x ): + print( f"hi {x}" ); - >>> cool_stuff( x ) - >>> cool_stuff( y ) - 2 - """ - pass + Done. + """ + pass -# Test that a doctest on the last non-whitespace line of a docstring -# reformats correctly. -def doctest_last_line(): - """ - Do cool stuff. +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: - >>> cool_stuff( x ) - """ - pass + cool_stuff( 1 ) + """ + pass -# Test that a doctest that continues to the last non-whitespace line of -# a docstring reformats correctly. -def doctest_last_line_continued(): - """ - Do cool stuff. +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - """ - pass + cool_stuff( 1 )""" + pass -# Test that a doctest is correctly identified and formatted with a blank -# continuation line. -def doctest_blank_continued(): - """ - Do cool stuff. +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: - >>> def cool_stuff ( x ): - ... print( x ) - ... - ... print( x ) - """ - pass + def cool_stuff( x ): + print( f"hi {x}" ); + def other_stuff( y ): + print( y ) -# Tests that a blank PS2 line at the end of a doctest can get dropped. -# It is treated as part of the Python snippet which will trim the -# trailing whitespace. -def doctest_blank_end(): - """ - Do cool stuff. + Done. + """ + pass - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... - """ - pass +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: -# Tests that a blank PS2 line at the end of a doctest can get dropped -# even when there is text following it. -def doctest_blank_end_then_some_text(): - """ - Do cool stuff. - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... - And say something else. - """ - pass + cool_stuff( 1 ) -# Test that a doctest containing a triple quoted string gets formatted + + Done. + """ + pass + + +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: + + + cool_stuff( 1 ) + + + + """ + pass + + +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + + cool_stuff( 2 ) + + Done. + """ + pass + + +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. +# +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ + Do cool stuff. + + :: + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_simple(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_case_insensitive(): + """ + .. cOdE-bLoCk:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_sourcecode(): + """ + .. sourcecode:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + + cool_stuff( 1 ) + cool_stuff( 2 ) + cool_stuff( 3 ) + cool_stuff( 4 ) + + Done. + """ + pass + + +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. +# +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python + + >>> cool_stuff( 1 ) + + Done. + """ + pass +``` + + +### Output 2 +``` +indent-style = space +line-width = 88 +indent-width = 2 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +preview = Disabled +``` + +```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + >>> cool_stuff( y ) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + """ + pass + + +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x )""" + pass + + +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + ... more( y )""" + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... + ... print( x ) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested( x ): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert ("Easy!") + >>> import math + >>> math.floor( 1.9 ) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( x ) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass + + +############################################################################### +# reStructuredText CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# reStructuredText formatted code blocks. +# +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +############################################################################### + + +def rst_literal_simple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_literal_simple_continued(): + """ + Do cool stuff:: + + def cool_stuff( x ): + print( f"hi {x}" ); + + Done. + """ + pass + + +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + """ + pass + + +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: + + cool_stuff( 1 )""" + pass + + +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: + + def cool_stuff( x ): + print( f"hi {x}" ); + + def other_stuff( y ): + print( y ) + + Done. + """ + pass + + +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: + + + + cool_stuff( 1 ) + + + + Done. + """ + pass + + +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: + + + cool_stuff( 1 ) + + + + """ + pass + + +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + + cool_stuff( 2 ) + + Done. + """ + pass + + +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. +# +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ + Do cool stuff. + + :: + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_simple(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_case_insensitive(): + """ + .. cOdE-bLoCk:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_sourcecode(): + """ + .. sourcecode:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + + cool_stuff( 1 ) + cool_stuff( 2 ) + cool_stuff( 3 ) + cool_stuff( 4 ) + + Done. + """ + pass + + +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. +# +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python + + >>> cool_stuff( 1 ) + + Done. + """ + pass +``` + + +### Output 3 +``` +indent-style = tab +line-width = 88 +indent-width = 8 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +preview = Disabled +``` + +```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + >>> cool_stuff( y ) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + """ + pass + + +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x )""" + pass + + +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + ... more( y )""" + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... + ... print( x ) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested( x ): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert ("Easy!") + >>> import math + >>> math.floor( 1.9 ) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( x ) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass + + +############################################################################### +# reStructuredText CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# reStructuredText formatted code blocks. +# +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +############################################################################### + + +def rst_literal_simple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_literal_simple_continued(): + """ + Do cool stuff:: + + def cool_stuff( x ): + print( f"hi {x}" ); + + Done. + """ + pass + + +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + """ + pass + + +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: + + cool_stuff( 1 )""" + pass + + +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: + + def cool_stuff( x ): + print( f"hi {x}" ); + + def other_stuff( y ): + print( y ) + + Done. + """ + pass + + +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: + + + + cool_stuff( 1 ) + + + + Done. + """ + pass + + +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: + + + cool_stuff( 1 ) + + + + """ + pass + + +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + + cool_stuff( 2 ) + + Done. + """ + pass + + +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. +# +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ + Do cool stuff. + + :: + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_simple(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_case_insensitive(): + """ + .. cOdE-bLoCk:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_sourcecode(): + """ + .. sourcecode:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + + cool_stuff( 1 ) + cool_stuff( 2 ) + cool_stuff( 3 ) + cool_stuff( 4 ) + + Done. + """ + pass + + +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. +# +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python + + >>> cool_stuff( 1 ) + + Done. + """ + pass +``` + + +### Output 4 +``` +indent-style = tab +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +preview = Disabled +``` + +```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + >>> cool_stuff( y ) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + """ + pass + + +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x )""" + pass + + +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + ... more( y )""" + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... + ... print( x ) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested( x ): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert ("Easy!") + >>> import math + >>> math.floor( 1.9 ) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( x ) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass + + +############################################################################### +# reStructuredText CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# reStructuredText formatted code blocks. +# +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +############################################################################### + + +def rst_literal_simple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_literal_simple_continued(): + """ + Do cool stuff:: + + def cool_stuff( x ): + print( f"hi {x}" ); + + Done. + """ + pass + + +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + """ + pass + + +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: + + cool_stuff( 1 )""" + pass + + +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: + + def cool_stuff( x ): + print( f"hi {x}" ); + + def other_stuff( y ): + print( y ) + + Done. + """ + pass + + +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: + + + + cool_stuff( 1 ) + + + + Done. + """ + pass + + +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: + + + cool_stuff( 1 ) + + + + """ + pass + + +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + + cool_stuff( 2 ) + + Done. + """ + pass + + +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. +# +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ + Do cool stuff. + + :: + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_simple(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_case_insensitive(): + """ + .. cOdE-bLoCk:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_sourcecode(): + """ + .. sourcecode:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + + cool_stuff( 1 ) + cool_stuff( 2 ) + cool_stuff( 3 ) + cool_stuff( 4 ) + + Done. + """ + pass + + +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. +# +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python + + >>> cool_stuff( 1 ) + + Done. + """ + pass +``` + + +### Output 5 +``` +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +preview = Disabled +``` + +```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff(1) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(f"hi {x}") + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff(x) + >>> cool_stuff(y) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff(x) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(f"hi {x}") + """ + pass + + +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. + + >>> cool_stuff(x)""" + pass + + +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. + + >>> cool_stuff(x) + ... more(y)""" + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... + ... print(x) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print(x) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print(x) + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted # correctly and doesn't result in invalid syntax. def doctest_with_triple_single(): - """ - Do cool stuff. + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested(x): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard + ... ) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass + + +############################################################################### +# reStructuredText CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# reStructuredText formatted code blocks. +# +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +############################################################################### + + +def rst_literal_simple(): + """ + Do cool stuff:: + + cool_stuff(1) + + Done. + """ + pass - >>> x = '''tricksy''' - """ - pass +def rst_literal_simple_continued(): + """ + Do cool stuff:: -# Test that a doctest containing a triple quoted f-string gets -# formatted correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): - """ - Do cool stuff. + def cool_stuff(x): + print(f"hi {x}") - >>> x = f'''tricksy''' - """ - pass + Done. + """ + pass -# Another nested multi-line string case, but with triple escaped double -# quotes inside a triple single quoted string. -def doctest_with_triple_escaped_double(): - """ - Do cool stuff. +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: - >>> x = '''\"\"\"''' - """ - pass + cool_stuff(1) + """ + pass -# Tests that inverting the triple quoting works as expected. -def doctest_with_triple_inverted(): - ''' - Do cool stuff. +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: - >>> x = """tricksy""" - ''' - pass + cool_stuff(1)""" + pass -# Tests that inverting the triple quoting with an f-string works as -# expected. -def doctest_with_triple_inverted_fstring(): - ''' - Do cool stuff. +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: - >>> x = f"""tricksy""" - ''' - pass + def cool_stuff(x): + print(f"hi {x}") -# Tests nested doctests are ignored. That is, we don't format doctests -# recursively. We only recognize "top level" doctests. + def other_stuff(y): + print(y) + + Done. + """ + pass + + +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: + + + + cool_stuff(1) + + + + Done. + """ + pass + + +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: + + + cool_stuff(1) + + + + """ + pass + + +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: + + cool_stuff(1) + + + cool_stuff(2) + + Done. + """ + pass + + +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( + ''' + hiya''' + ) + + Done. + """ + pass + + +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. # -# This restriction primarily exists to avoid needing to deal with -# nesting quotes. It also seems like a generally sensible restriction, -# although it could be lifted if necessary I believe. -def doctest_nested_doctest_not_formatted(): - ''' - Do cool stuff. +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff:: - >>> def nested( x ): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass - ''' - pass + cool_stuff(1) + Done. + """ + pass -# Tests that the starting column does not matter. -def doctest_varying_start_column(): - """ - Do cool stuff. - >>> assert ("Easy!") - >>> import math - >>> math.floor( 1.9 ) - 1 - """ - pass +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff:: + cool_stuff(1) + cool_stuff(2) -# Tests that long lines get wrapped... appropriately. + Done. + """ + pass + + +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + + cool_stuff(1) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff(1) + cool_stuff(2) + + Done. + """ + pass + + +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): + """ + Do cool stuff:: + + cool_stuff(1) + cool_stuff(2) + + Done. + """ + pass + + +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. # -# The docstring code formatter uses the same line width settings as for -# formatting other code. This means that a line in the docstring can -# actually extend past the configured line limit. +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. # -# It's not quite clear whether this is desirable or not. We could in -# theory compute the intendation length of a code snippet and then -# adjust the line-width setting on a recursive call to the formatter. -# But there are assuredly pathological cases to consider. Another path -# would be to expose another formatter option for controlling the -# line-width of code snippets independently. -def doctest_long_lines(): - """ - Do cool stuff. +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: - This won't get wrapped even though it exceeds our configured - line width because it doesn't exceed the line width within this - docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + cool_stuff(1) + cool_stuff(2) - But this one is long enough to get wrapped. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) - """ - # This demostrates a normal line that will get wrapped but won't - # get wrapped in the docstring above because of how the line-width - # setting gets reset at the first column in each code snippet. - foo, bar, quux = this_is_a_long_line( - lion, giraffe, hippo, zeba, lemur, penguin, monkey - ) + Done. + """ + pass -# Checks that a simple but invalid doctest gets skipped. -def doctest_skipped_simple(): - """ - Do cool stuff. +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ + Do cool stuff. + + :: + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_simple(): + """ + .. code-block:: python + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_case_insensitive(): + """ + .. cOdE-bLoCk:: python + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_sourcecode(): + """ + .. sourcecode:: python + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + + cool_stuff(1) + cool_stuff(2) + cool_stuff(3) + cool_stuff(4) + + Done. + """ + pass + + +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon + + >>> cool_stuff(1) + + Done. + """ + pass + + +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. +# +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: - >>> cool-stuff( x ): - 2 - """ - pass + cool_stuff( 1 ) + Done. + """ + pass -# Checks that a simple doctest that is continued over multiple lines, -# but is invalid, gets skipped. -def doctest_skipped_simple_continued(): - """ - Do cool stuff. - >>> def cool-stuff( x ): - ... print( f"hi {x}" ); - 2 - """ - pass +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: + cool_stuff( 1 ) -# Checks that a doctest with improper indentation gets skipped. -def doctest_skipped_inconsistent_indent(): - """ - Do cool stuff. + Done. + """ + pass - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: -# Checks that a doctest with some proper indentation and some improper -# indentation is "partially" formatted. That is, the part that appears -# before the inconsistent indentation is formatted. This requires that -# the part before it is valid Python. -def doctest_skipped_partial_inconsistent_indent(): - """ - Do cool stuff. + >>> cool_stuff( 1 ) - >>> def cool_stuff( x ): - ... print( x ) - ... print( f"hi {x}" ); - hi 2 - """ - pass + Done. + """ + pass -# Checks that a doctest with improper triple single quoted string gets -# skipped. That is, the code snippet is itself invalid Python, so it is -# left as is. -def doctest_skipped_triple_incorrect(): - """ - Do cool stuff. +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python - >>> foo( x ) - ... '''tri'''cksy''' - """ - pass + cool_stuff( 1 ) + Done. + """ + pass -# Tests that a doctest on a single line is skipped. -def doctest_skipped_one_line(): - ">>> foo( x )" - pass +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust -# f-strings are not considered docstrings[1], so any doctests -# inside of them should not be formatted. -# -# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals -def doctest_skipped_fstring(): - f""" - Do cool stuff. + cool_stuff( 1 ) - >>> cool_stuff( 1 ) - 2 + Done. """ - pass + pass -# Test that a doctest containing a triple quoted string at least -# does not result in invalid Python code. Ideally this would format -# correctly, but at time of writing it does not. -def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): - """ - Do cool stuff. +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python - >>> x = '\"\"\"' - """ - pass + >>> cool_stuff( 1 ) + + Done. + """ + pass ``` -### Output 4 +### Output 6 ``` -indent-style = tab +indent-style = space line-width = 88 -indent-width = 4 +indent-width = 2 quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect -docstring-code = Disabled +docstring-code = Enabled preview = Disabled ``` @@ -1388,161 +5109,180 @@ preview = Disabled # The simplest doctest to ensure basic formatting works. def doctest_simple(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff( 1 ) - 2 - """ - pass + >>> cool_stuff(1) + 2 + """ + pass # Another simple test, but one where the Python code # extends over multiple lines. def doctest_simple_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass + >>> def cool_stuff(x): + ... print(f"hi {x}") + hi 2 + """ + pass # Test that we support multiple directly adjacent # doctests. def doctest_adjacent(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff( x ) - >>> cool_stuff( y ) - 2 - """ - pass + >>> cool_stuff(x) + >>> cool_stuff(y) + 2 + """ + pass # Test that a doctest on the last non-whitespace line of a docstring # reformats correctly. def doctest_last_line(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff( x ) - """ - pass + >>> cool_stuff(x) + """ + pass # Test that a doctest that continues to the last non-whitespace line of # a docstring reformats correctly. def doctest_last_line_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - """ - pass + >>> def cool_stuff(x): + ... print(f"hi {x}") + """ + pass + + +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. + + >>> cool_stuff(x)""" + pass + + +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. + + >>> cool_stuff(x) + ... more(y)""" + pass # Test that a doctest is correctly identified and formatted with a blank # continuation line. def doctest_blank_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff ( x ): - ... print( x ) - ... - ... print( x ) - """ - pass + >>> def cool_stuff(x): + ... print(x) + ... + ... print(x) + """ + pass # Tests that a blank PS2 line at the end of a doctest can get dropped. # It is treated as part of the Python snippet which will trim the # trailing whitespace. def doctest_blank_end(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... - """ - pass + >>> def cool_stuff(x): + ... print(x) + ... print(x) + """ + pass # Tests that a blank PS2 line at the end of a doctest can get dropped # even when there is text following it. def doctest_blank_end_then_some_text(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... + >>> def cool_stuff(x): + ... print(x) + ... print(x) - And say something else. - """ - pass + And say something else. + """ + pass # Test that a doctest containing a triple quoted string gets formatted # correctly and doesn't result in invalid syntax. def doctest_with_triple_single(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = '''tricksy''' - """ - pass + >>> x = '''tricksy''' + """ + pass # Test that a doctest containing a triple quoted f-string gets # formatted correctly and doesn't result in invalid syntax. def doctest_with_triple_single(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = f'''tricksy''' - """ - pass + >>> x = f'''tricksy''' + """ + pass # Another nested multi-line string case, but with triple escaped double # quotes inside a triple single quoted string. def doctest_with_triple_escaped_double(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = '''\"\"\"''' - """ - pass + >>> x = '''\"\"\"''' + """ + pass # Tests that inverting the triple quoting works as expected. def doctest_with_triple_inverted(): - ''' - Do cool stuff. + ''' + Do cool stuff. - >>> x = """tricksy""" - ''' - pass + >>> x = """tricksy""" + ''' + pass # Tests that inverting the triple quoting with an f-string works as # expected. def doctest_with_triple_inverted_fstring(): - ''' - Do cool stuff. + ''' + Do cool stuff. - >>> x = f"""tricksy""" - ''' - pass + >>> x = f"""tricksy""" + ''' + pass # Tests nested doctests are ignored. That is, we don't format doctests @@ -1552,30 +5292,30 @@ def doctest_with_triple_inverted_fstring(): # nesting quotes. It also seems like a generally sensible restriction, # although it could be lifted if necessary I believe. def doctest_nested_doctest_not_formatted(): - ''' - Do cool stuff. + ''' + Do cool stuff. - >>> def nested( x ): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass - ''' - pass + >>> def nested(x): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass # Tests that the starting column does not matter. def doctest_varying_start_column(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> assert ("Easy!") - >>> import math - >>> math.floor( 1.9 ) - 1 - """ - pass + >>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1 + """ + pass # Tests that long lines get wrapped... appropriately. @@ -1591,59 +5331,61 @@ def doctest_varying_start_column(): # would be to expose another formatter option for controlling the # line-width of code snippets independently. def doctest_long_lines(): - """ - Do cool stuff. + """ + Do cool stuff. - This won't get wrapped even though it exceeds our configured - line width because it doesn't exceed the line width within this - docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) - But this one is long enough to get wrapped. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) - """ - # This demostrates a normal line that will get wrapped but won't - # get wrapped in the docstring above because of how the line-width - # setting gets reset at the first column in each code snippet. - foo, bar, quux = this_is_a_long_line( - lion, giraffe, hippo, zeba, lemur, penguin, monkey - ) + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard + ... ) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) # Checks that a simple but invalid doctest gets skipped. def doctest_skipped_simple(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool-stuff( x ): - 2 - """ - pass + >>> cool-stuff( x ): + 2 + """ + pass # Checks that a simple doctest that is continued over multiple lines, # but is invalid, gets skipped. def doctest_skipped_simple_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool-stuff( x ): - ... print( f"hi {x}" ); - 2 - """ - pass + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass # Checks that a doctest with improper indentation gets skipped. def doctest_skipped_inconsistent_indent(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass # Checks that a doctest with some proper indentation and some improper @@ -1651,412 +5393,555 @@ def doctest_skipped_inconsistent_indent(): # before the inconsistent indentation is formatted. This requires that # the part before it is valid Python. def doctest_skipped_partial_inconsistent_indent(): - """ - Do cool stuff. + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass + + +############################################################################### +# reStructuredText CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# reStructuredText formatted code blocks. +# +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +############################################################################### + + +def rst_literal_simple(): + """ + Do cool stuff:: + + cool_stuff(1) + + Done. + """ + pass + + +def rst_literal_simple_continued(): + """ + Do cool stuff:: + + def cool_stuff(x): + print(f"hi {x}") + + Done. + """ + pass + + +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: + + cool_stuff(1) + """ + pass + + +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: + + cool_stuff(1)""" + pass + + +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: + + def cool_stuff(x): + print(f"hi {x}") + + + def other_stuff(y): + print(y) + + Done. + """ + pass + + +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: + + + + cool_stuff(1) + + + + Done. + """ + pass + + +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: + + + cool_stuff(1) + + + + """ + pass + + +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: + + cool_stuff(1) + + + cool_stuff(2) + + Done. + """ + pass + + +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( + ''' + hiya''' + ) + + Done. + """ + pass + - >>> def cool_stuff( x ): - ... print( x ) - ... print( f"hi {x}" ); - hi 2 - """ - pass +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff:: + cool_stuff(1) -# Checks that a doctest with improper triple single quoted string gets -# skipped. That is, the code snippet is itself invalid Python, so it is -# left as is. -def doctest_skipped_triple_incorrect(): - """ - Do cool stuff. + Done. + """ + pass - >>> foo( x ) - ... '''tri'''cksy''' - """ - pass +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff:: -# Tests that a doctest on a single line is skipped. -def doctest_skipped_one_line(): - ">>> foo( x )" - pass + cool_stuff(1) + cool_stuff(2) + Done. + """ + pass -# f-strings are not considered docstrings[1], so any doctests -# inside of them should not be formatted. -# -# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals -def doctest_skipped_fstring(): - f""" - Do cool stuff. - >>> cool_stuff( 1 ) - 2 - """ - pass +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + cool_stuff(1) -# Test that a doctest containing a triple quoted string at least -# does not result in invalid Python code. Ideally this would format -# correctly, but at time of writing it does not. -def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): - """ - Do cool stuff. + Done. + """ + pass - >>> x = '\"\"\"' - """ - pass -``` +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: -### Output 5 -``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Enabled -preview = Disabled -``` + cool_stuff(1) + cool_stuff(2) -```python -############################################################################### -# DOCTEST CODE EXAMPLES -# -# This section shows examples of docstrings that contain code snippets in -# Python's "doctest" format. -# -# See: https://docs.python.org/3/library/doctest.html -############################################################################### + Done. + """ + pass -# The simplest doctest to ensure basic formatting works. -def doctest_simple(): - """ - Do cool stuff. - >>> cool_stuff(1) - 2 - """ - pass +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): + """ + Do cool stuff:: + cool_stuff(1) + cool_stuff(2) -# Another simple test, but one where the Python code -# extends over multiple lines. -def doctest_simple_continued(): - """ - Do cool stuff. + Done. + """ + pass - >>> def cool_stuff(x): - ... print(f"hi {x}") - hi 2 - """ - pass +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. +# +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: -# Test that we support multiple directly adjacent -# doctests. -def doctest_adjacent(): - """ - Do cool stuff. + cool_stuff(1) + cool_stuff(2) - >>> cool_stuff(x) - >>> cool_stuff(y) - 2 - """ - pass + Done. + """ + pass -# Test that a doctest on the last non-whitespace line of a docstring -# reformats correctly. -def doctest_last_line(): - """ - Do cool stuff. +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ + Do cool stuff. - >>> cool_stuff(x) - """ - pass + :: + cool_stuff(1) -# Test that a doctest that continues to the last non-whitespace line of -# a docstring reformats correctly. -def doctest_last_line_continued(): - """ - Do cool stuff. + Done. + """ + pass - >>> def cool_stuff(x): - ... print(f"hi {x}") - """ - pass +def rst_directive_simple(): + """ + .. code-block:: python -# Test that a doctest is correctly identified and formatted with a blank -# continuation line. -def doctest_blank_continued(): - """ - Do cool stuff. + cool_stuff(1) - >>> def cool_stuff(x): - ... print(x) - ... - ... print(x) - """ - pass + Done. + """ + pass -# Tests that a blank PS2 line at the end of a doctest can get dropped. -# It is treated as part of the Python snippet which will trim the -# trailing whitespace. -def doctest_blank_end(): - """ - Do cool stuff. +def rst_directive_case_insensitive(): + """ + .. cOdE-bLoCk:: python - >>> def cool_stuff(x): - ... print(x) - ... print(x) - """ - pass + cool_stuff(1) + Done. + """ + pass -# Tests that a blank PS2 line at the end of a doctest can get dropped -# even when there is text following it. -def doctest_blank_end_then_some_text(): - """ - Do cool stuff. - >>> def cool_stuff(x): - ... print(x) - ... print(x) +def rst_directive_sourcecode(): + """ + .. sourcecode:: python - And say something else. - """ - pass + cool_stuff(1) + Done. + """ + pass -# Test that a doctest containing a triple quoted string gets formatted -# correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): - """ - Do cool stuff. - >>> x = '''tricksy''' - """ - pass +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + cool_stuff(1) + cool_stuff(2) + cool_stuff(3) + cool_stuff(4) -# Test that a doctest containing a triple quoted f-string gets -# formatted correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): - """ - Do cool stuff. + Done. + """ + pass - >>> x = f'''tricksy''' - """ - pass +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon -# Another nested multi-line string case, but with triple escaped double -# quotes inside a triple single quoted string. -def doctest_with_triple_escaped_double(): - """ - Do cool stuff. + >>> cool_stuff(1) - >>> x = '''\"\"\"''' - """ - pass + Done. + """ + pass -# Tests that inverting the triple quoting works as expected. -def doctest_with_triple_inverted(): - ''' - Do cool stuff. +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: - >>> x = """tricksy""" - ''' - pass + cool_stuff( 1 ) + Done. + """ + pass -# Tests that inverting the triple quoting with an f-string works as -# expected. -def doctest_with_triple_inverted_fstring(): - ''' - Do cool stuff. - >>> x = f"""tricksy""" - ''' - pass +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): + """ + Do cool stuff:: + cool_stuff( 1 ) + cool_stuff( 2 ) -# Tests nested doctests are ignored. That is, we don't format doctests -# recursively. We only recognize "top level" doctests. -# -# This restriction primarily exists to avoid needing to deal with -# nesting quotes. It also seems like a generally sensible restriction, -# although it could be lifted if necessary I believe. -def doctest_nested_doctest_not_formatted(): - ''' - Do cool stuff. + Done. + """ + pass - >>> def nested(x): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass - ''' - pass +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: -# Tests that the starting column does not matter. -def doctest_varying_start_column(): - """ - Do cool stuff. + cool_stuff( 1 ) + + Done. + """ + pass - >>> assert "Easy!" - >>> import math - >>> math.floor(1.9) - 1 - """ - pass +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: -# Tests that long lines get wrapped... appropriately. -# -# The docstring code formatter uses the same line width settings as for -# formatting other code. This means that a line in the docstring can -# actually extend past the configured line limit. + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. # -# It's not quite clear whether this is desirable or not. We could in -# theory compute the intendation length of a code snippet and then -# adjust the line-width setting on a recursive call to the formatter. -# But there are assuredly pathological cases to consider. Another path -# would be to expose another formatter option for controlling the -# line-width of code snippets independently. -def doctest_long_lines(): - """ - Do cool stuff. +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: - This won't get wrapped even though it exceeds our configured - line width because it doesn't exceed the line width within this - docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + if True: + cool_stuff( ''' + hiya''' ) - But this one is long enough to get wrapped. - >>> foo, bar, quux = this_is_a_long_line( - ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard - ... ) - """ - # This demostrates a normal line that will get wrapped but won't - # get wrapped in the docstring above because of how the line-width - # setting gets reset at the first column in each code snippet. - foo, bar, quux = this_is_a_long_line( - lion, giraffe, hippo, zeba, lemur, penguin, monkey - ) + Done. + """ + pass -# Checks that a simple but invalid doctest gets skipped. -def doctest_skipped_simple(): - """ - Do cool stuff. +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: - >>> cool-stuff( x ): - 2 - """ - pass + cool_stuff( 1 ) + Done. + """ + pass -# Checks that a simple doctest that is continued over multiple lines, -# but is invalid, gets skipped. -def doctest_skipped_simple_continued(): - """ - Do cool stuff. - >>> def cool-stuff( x ): - ... print( f"hi {x}" ); - 2 - """ - pass +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: + cool_stuff( 1 ) -# Checks that a doctest with improper indentation gets skipped. -def doctest_skipped_inconsistent_indent(): - """ - Do cool stuff. + Done. + """ + pass - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: -# Checks that a doctest with some proper indentation and some improper -# indentation is "partially" formatted. That is, the part that appears -# before the inconsistent indentation is formatted. This requires that -# the part before it is valid Python. -def doctest_skipped_partial_inconsistent_indent(): - """ - Do cool stuff. + >>> cool_stuff( 1 ) - >>> def cool_stuff(x): - ... print(x) - ... print( f"hi {x}" ); - hi 2 - """ - pass + Done. + """ + pass -# Checks that a doctest with improper triple single quoted string gets -# skipped. That is, the code snippet is itself invalid Python, so it is -# left as is. -def doctest_skipped_triple_incorrect(): - """ - Do cool stuff. +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python - >>> foo( x ) - ... '''tri'''cksy''' - """ - pass + cool_stuff( 1 ) + Done. + """ + pass -# Tests that a doctest on a single line is skipped. -def doctest_skipped_one_line(): - ">>> foo( x )" - pass +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust -# f-strings are not considered docstrings[1], so any doctests -# inside of them should not be formatted. -# -# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals -def doctest_skipped_fstring(): - f""" - Do cool stuff. + cool_stuff( 1 ) - >>> cool_stuff( 1 ) - 2 - """ - pass + Done. + """ + pass -# Test that a doctest containing a triple quoted string at least -# does not result in invalid Python code. Ideally this would format -# correctly, but at time of writing it does not. -def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): - """ - Do cool stuff. +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python - >>> x = '\"\"\"' - """ - pass + >>> cool_stuff( 1 ) + + Done. + """ + pass ``` -### Output 6 +### Output 7 ``` -indent-style = space +indent-style = tab line-width = 88 -indent-width = 2 +indent-width = 8 quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect @@ -2076,159 +5961,180 @@ preview = Disabled # The simplest doctest to ensure basic formatting works. def doctest_simple(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff(1) - 2 - """ - pass + >>> cool_stuff(1) + 2 + """ + pass # Another simple test, but one where the Python code # extends over multiple lines. def doctest_simple_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff(x): - ... print(f"hi {x}") - hi 2 - """ - pass + >>> def cool_stuff(x): + ... print(f"hi {x}") + hi 2 + """ + pass # Test that we support multiple directly adjacent # doctests. def doctest_adjacent(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff(x) - >>> cool_stuff(y) - 2 - """ - pass + >>> cool_stuff(x) + >>> cool_stuff(y) + 2 + """ + pass # Test that a doctest on the last non-whitespace line of a docstring # reformats correctly. def doctest_last_line(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff(x) - """ - pass + >>> cool_stuff(x) + """ + pass # Test that a doctest that continues to the last non-whitespace line of # a docstring reformats correctly. def doctest_last_line_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff(x): - ... print(f"hi {x}") - """ - pass + >>> def cool_stuff(x): + ... print(f"hi {x}") + """ + pass + + +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. + + >>> cool_stuff(x)""" + pass + + +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. + + >>> cool_stuff(x) + ... more(y)""" + pass # Test that a doctest is correctly identified and formatted with a blank # continuation line. def doctest_blank_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff(x): - ... print(x) - ... - ... print(x) - """ - pass + >>> def cool_stuff(x): + ... print(x) + ... + ... print(x) + """ + pass # Tests that a blank PS2 line at the end of a doctest can get dropped. # It is treated as part of the Python snippet which will trim the # trailing whitespace. def doctest_blank_end(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff(x): - ... print(x) - ... print(x) - """ - pass + >>> def cool_stuff(x): + ... print(x) + ... print(x) + """ + pass # Tests that a blank PS2 line at the end of a doctest can get dropped # even when there is text following it. def doctest_blank_end_then_some_text(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff(x): - ... print(x) - ... print(x) + >>> def cool_stuff(x): + ... print(x) + ... print(x) - And say something else. - """ - pass + And say something else. + """ + pass # Test that a doctest containing a triple quoted string gets formatted # correctly and doesn't result in invalid syntax. def doctest_with_triple_single(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = '''tricksy''' - """ - pass + >>> x = '''tricksy''' + """ + pass # Test that a doctest containing a triple quoted f-string gets # formatted correctly and doesn't result in invalid syntax. def doctest_with_triple_single(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = f'''tricksy''' - """ - pass + >>> x = f'''tricksy''' + """ + pass # Another nested multi-line string case, but with triple escaped double # quotes inside a triple single quoted string. def doctest_with_triple_escaped_double(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = '''\"\"\"''' - """ - pass + >>> x = '''\"\"\"''' + """ + pass # Tests that inverting the triple quoting works as expected. def doctest_with_triple_inverted(): - ''' - Do cool stuff. + ''' + Do cool stuff. - >>> x = """tricksy""" - ''' - pass + >>> x = """tricksy""" + ''' + pass # Tests that inverting the triple quoting with an f-string works as # expected. def doctest_with_triple_inverted_fstring(): - ''' - Do cool stuff. + ''' + Do cool stuff. - >>> x = f"""tricksy""" - ''' - pass + >>> x = f"""tricksy""" + ''' + pass # Tests nested doctests are ignored. That is, we don't format doctests @@ -2238,30 +6144,30 @@ def doctest_with_triple_inverted_fstring(): # nesting quotes. It also seems like a generally sensible restriction, # although it could be lifted if necessary I believe. def doctest_nested_doctest_not_formatted(): - ''' - Do cool stuff. + ''' + Do cool stuff. - >>> def nested(x): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass - ''' - pass + >>> def nested(x): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass # Tests that the starting column does not matter. def doctest_varying_start_column(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> assert "Easy!" - >>> import math - >>> math.floor(1.9) - 1 - """ - pass + >>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1 + """ + pass # Tests that long lines get wrapped... appropriately. @@ -2277,61 +6183,61 @@ def doctest_varying_start_column(): # would be to expose another formatter option for controlling the # line-width of code snippets independently. def doctest_long_lines(): - """ - Do cool stuff. + """ + Do cool stuff. - This won't get wrapped even though it exceeds our configured - line width because it doesn't exceed the line width within this - docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) - But this one is long enough to get wrapped. - >>> foo, bar, quux = this_is_a_long_line( - ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard - ... ) - """ - # This demostrates a normal line that will get wrapped but won't - # get wrapped in the docstring above because of how the line-width - # setting gets reset at the first column in each code snippet. - foo, bar, quux = this_is_a_long_line( - lion, giraffe, hippo, zeba, lemur, penguin, monkey - ) + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard + ... ) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) # Checks that a simple but invalid doctest gets skipped. def doctest_skipped_simple(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool-stuff( x ): - 2 - """ - pass + >>> cool-stuff( x ): + 2 + """ + pass # Checks that a simple doctest that is continued over multiple lines, # but is invalid, gets skipped. def doctest_skipped_simple_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool-stuff( x ): - ... print( f"hi {x}" ); - 2 - """ - pass + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass # Checks that a doctest with improper indentation gets skipped. def doctest_skipped_inconsistent_indent(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass # Checks that a doctest with some proper indentation and some improper @@ -2339,34 +6245,34 @@ def doctest_skipped_inconsistent_indent(): # before the inconsistent indentation is formatted. This requires that # the part before it is valid Python. def doctest_skipped_partial_inconsistent_indent(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff(x): - ... print(x) - ... print( f"hi {x}" ); - hi 2 - """ - pass + >>> def cool_stuff(x): + ... print(x) + ... print( f"hi {x}" ); + hi 2 + """ + pass # Checks that a doctest with improper triple single quoted string gets # skipped. That is, the code snippet is itself invalid Python, so it is # left as is. def doctest_skipped_triple_incorrect(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> foo( x ) - ... '''tri'''cksy''' - """ - pass + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass # Tests that a doctest on a single line is skipped. def doctest_skipped_one_line(): - ">>> foo( x )" - pass + ">>> foo( x )" + pass # f-strings are not considered docstrings[1], so any doctests @@ -2374,367 +6280,510 @@ def doctest_skipped_one_line(): # # [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals def doctest_skipped_fstring(): - f""" + f""" Do cool stuff. >>> cool_stuff( 1 ) 2 """ - pass + pass # Test that a doctest containing a triple quoted string at least # does not result in invalid Python code. Ideally this would format # correctly, but at time of writing it does not. def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): - """ - Do cool stuff. + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass + + +############################################################################### +# reStructuredText CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# reStructuredText formatted code blocks. +# +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +############################################################################### + + +def rst_literal_simple(): + """ + Do cool stuff:: + + cool_stuff(1) + + Done. + """ + pass + + +def rst_literal_simple_continued(): + """ + Do cool stuff:: + + def cool_stuff(x): + print(f"hi {x}") + + Done. + """ + pass + + +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: + + cool_stuff(1) + """ + pass + + +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: + + cool_stuff(1)""" + pass + + +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: + + def cool_stuff(x): + print(f"hi {x}") + + + def other_stuff(y): + print(y) + + Done. + """ + pass + + +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: + + + + cool_stuff(1) + + + + Done. + """ + pass + + +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: + + + cool_stuff(1) + + + + """ + pass + - >>> x = '\"\"\"' - """ - pass -``` +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: + cool_stuff(1) -### Output 7 -``` -indent-style = tab -line-width = 88 -indent-width = 8 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Enabled -preview = Disabled -``` -```python -############################################################################### -# DOCTEST CODE EXAMPLES -# -# This section shows examples of docstrings that contain code snippets in -# Python's "doctest" format. -# -# See: https://docs.python.org/3/library/doctest.html -############################################################################### + cool_stuff(2) -# The simplest doctest to ensure basic formatting works. -def doctest_simple(): + Done. """ - Do cool stuff. + pass - >>> cool_stuff(1) - 2 + +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( + ''' + hiya''' + ) + + Done. """ pass -# Another simple test, but one where the Python code -# extends over multiple lines. -def doctest_simple_continued(): +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): """ - Do cool stuff. + Do cool stuff:: - >>> def cool_stuff(x): - ... print(f"hi {x}") - hi 2 + cool_stuff(1) + + Done. """ pass -# Test that we support multiple directly adjacent -# doctests. -def doctest_adjacent(): +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): """ - Do cool stuff. + Do cool stuff:: - >>> cool_stuff(x) - >>> cool_stuff(y) - 2 + cool_stuff(1) + cool_stuff(2) + + Done. """ pass -# Test that a doctest on the last non-whitespace line of a docstring -# reformats correctly. -def doctest_last_line(): +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): """ - Do cool stuff. + Do cool stuff:: - >>> cool_stuff(x) + cool_stuff(1) + + Done. """ pass -# Test that a doctest that continues to the last non-whitespace line of -# a docstring reformats correctly. -def doctest_last_line_continued(): +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): """ - Do cool stuff. + Do cool stuff:: - >>> def cool_stuff(x): - ... print(f"hi {x}") + cool_stuff(1) + cool_stuff(2) + + Done. """ pass -# Test that a doctest is correctly identified and formatted with a blank -# continuation line. -def doctest_blank_continued(): +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): """ - Do cool stuff. + Do cool stuff:: - >>> def cool_stuff(x): - ... print(x) - ... - ... print(x) + cool_stuff(1) + cool_stuff(2) + + Done. """ pass -# Tests that a blank PS2 line at the end of a doctest can get dropped. -# It is treated as part of the Python snippet which will trim the -# trailing whitespace. -def doctest_blank_end(): +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. +# +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): """ - Do cool stuff. + Do cool stuff:: - >>> def cool_stuff(x): - ... print(x) - ... print(x) + cool_stuff(1) + cool_stuff(2) + + Done. """ pass -# Tests that a blank PS2 line at the end of a doctest can get dropped -# even when there is text following it. -def doctest_blank_end_then_some_text(): +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): """ Do cool stuff. - >>> def cool_stuff(x): - ... print(x) - ... print(x) + :: - And say something else. + cool_stuff(1) + + Done. """ pass -# Test that a doctest containing a triple quoted string gets formatted -# correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): +def rst_directive_simple(): """ - Do cool stuff. + .. code-block:: python - >>> x = '''tricksy''' + cool_stuff(1) + + Done. """ pass -# Test that a doctest containing a triple quoted f-string gets -# formatted correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): +def rst_directive_case_insensitive(): """ - Do cool stuff. + .. cOdE-bLoCk:: python - >>> x = f'''tricksy''' + cool_stuff(1) + + Done. """ pass -# Another nested multi-line string case, but with triple escaped double -# quotes inside a triple single quoted string. -def doctest_with_triple_escaped_double(): +def rst_directive_sourcecode(): """ - Do cool stuff. + .. sourcecode:: python - >>> x = '''\"\"\"''' + cool_stuff(1) + + Done. """ pass -# Tests that inverting the triple quoting works as expected. -def doctest_with_triple_inverted(): - ''' - Do cool stuff. +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah - >>> x = """tricksy""" - ''' + cool_stuff(1) + cool_stuff(2) + cool_stuff(3) + cool_stuff(4) + + Done. + """ pass -# Tests that inverting the triple quoting with an f-string works as -# expected. -def doctest_with_triple_inverted_fstring(): - ''' - Do cool stuff. +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon - >>> x = f"""tricksy""" - ''' + >>> cool_stuff(1) + + Done. + """ pass -# Tests nested doctests are ignored. That is, we don't format doctests -# recursively. We only recognize "top level" doctests. -# -# This restriction primarily exists to avoid needing to deal with -# nesting quotes. It also seems like a generally sensible restriction, -# although it could be lifted if necessary I believe. -def doctest_nested_doctest_not_formatted(): - ''' - Do cool stuff. +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: - >>> def nested(x): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass - ''' + cool_stuff( 1 ) + + Done. + """ pass -# Tests that the starting column does not matter. -def doctest_varying_start_column(): +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): """ - Do cool stuff. + Do cool stuff:: - >>> assert "Easy!" - >>> import math - >>> math.floor(1.9) - 1 + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. """ pass -# Tests that long lines get wrapped... appropriately. -# -# The docstring code formatter uses the same line width settings as for -# formatting other code. This means that a line in the docstring can -# actually extend past the configured line limit. -# -# It's not quite clear whether this is desirable or not. We could in -# theory compute the intendation length of a code snippet and then -# adjust the line-width setting on a recursive call to the formatter. -# But there are assuredly pathological cases to consider. Another path -# would be to expose another formatter option for controlling the -# line-width of code snippets independently. -def doctest_long_lines(): +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): """ - Do cool stuff. + Do cool stuff:: - This won't get wrapped even though it exceeds our configured - line width because it doesn't exceed the line width within this - docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + cool_stuff( 1 ) - But this one is long enough to get wrapped. - >>> foo, bar, quux = this_is_a_long_line( - ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard - ... ) + Done. """ - # This demostrates a normal line that will get wrapped but won't - # get wrapped in the docstring above because of how the line-width - # setting gets reset at the first column in each code snippet. - foo, bar, quux = this_is_a_long_line( - lion, giraffe, hippo, zeba, lemur, penguin, monkey - ) + pass -# Checks that a simple but invalid doctest gets skipped. -def doctest_skipped_simple(): +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): """ - Do cool stuff. + Do cool stuff:: - >>> cool-stuff( x ): - 2 + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. """ pass -# Checks that a simple doctest that is continued over multiple lines, -# but is invalid, gets skipped. -def doctest_skipped_simple_continued(): +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. +# +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): """ - Do cool stuff. + Do cool stuff:: - >>> def cool-stuff( x ): - ... print( f"hi {x}" ); - 2 + if True: + cool_stuff( ''' + hiya''' ) + + Done. """ pass -# Checks that a doctest with improper indentation gets skipped. -def doctest_skipped_inconsistent_indent(): +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): """ - Do cool stuff. + .. code-block:: - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 + cool_stuff( 1 ) + + Done. """ pass -# Checks that a doctest with some proper indentation and some improper -# indentation is "partially" formatted. That is, the part that appears -# before the inconsistent indentation is formatted. This requires that -# the part before it is valid Python. -def doctest_skipped_partial_inconsistent_indent(): +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): """ - Do cool stuff. + This is a test. + .. This is a test:: - >>> def cool_stuff(x): - ... print(x) - ... print( f"hi {x}" ); - hi 2 + cool_stuff( 1 ) + + Done. """ pass -# Checks that a doctest with improper triple single quoted string gets -# skipped. That is, the code snippet is itself invalid Python, so it is -# left as is. -def doctest_skipped_triple_incorrect(): +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): """ - Do cool stuff. + Do cool stuff:: - >>> foo( x ) - ... '''tri'''cksy''' + >>> cool_stuff( 1 ) + + Done. """ pass -# Tests that a doctest on a single line is skipped. -def doctest_skipped_one_line(): - ">>> foo( x )" +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ pass -# f-strings are not considered docstrings[1], so any doctests -# inside of them should not be formatted. -# -# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals -def doctest_skipped_fstring(): - f""" - Do cool stuff. +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust - >>> cool_stuff( 1 ) - 2 - """ + cool_stuff( 1 ) + + Done. + """ pass -# Test that a doctest containing a triple quoted string at least -# does not result in invalid Python code. Ideally this would format -# correctly, but at time of writing it does not. -def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): """ - Do cool stuff. + .. code-block:: python - >>> x = '\"\"\"' + >>> cool_stuff( 1 ) + + Done. """ pass ``` @@ -2780,7 +6829,7 @@ def doctest_simple_continued(): Do cool stuff. >>> def cool_stuff(x): - ... print(f"hi {x}") + ... print(f"hi {x}") hi 2 """ pass @@ -2816,9 +6865,30 @@ def doctest_last_line_continued(): """ Do cool stuff. - >>> def cool_stuff(x): - ... print(f"hi {x}") - """ + >>> def cool_stuff(x): + ... print(f"hi {x}") + """ + pass + + +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. + + >>> cool_stuff(x)""" + pass + + +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. + + >>> cool_stuff(x) + ... more(y)""" pass @@ -2829,9 +6899,9 @@ def doctest_blank_continued(): Do cool stuff. >>> def cool_stuff(x): - ... print(x) + ... print(x) ... - ... print(x) + ... print(x) """ pass @@ -2844,8 +6914,8 @@ def doctest_blank_end(): Do cool stuff. >>> def cool_stuff(x): - ... print(x) - ... print(x) + ... print(x) + ... print(x) """ pass @@ -2857,8 +6927,8 @@ def doctest_blank_end_then_some_text(): Do cool stuff. >>> def cool_stuff(x): - ... print(x) - ... print(x) + ... print(x) + ... print(x) And say something else. """ @@ -2930,11 +7000,11 @@ def doctest_nested_doctest_not_formatted(): Do cool stuff. >>> def nested(x): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass ''' pass @@ -2975,7 +7045,7 @@ def doctest_long_lines(): But this one is long enough to get wrapped. >>> foo, bar, quux = this_is_a_long_line( - ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard ... ) """ # This demostrates a normal line that will get wrapped but won't @@ -3031,7 +7101,7 @@ def doctest_skipped_partial_inconsistent_indent(): Do cool stuff. >>> def cool_stuff(x): - ... print(x) + ... print(x) ... print( f"hi {x}" ); hi 2 """ @@ -3081,6 +7151,493 @@ def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): >>> x = '\"\"\"' """ pass + + +############################################################################### +# reStructuredText CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# reStructuredText formatted code blocks. +# +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +############################################################################### + + +def rst_literal_simple(): + """ + Do cool stuff:: + + cool_stuff(1) + + Done. + """ + pass + + +def rst_literal_simple_continued(): + """ + Do cool stuff:: + + def cool_stuff(x): + print(f"hi {x}") + + Done. + """ + pass + + +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: + + cool_stuff(1) + """ + pass + + +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: + + cool_stuff(1)""" + pass + + +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: + + def cool_stuff(x): + print(f"hi {x}") + + + def other_stuff(y): + print(y) + + Done. + """ + pass + + +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: + + + + cool_stuff(1) + + + + Done. + """ + pass + + +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: + + + cool_stuff(1) + + + + """ + pass + + +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: + + cool_stuff(1) + + + cool_stuff(2) + + Done. + """ + pass + + +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( + ''' + hiya''' + ) + + Done. + """ + pass + + +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff:: + + cool_stuff(1) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff(1) + cool_stuff(2) + + Done. + """ + pass + + +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + + cool_stuff(1) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff(1) + cool_stuff(2) + + Done. + """ + pass + + +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): + """ + Do cool stuff:: + + cool_stuff(1) + cool_stuff(2) + + Done. + """ + pass + + +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. +# +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: + + cool_stuff(1) + cool_stuff(2) + + Done. + """ + pass + + +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ + Do cool stuff. + + :: + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_simple(): + """ + .. code-block:: python + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_case_insensitive(): + """ + .. cOdE-bLoCk:: python + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_sourcecode(): + """ + .. sourcecode:: python + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + + cool_stuff(1) + cool_stuff(2) + cool_stuff(3) + cool_stuff(4) + + Done. + """ + pass + + +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon + + >>> cool_stuff(1) + + Done. + """ + pass + + +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. +# +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python + + >>> cool_stuff( 1 ) + + Done. + """ + pass ``` From 3def18fc2100e61f07a7f6c707765c445c20443e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B6rn=20L=C3=B6nnemark?= Date: Tue, 5 Dec 2023 20:42:04 +0100 Subject: [PATCH 117/197] Include version number in release archive names (#9002) ## Summary Add a release's version number to the names of archives containing binaries that are attached to that GitHub release. This makes it possible for users to easily tell archives from different downloaded releases apart. See also: #8961 ## Test Plan The workflow was tested in my fork. The example release can be found at: [https://github.com/tobbez/ruff/releases/tag/v0.1.7](https://github.com/tobbez/ruff/releases/tag/v0.1.7). To allow the workflow run to succeed in the fork while testing, I had to use a small commit to prevent interaction with external services (ghcr, PyPI, and the ruff-pre-commit repository): ```diff diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 86eac6ebc..56b9fa908 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -463,10 +463,12 @@ jobs: id-token: write steps: - uses: actions/download-artifact@v3 + if: false with: name: wheels path: wheels - name: Publish to PyPi + if: false uses: pypa/gh-action-pypi-publish@release/v1 with: skip-existing: true @@ -517,6 +519,7 @@ jobs: tag_name: v${{ inputs.tag }} docker-publish: + if: false # This action doesn't need to wait on any other task, it's easy to re-tag if something failed and we're validating # the tag here also name: Push Docker image ghcr.io/astral-sh/ruff @@ -575,6 +578,7 @@ jobs: # After the release has been published, we update downstream repositories # This is separate because if this fails the release is still fine, we just need to do some manual workflow triggers update-dependents: + if: false name: Update dependents runs-on: ubuntu-latest needs: publish-release ``` Those workflow jobs are however not modified by this PR, so they should not be affected. --- .github/workflows/release.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 2ec8ef052f0f5..86eac6ebcdbf3 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -86,7 +86,7 @@ jobs: path: dist - name: "Archive binary" run: | - ARCHIVE_FILE=ruff-x86_64-apple-darwin.tar.gz + ARCHIVE_FILE=ruff-${{ inputs.tag }}-x86_64-apple-darwin.tar.gz tar czvf $ARCHIVE_FILE -C target/x86_64-apple-darwin/release ruff shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256 - name: "Upload binary" @@ -125,7 +125,7 @@ jobs: path: dist - name: "Archive binary" run: | - ARCHIVE_FILE=ruff-aarch64-apple-darwin.tar.gz + ARCHIVE_FILE=ruff-${{ inputs.tag }}-aarch64-apple-darwin.tar.gz tar czvf $ARCHIVE_FILE -C target/aarch64-apple-darwin/release ruff shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256 - name: "Upload binary" @@ -177,7 +177,7 @@ jobs: - name: "Archive binary" shell: bash run: | - ARCHIVE_FILE=ruff-${{ matrix.platform.target }}.zip + ARCHIVE_FILE=ruff-${{ inputs.tag }}-${{ matrix.platform.target }}.zip 7z a $ARCHIVE_FILE ./target/${{ matrix.platform.target }}/release/ruff.exe sha256sum $ARCHIVE_FILE > $ARCHIVE_FILE.sha256 - name: "Upload binary" @@ -224,7 +224,7 @@ jobs: path: dist - name: "Archive binary" run: | - ARCHIVE_FILE=ruff-${{ matrix.target }}.tar.gz + ARCHIVE_FILE=ruff-${{ inputs.tag }}-${{ matrix.target }}.tar.gz tar czvf $ARCHIVE_FILE -C target/${{ matrix.target }}/release ruff shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256 - name: "Upload binary" @@ -291,7 +291,7 @@ jobs: path: dist - name: "Archive binary" run: | - ARCHIVE_FILE=ruff-${{ matrix.platform.target }}.tar.gz + ARCHIVE_FILE=ruff-${{ inputs.tag }}-${{ matrix.platform.target }}.tar.gz tar czvf $ARCHIVE_FILE -C target/${{ matrix.platform.target }}/release ruff shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256 - name: "Upload binary" @@ -343,7 +343,7 @@ jobs: path: dist - name: "Archive binary" run: | - ARCHIVE_FILE=ruff-${{ matrix.target }}.tar.gz + ARCHIVE_FILE=ruff-${{ inputs.tag }}-${{ matrix.target }}.tar.gz tar czvf $ARCHIVE_FILE -C target/${{ matrix.target }}/release ruff shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256 - name: "Upload binary" @@ -399,7 +399,7 @@ jobs: path: dist - name: "Archive binary" run: | - ARCHIVE_FILE=ruff-${{ matrix.platform.target }}.tar.gz + ARCHIVE_FILE=ruff-${{ inputs.tag }}-${{ matrix.platform.target }}.tar.gz tar czvf $ARCHIVE_FILE -C target/${{ matrix.platform.target }}/release ruff shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256 - name: "Upload binary" From 268d95e9111caefea5ddf30d8a3608ee12a45cb1 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 5 Dec 2023 15:25:28 -0500 Subject: [PATCH 118/197] Apply unnecessary index rule prior to enumerate rewrite (#9012) This PR adds synthetic edits to `PLR1736` to avoid removing the referenced value as part of `FURB148`. Closes https://github.com/astral-sh/ruff/issues/9010. --- .../rules/unnecessary_dict_index_lookup.rs | 37 +++++++++++-------- .../rules/unnecessary_list_index_lookup.rs | 37 +++++++++++-------- 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dict_index_lookup.rs b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dict_index_lookup.rs index 88a842b7d6b4b..913279081fcc4 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dict_index_lookup.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dict_index_lookup.rs @@ -2,6 +2,7 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::visitor::Visitor; use ruff_python_ast::{self as ast, Expr, StmtFor}; +use ruff_text_size::Ranged; use crate::checkers::ast::Checker; use crate::rules::pylint::helpers::SequenceIndexVisitor; @@ -51,7 +52,7 @@ pub(crate) fn unnecessary_dict_index_lookup(checker: &mut Checker, stmt_for: &St }; let ranges = { - let mut visitor = SequenceIndexVisitor::new(dict_name, index_name, value_name); + let mut visitor = SequenceIndexVisitor::new(&dict_name.id, &index_name.id, &value_name.id); visitor.visit_body(&stmt_for.body); visitor.visit_body(&stmt_for.orelse); visitor.into_accesses() @@ -59,10 +60,10 @@ pub(crate) fn unnecessary_dict_index_lookup(checker: &mut Checker, stmt_for: &St for range in ranges { let mut diagnostic = Diagnostic::new(UnnecessaryDictIndexLookup, range); - diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - value_name.to_string(), - range, - ))); + diagnostic.set_fix(Fix::safe_edits( + Edit::range_replacement(value_name.id.to_string(), range), + [noop(index_name), noop(value_name)], + )); checker.diagnostics.push(diagnostic); } } @@ -93,7 +94,8 @@ pub(crate) fn unnecessary_dict_index_lookup_comprehension(checker: &mut Checker, }; let ranges = { - let mut visitor = SequenceIndexVisitor::new(dict_name, index_name, value_name); + let mut visitor = + SequenceIndexVisitor::new(&dict_name.id, &index_name.id, &value_name.id); visitor.visit_expr(elt.as_ref()); for expr in &comp.ifs { visitor.visit_expr(expr); @@ -103,10 +105,10 @@ pub(crate) fn unnecessary_dict_index_lookup_comprehension(checker: &mut Checker, for range in ranges { let mut diagnostic = Diagnostic::new(UnnecessaryDictIndexLookup, range); - diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - value_name.to_string(), - range, - ))); + diagnostic.set_fix(Fix::safe_edits( + Edit::range_replacement(value_name.id.to_string(), range), + [noop(index_name), noop(value_name)], + )); checker.diagnostics.push(diagnostic); } } @@ -115,7 +117,7 @@ pub(crate) fn unnecessary_dict_index_lookup_comprehension(checker: &mut Checker, fn dict_items<'a>( call_expr: &'a Expr, tuple_expr: &'a Expr, -) -> Option<(&'a str, &'a str, &'a str)> { +) -> Option<(&'a ast::ExprName, &'a ast::ExprName, &'a ast::ExprName)> { let ast::ExprCall { func, arguments, .. } = call_expr.as_call_expr()?; @@ -130,7 +132,7 @@ fn dict_items<'a>( return None; } - let Expr::Name(ast::ExprName { id: dict_name, .. }) = value.as_ref() else { + let Expr::Name(dict_name) = value.as_ref() else { return None; }; @@ -142,19 +144,24 @@ fn dict_items<'a>( }; // Grab the variable names. - let Expr::Name(ast::ExprName { id: index_name, .. }) = index else { + let Expr::Name(index_name) = index else { return None; }; - let Expr::Name(ast::ExprName { id: value_name, .. }) = value else { + let Expr::Name(value_name) = value else { return None; }; // If either of the variable names are intentionally ignored by naming them `_`, then don't // emit. - if index_name == "_" || value_name == "_" { + if index_name.id == "_" || value_name.id == "_" { return None; } Some((dict_name, index_name, value_name)) } + +/// Return a no-op edit for the given name. +fn noop(name: &ast::ExprName) -> Edit { + Edit::range_replacement(name.id.to_string(), name.range()) +} diff --git a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs index 920d2442e9b5a..461a8d56c94c6 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_list_index_lookup.rs @@ -3,6 +3,7 @@ use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::visitor::Visitor; use ruff_python_ast::{self as ast, Expr, StmtFor}; use ruff_python_semantic::SemanticModel; +use ruff_text_size::Ranged; use crate::checkers::ast::Checker; use crate::rules::pylint::helpers::SequenceIndexVisitor; @@ -53,7 +54,7 @@ pub(crate) fn unnecessary_list_index_lookup(checker: &mut Checker, stmt_for: &St }; let ranges = { - let mut visitor = SequenceIndexVisitor::new(sequence, index_name, value_name); + let mut visitor = SequenceIndexVisitor::new(&sequence.id, &index_name.id, &value_name.id); visitor.visit_body(&stmt_for.body); visitor.visit_body(&stmt_for.orelse); visitor.into_accesses() @@ -61,10 +62,10 @@ pub(crate) fn unnecessary_list_index_lookup(checker: &mut Checker, stmt_for: &St for range in ranges { let mut diagnostic = Diagnostic::new(UnnecessaryListIndexLookup, range); - diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - value_name.to_string(), - range, - ))); + diagnostic.set_fix(Fix::safe_edits( + Edit::range_replacement(value_name.id.to_string(), range), + [noop(index_name), noop(value_name)], + )); checker.diagnostics.push(diagnostic); } } @@ -97,17 +98,18 @@ pub(crate) fn unnecessary_list_index_lookup_comprehension(checker: &mut Checker, }; let ranges = { - let mut visitor = SequenceIndexVisitor::new(sequence, index_name, value_name); + let mut visitor = + SequenceIndexVisitor::new(&sequence.id, &index_name.id, &value_name.id); visitor.visit_expr(elt.as_ref()); visitor.into_accesses() }; for range in ranges { let mut diagnostic = Diagnostic::new(UnnecessaryListIndexLookup, range); - diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - value_name.to_string(), - range, - ))); + diagnostic.set_fix(Fix::safe_edits( + Edit::range_replacement(value_name.id.to_string(), range), + [noop(index_name), noop(value_name)], + )); checker.diagnostics.push(diagnostic); } } @@ -117,7 +119,7 @@ fn enumerate_items<'a>( call_expr: &'a Expr, tuple_expr: &'a Expr, semantic: &SemanticModel, -) -> Option<(&'a str, &'a str, &'a str)> { +) -> Option<(&'a ast::ExprName, &'a ast::ExprName, &'a ast::ExprName)> { let ast::ExprCall { func, arguments, .. } = call_expr.as_call_expr()?; @@ -138,24 +140,29 @@ fn enumerate_items<'a>( }; // Grab the variable names. - let Expr::Name(ast::ExprName { id: index_name, .. }) = index else { + let Expr::Name(index_name) = index else { return None; }; - let Expr::Name(ast::ExprName { id: value_name, .. }) = value else { + let Expr::Name(value_name) = value else { return None; }; // If either of the variable names are intentionally ignored by naming them `_`, then don't // emit. - if index_name == "_" || value_name == "_" { + if index_name.id == "_" || value_name.id == "_" { return None; } // Get the first argument of the enumerate call. - let Some(Expr::Name(ast::ExprName { id: sequence, .. })) = arguments.args.first() else { + let Some(Expr::Name(sequence)) = arguments.args.first() else { return None; }; Some((sequence, index_name, value_name)) } + +/// Return a no-op edit for the given name. +fn noop(name: &ast::ExprName) -> Edit { + Edit::range_replacement(name.id.to_string(), name.range()) +} From 958702ded068c20cb83d58312e892eb73b4276e0 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 5 Dec 2023 16:30:29 -0500 Subject: [PATCH 119/197] Respect trailing comma in unnecessary-dict-kwargs (#9015) Closes https://github.com/astral-sh/ruff/issues/9014. --- .../test/fixtures/flake8_pie/PIE804.py | 3 ++- .../src/checkers/ast/analyze/expression.rs | 2 +- .../rules/unnecessary_dict_kwargs.rs | 21 +++++++++++++----- ...__flake8_pie__tests__PIE804_PIE804.py.snap | 22 +++++++++++++++++-- 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE804.py b/crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE804.py index 84274c853a8aa..03d88e0ef8e22 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE804.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE804.py @@ -10,7 +10,6 @@ foo(**{}) - foo(**{**data, "foo": "buzz"}) foo(**buzz) foo(**{"bar-foo": True}) @@ -20,3 +19,5 @@ foo(**{"": True}) foo(**{f"buzz__{bar}": True}) abc(**{"for": 3}) + +foo(**{},) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 87a354b9641f3..381a53adbd1dd 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -543,7 +543,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { flake8_bugbear::rules::no_explicit_stacklevel(checker, call); } if checker.enabled(Rule::UnnecessaryDictKwargs) { - flake8_pie::rules::unnecessary_dict_kwargs(checker, expr, keywords); + flake8_pie::rules::unnecessary_dict_kwargs(checker, call); } if checker.enabled(Rule::UnnecessaryRangeStart) { flake8_pie::rules::unnecessary_range_start(checker, call); diff --git a/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs b/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs index c4625444f7bde..ab4c7ceb9ddcc 100644 --- a/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs +++ b/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs @@ -1,6 +1,6 @@ use itertools::Itertools; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; -use ruff_python_ast::{self as ast, Expr, Keyword}; +use ruff_python_ast::{self as ast, Expr}; use ruff_macros::{derive_message_formats, violation}; use ruff_text_size::Ranged; @@ -8,6 +8,7 @@ use ruff_text_size::Ranged; use ruff_python_stdlib::identifiers::is_identifier; use crate::checkers::ast::Checker; +use crate::fix::edits::{remove_argument, Parentheses}; /// ## What it does /// Checks for unnecessary `dict` kwargs. @@ -52,8 +53,8 @@ impl AlwaysFixableViolation for UnnecessaryDictKwargs { } /// PIE804 -pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, expr: &Expr, kwargs: &[Keyword]) { - for kw in kwargs { +pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, call: &ast::ExprCall) { + for kw in &call.arguments.keywords { // keyword is a spread operator (indicated by None) if kw.arg.is_some() { continue; @@ -65,7 +66,7 @@ pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, expr: &Expr, kwargs // Ex) `foo(**{**bar})` if matches!(keys.as_slice(), [None]) { - let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, expr.range()); + let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, call.range()); diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( format!("**{}", checker.locator().slice(values[0].range())), @@ -86,10 +87,18 @@ pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, expr: &Expr, kwargs continue; } - let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, expr.range()); + let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, call.range()); if values.is_empty() { - diagnostic.set_fix(Fix::safe_edit(Edit::deletion(kw.start(), kw.end()))); + diagnostic.try_set_fix(|| { + remove_argument( + kw, + &call.arguments, + Parentheses::Preserve, + checker.locator().contents(), + ) + .map(Fix::safe_edit) + }); } else { diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( kwargs diff --git a/crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE804_PIE804.py.snap b/crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE804_PIE804.py.snap index 450ed048e6e4a..0f608fbedb040 100644 --- a/crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE804_PIE804.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE804_PIE804.py.snap @@ -106,6 +106,8 @@ PIE804.py:11:1: PIE804 [*] Unnecessary `dict` kwargs 10 | 11 | foo(**{}) | ^^^^^^^^^ PIE804 +12 | +13 | foo(**{**data, "foo": "buzz"}) | = help: Remove unnecessary kwargs @@ -116,7 +118,23 @@ PIE804.py:11:1: PIE804 [*] Unnecessary `dict` kwargs 11 |-foo(**{}) 11 |+foo() 12 12 | -13 13 | -14 14 | foo(**{**data, "foo": "buzz"}) +13 13 | foo(**{**data, "foo": "buzz"}) +14 14 | foo(**buzz) + +PIE804.py:23:1: PIE804 [*] Unnecessary `dict` kwargs + | +21 | abc(**{"for": 3}) +22 | +23 | foo(**{},) + | ^^^^^^^^^^ PIE804 + | + = help: Remove unnecessary kwargs + +ℹ Safe fix +20 20 | foo(**{f"buzz__{bar}": True}) +21 21 | abc(**{"for": 3}) +22 22 | +23 |-foo(**{},) + 23 |+foo() From b4a050c21d96e866239770bbd5d2d62881b9557e Mon Sep 17 00:00:00 2001 From: Eero Vaher Date: Wed, 6 Dec 2023 02:12:10 +0100 Subject: [PATCH 120/197] Fix formatting of a warning box in docs (#9017) ## Summary The last few words of a sentence that should be inside a warning box (in https://docs.astral.sh/ruff/configuration/#default-inclusions) are currently placed just after it because of a mistake in indentation. --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 85071a439f072..e2a3cfb37cc8e 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -338,7 +338,7 @@ You can also change the default selection using the [`include`](settings.md#incl !!! warning Paths provided to `include` _must_ match files. For example, `include = ["src"]` will fail since it -matches a directory. + matches a directory. ## Jupyter Notebook discovery From ee6548d7dd1b04421d802ddf78ef1ae47cbd95ff Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Wed, 6 Dec 2023 16:15:06 +0900 Subject: [PATCH 121/197] Enforce valid format options in spec tests (#9021) --- .../test/fixtures/black/cases/ignore_pyi.pyi | 7 ++-- .../cases/line_ranges_fmt_off_decorator.py | 9 ++++ .../line_ranges_fmt_off_decorator.py.expect | 11 ++++- .../black/cases/linelength6.options.json | 2 +- .../black/cases/power_op_newline.options.json | 2 +- .../test/fixtures/import_black_tests.py | 3 +- crates/ruff_python_formatter/src/options.rs | 2 +- ...k_compatibility@cases__ignore_pyi.pyi.snap | 25 +++-------- ...ses__line_ranges_fmt_off_decorator.py.snap | 42 +++++++++++++++++-- ...patibility@cases__power_op_newline.py.snap | 19 +++++---- 10 files changed, 83 insertions(+), 39 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/ignore_pyi.pyi b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/ignore_pyi.pyi index 64230590670a4..5e643ea38e4f7 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/ignore_pyi.pyi +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/ignore_pyi.pyi @@ -15,7 +15,6 @@ def g(): # hi ... -# FIXME(#8905): Uncomment, leads to unstable formatting -# def h(): -# ... -# # bye +def h(): + ... + # bye diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py index 3c9e616d83a98..8ae63e21716b8 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py @@ -9,3 +9,12 @@ class MyClass: # fmt: on def method(): print ( "str" ) + + @decor( + a=1, + # fmt: off + b=(2, 3), + # fmt: on + ) + def func(): + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py.expect b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py.expect index 326b48df6b4f4..905336810bff8 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py.expect +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/line_ranges_fmt_off_decorator.py.expect @@ -1,4 +1,4 @@ -# flags: --line-ranges=12-12 +# flags: --line-ranges=12-12 --line-ranges=21-21 # NOTE: If you need to modify this file, pay special attention to the --line-ranges= # flag above as it's formatting specifically these lines. @@ -10,3 +10,12 @@ class MyClass: # fmt: on def method(): print("str") + + @decor( + a=1, + # fmt: off + b=(2, 3), + # fmt: on + ) + def func(): + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/linelength6.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/linelength6.options.json index f6d0b5fa4c54c..d5eda5fc94062 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/linelength6.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/linelength6.options.json @@ -1 +1 @@ -{"line_length": 6} \ No newline at end of file +{"line_width": 6} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_newline.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_newline.options.json index 80ad04dcfc445..70fa4ec1b938a 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_newline.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/power_op_newline.options.json @@ -1 +1 @@ -{"line_length": 0} \ No newline at end of file +{"line_width": 1} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/import_black_tests.py b/crates/ruff_python_formatter/resources/test/fixtures/import_black_tests.py index 31d1515aefe3e..b196876e7063e 100755 --- a/crates/ruff_python_formatter/resources/test/fixtures/import_black_tests.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/import_black_tests.py @@ -48,7 +48,8 @@ def import_fixture(fixture: Path, fixture_set: str): if "--line-length=" in flags: [_, length_and_rest] = flags.split("--line-length=", 1) length = length_and_rest.split(" ", 1)[0] - options["line_length"] = int(length) + length = int(length) + options["line_width"] = 1 if length == 0 else length if "--skip-magic-trailing-comma" in flags: options["magic_trailing_comma"] = "ignore" diff --git a/crates/ruff_python_formatter/src/options.rs b/crates/ruff_python_formatter/src/options.rs index 8306afd82c431..a07fabbb9a795 100644 --- a/crates/ruff_python_formatter/src/options.rs +++ b/crates/ruff_python_formatter/src/options.rs @@ -11,7 +11,7 @@ use std::str::FromStr; #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), - serde(default) + serde(default, deny_unknown_fields) )] pub struct PyFormatOptions { /// Whether we're in a `.py` file or `.pyi` file, which have different rules. diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__ignore_pyi.pyi.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__ignore_pyi.pyi.snap index ed9ee11309184..0d405b5b573a2 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__ignore_pyi.pyi.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__ignore_pyi.pyi.snap @@ -22,10 +22,9 @@ def g(): # hi ... -# FIXME(#8905): Uncomment, leads to unstable formatting -# def h(): -# ... -# # bye +def h(): + ... + # bye ``` ## Black Differences @@ -41,17 +40,6 @@ def g(): class y: ... # comment # whitespace doesn't matter (note the next line has a trailing space and tab) -@@ -13,6 +12,7 @@ - # hi - ... - --def h(): -- ... -- # bye -+# FIXME(#8905): Uncomment, leads to unstable formatting -+# def h(): -+# ... -+# # bye ``` ## Ruff Output @@ -71,10 +59,9 @@ def g(): # hi ... -# FIXME(#8905): Uncomment, leads to unstable formatting -# def h(): -# ... -# # bye +def h(): + ... + # bye ``` ## Black Output diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off_decorator.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off_decorator.py.snap index 4ac42448f3593..d14b92cc08c31 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off_decorator.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__line_ranges_fmt_off_decorator.py.snap @@ -16,6 +16,15 @@ class MyClass: # fmt: on def method(): print ( "str" ) + + @decor( + a=1, + # fmt: off + b=(2, 3), + # fmt: on + ) + def func(): + pass ``` ## Black Differences @@ -23,8 +32,8 @@ class MyClass: ```diff --- Black +++ Ruff -@@ -1,12 +1,10 @@ --# flags: --line-ranges=12-12 +@@ -1,15 +1,13 @@ +-# flags: --line-ranges=12-12 --line-ranges=21-21 # NOTE: If you need to modify this file, pay special attention to the --line-ranges= # flag above as it's formatting specifically these lines. @@ -37,6 +46,15 @@ class MyClass: def method(): - print("str") + print ( "str" ) + + @decor( + a=1, +@@ -18,4 +16,4 @@ + # fmt: on + ) + def func(): +- pass ++ pass ``` ## Ruff Output @@ -52,12 +70,21 @@ class MyClass: # fmt: on def method(): print ( "str" ) + + @decor( + a=1, + # fmt: off + b=(2, 3), + # fmt: on + ) + def func(): + pass ``` ## Black Output ```python -# flags: --line-ranges=12-12 +# flags: --line-ranges=12-12 --line-ranges=21-21 # NOTE: If you need to modify this file, pay special attention to the --line-ranges= # flag above as it's formatting specifically these lines. @@ -69,6 +96,15 @@ class MyClass: # fmt: on def method(): print("str") + + @decor( + a=1, + # fmt: off + b=(2, 3), + # fmt: on + ) + def func(): + pass ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__power_op_newline.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__power_op_newline.py.snap index 1796017091aa5..bb1b6eed95ecb 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__power_op_newline.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__power_op_newline.py.snap @@ -13,21 +13,24 @@ importA;()<<0**0# ```diff --- Black +++ Ruff -@@ -1,6 +1,2 @@ - importA --( -- () -- << 0 +@@ -2,5 +2,5 @@ + ( + () + << 0 - ** 0 --) # -+() << 0**0 # ++ **0 + ) # ``` ## Ruff Output ```python importA -() << 0**0 # +( + () + << 0 + **0 +) # ``` ## Black Output From bd443ebe9124aae8ac05d46b533a6f62dcfad21e Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Wed, 6 Dec 2023 10:52:19 -0600 Subject: [PATCH 122/197] Add visitor tests for strings, bytes, f-strings (#9009) This PR adds tests for visitor implementation for string literals, bytes literals and f-strings. --- crates/ruff_python_ast/tests/preorder.rs | 50 +++++++++++++++++-- .../snapshots/preorder__bytes_literals.snap | 11 ++++ .../tests/snapshots/preorder__f_strings.snap | 22 ++++++++ .../snapshots/preorder__string_literals.snap | 11 ++++ .../snapshots/visitor__bytes_literals.snap | 10 ++++ .../tests/snapshots/visitor__f_strings.snap | 21 ++++++++ .../snapshots/visitor__string_literals.snap | 10 ++++ crates/ruff_python_ast/tests/visitor.rs | 49 ++++++++++++++++-- 8 files changed, 174 insertions(+), 10 deletions(-) create mode 100644 crates/ruff_python_ast/tests/snapshots/preorder__bytes_literals.snap create mode 100644 crates/ruff_python_ast/tests/snapshots/preorder__f_strings.snap create mode 100644 crates/ruff_python_ast/tests/snapshots/preorder__string_literals.snap create mode 100644 crates/ruff_python_ast/tests/snapshots/visitor__bytes_literals.snap create mode 100644 crates/ruff_python_ast/tests/snapshots/visitor__f_strings.snap create mode 100644 crates/ruff_python_ast/tests/snapshots/visitor__string_literals.snap diff --git a/crates/ruff_python_ast/tests/preorder.rs b/crates/ruff_python_ast/tests/preorder.rs index 106ce9138967c..37e8d72fa83b0 100644 --- a/crates/ruff_python_ast/tests/preorder.rs +++ b/crates/ruff_python_ast/tests/preorder.rs @@ -3,14 +3,15 @@ use std::fmt::{Debug, Write}; use insta::assert_snapshot; use ruff_python_ast::visitor::preorder::{ - walk_alias, walk_comprehension, walk_except_handler, walk_expr, walk_keyword, walk_match_case, - walk_module, walk_parameter, walk_parameters, walk_pattern, walk_stmt, walk_type_param, - walk_with_item, PreorderVisitor, + walk_alias, walk_bytes_literal, walk_comprehension, walk_except_handler, walk_expr, + walk_keyword, walk_match_case, walk_module, walk_parameter, walk_parameters, walk_pattern, + walk_stmt, walk_string_literal, walk_type_param, walk_with_item, PreorderVisitor, }; use ruff_python_ast::AnyNodeRef; use ruff_python_ast::{ - Alias, BoolOp, CmpOp, Comprehension, ExceptHandler, Expr, Keyword, MatchCase, Mod, Operator, - Parameter, Parameters, Pattern, Singleton, Stmt, TypeParam, UnaryOp, WithItem, + Alias, BoolOp, BytesLiteral, CmpOp, Comprehension, ExceptHandler, Expr, Keyword, MatchCase, + Mod, Operator, Parameter, Parameters, Pattern, Singleton, Stmt, StringLiteral, TypeParam, + UnaryOp, WithItem, }; use ruff_python_parser::lexer::lex; use ruff_python_parser::{parse_tokens, Mode}; @@ -128,6 +129,33 @@ fn function_type_parameters() { assert_snapshot!(trace); } +#[test] +fn string_literals() { + let source = r"'a' 'b' 'c'"; + + let trace = trace_preorder_visitation(source); + + assert_snapshot!(trace); +} + +#[test] +fn bytes_literals() { + let source = r"b'a' b'b' b'c'"; + + let trace = trace_preorder_visitation(source); + + assert_snapshot!(trace); +} + +#[test] +fn f_strings() { + let source = r"'pre' f'foo {bar:.{x}f} baz'"; + + let trace = trace_preorder_visitation(source); + + assert_snapshot!(trace); +} + fn trace_preorder_visitation(source: &str) -> String { let tokens = lex(source, Mode::Module); let parsed = parse_tokens(tokens, source, Mode::Module, "test.py").unwrap(); @@ -278,4 +306,16 @@ impl PreorderVisitor<'_> for RecordVisitor { walk_type_param(self, type_param); self.exit_node(); } + + fn visit_string_literal(&mut self, string_literal: &StringLiteral) { + self.enter_node(string_literal); + walk_string_literal(self, string_literal); + self.exit_node(); + } + + fn visit_bytes_literal(&mut self, bytes_literal: &BytesLiteral) { + self.enter_node(bytes_literal); + walk_bytes_literal(self, bytes_literal); + self.exit_node(); + } } diff --git a/crates/ruff_python_ast/tests/snapshots/preorder__bytes_literals.snap b/crates/ruff_python_ast/tests/snapshots/preorder__bytes_literals.snap new file mode 100644 index 0000000000000..d71ea07e19274 --- /dev/null +++ b/crates/ruff_python_ast/tests/snapshots/preorder__bytes_literals.snap @@ -0,0 +1,11 @@ +--- +source: crates/ruff_python_ast/tests/preorder.rs +expression: trace +--- +- ModModule + - StmtExpr + - ExprBytesLiteral + - BytesLiteral + - BytesLiteral + - BytesLiteral + diff --git a/crates/ruff_python_ast/tests/snapshots/preorder__f_strings.snap b/crates/ruff_python_ast/tests/snapshots/preorder__f_strings.snap new file mode 100644 index 0000000000000..426a155c787ec --- /dev/null +++ b/crates/ruff_python_ast/tests/snapshots/preorder__f_strings.snap @@ -0,0 +1,22 @@ +--- +source: crates/ruff_python_ast/tests/preorder.rs +expression: trace +--- +- ModModule + - StmtExpr + - ExprFString + - StringLiteral + - ExprStringLiteral + - StringLiteral + - ExprFormattedValue + - ExprName + - ExprFString + - ExprStringLiteral + - StringLiteral + - ExprFormattedValue + - ExprName + - ExprStringLiteral + - StringLiteral + - ExprStringLiteral + - StringLiteral + diff --git a/crates/ruff_python_ast/tests/snapshots/preorder__string_literals.snap b/crates/ruff_python_ast/tests/snapshots/preorder__string_literals.snap new file mode 100644 index 0000000000000..7b62ce78b72f7 --- /dev/null +++ b/crates/ruff_python_ast/tests/snapshots/preorder__string_literals.snap @@ -0,0 +1,11 @@ +--- +source: crates/ruff_python_ast/tests/preorder.rs +expression: trace +--- +- ModModule + - StmtExpr + - ExprStringLiteral + - StringLiteral + - StringLiteral + - StringLiteral + diff --git a/crates/ruff_python_ast/tests/snapshots/visitor__bytes_literals.snap b/crates/ruff_python_ast/tests/snapshots/visitor__bytes_literals.snap new file mode 100644 index 0000000000000..57bed3a9c7502 --- /dev/null +++ b/crates/ruff_python_ast/tests/snapshots/visitor__bytes_literals.snap @@ -0,0 +1,10 @@ +--- +source: crates/ruff_python_ast/tests/visitor.rs +expression: trace +--- +- StmtExpr + - ExprBytesLiteral + - BytesLiteral + - BytesLiteral + - BytesLiteral + diff --git a/crates/ruff_python_ast/tests/snapshots/visitor__f_strings.snap b/crates/ruff_python_ast/tests/snapshots/visitor__f_strings.snap new file mode 100644 index 0000000000000..195de7cd4b40a --- /dev/null +++ b/crates/ruff_python_ast/tests/snapshots/visitor__f_strings.snap @@ -0,0 +1,21 @@ +--- +source: crates/ruff_python_ast/tests/visitor.rs +expression: trace +--- +- StmtExpr + - ExprFString + - StringLiteral + - ExprStringLiteral + - StringLiteral + - ExprFormattedValue + - ExprName + - ExprFString + - ExprStringLiteral + - StringLiteral + - ExprFormattedValue + - ExprName + - ExprStringLiteral + - StringLiteral + - ExprStringLiteral + - StringLiteral + diff --git a/crates/ruff_python_ast/tests/snapshots/visitor__string_literals.snap b/crates/ruff_python_ast/tests/snapshots/visitor__string_literals.snap new file mode 100644 index 0000000000000..7c066eae56989 --- /dev/null +++ b/crates/ruff_python_ast/tests/snapshots/visitor__string_literals.snap @@ -0,0 +1,10 @@ +--- +source: crates/ruff_python_ast/tests/visitor.rs +expression: trace +--- +- StmtExpr + - ExprStringLiteral + - StringLiteral + - StringLiteral + - StringLiteral + diff --git a/crates/ruff_python_ast/tests/visitor.rs b/crates/ruff_python_ast/tests/visitor.rs index a503009566f78..3e4a32ebdd126 100644 --- a/crates/ruff_python_ast/tests/visitor.rs +++ b/crates/ruff_python_ast/tests/visitor.rs @@ -6,14 +6,14 @@ use ruff_python_parser::lexer::lex; use ruff_python_parser::{parse_tokens, Mode}; use ruff_python_ast::visitor::{ - walk_alias, walk_comprehension, walk_except_handler, walk_expr, walk_keyword, walk_match_case, - walk_parameter, walk_parameters, walk_pattern, walk_stmt, walk_type_param, walk_with_item, - Visitor, + walk_alias, walk_bytes_literal, walk_comprehension, walk_except_handler, walk_expr, + walk_keyword, walk_match_case, walk_parameter, walk_parameters, walk_pattern, walk_stmt, + walk_string_literal, walk_type_param, walk_with_item, Visitor, }; use ruff_python_ast::AnyNodeRef; use ruff_python_ast::{ - Alias, BoolOp, CmpOp, Comprehension, ExceptHandler, Expr, Keyword, MatchCase, Operator, - Parameter, Parameters, Pattern, Stmt, TypeParam, UnaryOp, WithItem, + Alias, BoolOp, BytesLiteral, CmpOp, Comprehension, ExceptHandler, Expr, Keyword, MatchCase, + Operator, Parameter, Parameters, Pattern, Stmt, StringLiteral, TypeParam, UnaryOp, WithItem, }; #[test] @@ -129,6 +129,33 @@ fn function_type_parameters() { assert_snapshot!(trace); } +#[test] +fn string_literals() { + let source = r"'a' 'b' 'c'"; + + let trace = trace_visitation(source); + + assert_snapshot!(trace); +} + +#[test] +fn bytes_literals() { + let source = r"b'a' b'b' b'c'"; + + let trace = trace_visitation(source); + + assert_snapshot!(trace); +} + +#[test] +fn f_strings() { + let source = r"'pre' f'foo {bar:.{x}f} baz'"; + + let trace = trace_visitation(source); + + assert_snapshot!(trace); +} + fn trace_visitation(source: &str) -> String { let tokens = lex(source, Mode::Module); let parsed = parse_tokens(tokens, source, Mode::Module, "test.py").unwrap(); @@ -281,4 +308,16 @@ impl Visitor<'_> for RecordVisitor { walk_type_param(self, type_param); self.exit_node(); } + + fn visit_string_literal(&mut self, string_literal: &StringLiteral) { + self.enter_node(string_literal); + walk_string_literal(self, string_literal); + self.exit_node(); + } + + fn visit_bytes_literal(&mut self, bytes_literal: &BytesLiteral) { + self.enter_node(bytes_literal); + walk_bytes_literal(self, bytes_literal); + self.exit_node(); + } } From ef7778d7948cfc759883225c51c5372a859842d4 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Wed, 6 Dec 2023 10:58:51 -0600 Subject: [PATCH 123/197] Fix preorder visitor tests (#9025) Follow-up PR to #9009 to fix the `PreorderVisitor` test cases as suggested here: https://github.com/astral-sh/ruff/pull/9009#discussion_r1416459688 --- .../ruff_python_ast/src/visitor/preorder.rs | 1 - crates/ruff_python_ast/tests/preorder.rs | 130 ++---------------- .../preorder__class_type_parameters.snap | 11 +- .../tests/snapshots/preorder__decorators.snap | 6 +- .../tests/snapshots/preorder__f_strings.snap | 29 ++-- .../preorder__function_arguments.snap | 26 ++-- ...function_positional_only_with_default.snap | 13 +- .../preorder__function_type_parameters.snap | 11 +- .../preorder__match_class_pattern.snap | 25 ++-- .../snapshots/preorder__type_aliases.snap | 11 +- 10 files changed, 86 insertions(+), 177 deletions(-) diff --git a/crates/ruff_python_ast/src/visitor/preorder.rs b/crates/ruff_python_ast/src/visitor/preorder.rs index 5b2e3ad793ef5..ad5cbceccc65b 100644 --- a/crates/ruff_python_ast/src/visitor/preorder.rs +++ b/crates/ruff_python_ast/src/visitor/preorder.rs @@ -139,7 +139,6 @@ pub trait PreorderVisitor<'a> { } #[inline] - fn visit_pattern_keyword(&mut self, pattern_keyword: &'a PatternKeyword) { walk_pattern_keyword(self, pattern_keyword); } diff --git a/crates/ruff_python_ast/tests/preorder.rs b/crates/ruff_python_ast/tests/preorder.rs index 37e8d72fa83b0..ea0542d9f1e6f 100644 --- a/crates/ruff_python_ast/tests/preorder.rs +++ b/crates/ruff_python_ast/tests/preorder.rs @@ -2,17 +2,8 @@ use std::fmt::{Debug, Write}; use insta::assert_snapshot; -use ruff_python_ast::visitor::preorder::{ - walk_alias, walk_bytes_literal, walk_comprehension, walk_except_handler, walk_expr, - walk_keyword, walk_match_case, walk_module, walk_parameter, walk_parameters, walk_pattern, - walk_stmt, walk_string_literal, walk_type_param, walk_with_item, PreorderVisitor, -}; -use ruff_python_ast::AnyNodeRef; -use ruff_python_ast::{ - Alias, BoolOp, BytesLiteral, CmpOp, Comprehension, ExceptHandler, Expr, Keyword, MatchCase, - Mod, Operator, Parameter, Parameters, Pattern, Singleton, Stmt, StringLiteral, TypeParam, - UnaryOp, WithItem, -}; +use ruff_python_ast::visitor::preorder::{PreorderVisitor, TraversalSignal}; +use ruff_python_ast::{AnyNodeRef, BoolOp, CmpOp, Operator, Singleton, UnaryOp}; use ruff_python_parser::lexer::lex; use ruff_python_parser::{parse_tokens, Mode}; @@ -175,18 +166,6 @@ struct RecordVisitor { } impl RecordVisitor { - fn enter_node<'a, T>(&mut self, node: T) - where - T: Into>, - { - self.emit(&node.into().kind()); - self.depth += 1; - } - - fn exit_node(&mut self) { - self.depth -= 1; - } - fn emit(&mut self, text: &dyn Debug) { for _ in 0..self.depth { self.output.push_str(" "); @@ -196,29 +175,16 @@ impl RecordVisitor { } } -impl PreorderVisitor<'_> for RecordVisitor { - fn visit_mod(&mut self, module: &Mod) { - self.enter_node(module); - walk_module(self, module); - self.exit_node(); - } - - fn visit_stmt(&mut self, stmt: &Stmt) { - self.enter_node(stmt); - walk_stmt(self, stmt); - self.exit_node(); - } +impl<'a> PreorderVisitor<'a> for RecordVisitor { + fn enter_node(&mut self, node: AnyNodeRef<'a>) -> TraversalSignal { + self.emit(&node.kind()); + self.depth += 1; - fn visit_annotation(&mut self, expr: &Expr) { - self.enter_node(expr); - walk_expr(self, expr); - self.exit_node(); + TraversalSignal::Traverse } - fn visit_expr(&mut self, expr: &Expr) { - self.enter_node(expr); - walk_expr(self, expr); - self.exit_node(); + fn leave_node(&mut self, _node: AnyNodeRef<'a>) { + self.depth -= 1; } fn visit_singleton(&mut self, singleton: &Singleton) { @@ -240,82 +206,4 @@ impl PreorderVisitor<'_> for RecordVisitor { fn visit_cmp_op(&mut self, cmp_op: &CmpOp) { self.emit(&cmp_op); } - - fn visit_comprehension(&mut self, comprehension: &Comprehension) { - self.enter_node(comprehension); - walk_comprehension(self, comprehension); - self.exit_node(); - } - - fn visit_except_handler(&mut self, except_handler: &ExceptHandler) { - self.enter_node(except_handler); - walk_except_handler(self, except_handler); - self.exit_node(); - } - - fn visit_format_spec(&mut self, format_spec: &Expr) { - self.enter_node(format_spec); - walk_expr(self, format_spec); - self.exit_node(); - } - - fn visit_parameters(&mut self, parameters: &Parameters) { - self.enter_node(parameters); - walk_parameters(self, parameters); - self.exit_node(); - } - - fn visit_parameter(&mut self, parameter: &Parameter) { - self.enter_node(parameter); - walk_parameter(self, parameter); - self.exit_node(); - } - - fn visit_keyword(&mut self, keyword: &Keyword) { - self.enter_node(keyword); - walk_keyword(self, keyword); - self.exit_node(); - } - - fn visit_alias(&mut self, alias: &Alias) { - self.enter_node(alias); - walk_alias(self, alias); - self.exit_node(); - } - - fn visit_with_item(&mut self, with_item: &WithItem) { - self.enter_node(with_item); - walk_with_item(self, with_item); - self.exit_node(); - } - - fn visit_match_case(&mut self, match_case: &MatchCase) { - self.enter_node(match_case); - walk_match_case(self, match_case); - self.exit_node(); - } - - fn visit_pattern(&mut self, pattern: &Pattern) { - self.enter_node(pattern); - walk_pattern(self, pattern); - self.exit_node(); - } - - fn visit_type_param(&mut self, type_param: &TypeParam) { - self.enter_node(type_param); - walk_type_param(self, type_param); - self.exit_node(); - } - - fn visit_string_literal(&mut self, string_literal: &StringLiteral) { - self.enter_node(string_literal); - walk_string_literal(self, string_literal); - self.exit_node(); - } - - fn visit_bytes_literal(&mut self, bytes_literal: &BytesLiteral) { - self.enter_node(bytes_literal); - walk_bytes_literal(self, bytes_literal); - self.exit_node(); - } } diff --git a/crates/ruff_python_ast/tests/snapshots/preorder__class_type_parameters.snap b/crates/ruff_python_ast/tests/snapshots/preorder__class_type_parameters.snap index bf2a7eccb5fe4..20ef6b71fa442 100644 --- a/crates/ruff_python_ast/tests/snapshots/preorder__class_type_parameters.snap +++ b/crates/ruff_python_ast/tests/snapshots/preorder__class_type_parameters.snap @@ -4,11 +4,12 @@ expression: trace --- - ModModule - StmtClassDef - - TypeParamTypeVar - - ExprName - - TypeParamTypeVar - - TypeParamTypeVarTuple - - TypeParamParamSpec + - TypeParams + - TypeParamTypeVar + - ExprName + - TypeParamTypeVar + - TypeParamTypeVarTuple + - TypeParamParamSpec - StmtExpr - ExprEllipsisLiteral diff --git a/crates/ruff_python_ast/tests/snapshots/preorder__decorators.snap b/crates/ruff_python_ast/tests/snapshots/preorder__decorators.snap index ff57b138dec47..e91bd2e83b9bb 100644 --- a/crates/ruff_python_ast/tests/snapshots/preorder__decorators.snap +++ b/crates/ruff_python_ast/tests/snapshots/preorder__decorators.snap @@ -4,10 +4,12 @@ expression: trace --- - ModModule - StmtFunctionDef - - ExprName + - Decorator + - ExprName - Parameters - StmtPass - StmtClassDef - - ExprName + - Decorator + - ExprName - StmtPass diff --git a/crates/ruff_python_ast/tests/snapshots/preorder__f_strings.snap b/crates/ruff_python_ast/tests/snapshots/preorder__f_strings.snap index 426a155c787ec..613106d59e320 100644 --- a/crates/ruff_python_ast/tests/snapshots/preorder__f_strings.snap +++ b/crates/ruff_python_ast/tests/snapshots/preorder__f_strings.snap @@ -6,17 +6,20 @@ expression: trace - StmtExpr - ExprFString - StringLiteral - - ExprStringLiteral - - StringLiteral - - ExprFormattedValue - - ExprName - - ExprFString - - ExprStringLiteral - - StringLiteral - - ExprFormattedValue - - ExprName - - ExprStringLiteral - - StringLiteral - - ExprStringLiteral - - StringLiteral + - FString + - ExprStringLiteral + - StringLiteral + - ExprFormattedValue + - ExprName + - ExprFString + - ExprFString + - FString + - ExprStringLiteral + - StringLiteral + - ExprFormattedValue + - ExprName + - ExprStringLiteral + - StringLiteral + - ExprStringLiteral + - StringLiteral diff --git a/crates/ruff_python_ast/tests/snapshots/preorder__function_arguments.snap b/crates/ruff_python_ast/tests/snapshots/preorder__function_arguments.snap index 5ecec46ee04f9..da83fc10f8129 100644 --- a/crates/ruff_python_ast/tests/snapshots/preorder__function_arguments.snap +++ b/crates/ruff_python_ast/tests/snapshots/preorder__function_arguments.snap @@ -5,16 +5,22 @@ expression: trace - ModModule - StmtFunctionDef - Parameters - - Parameter - - Parameter - - Parameter - - Parameter - - ExprNumberLiteral - - Parameter - - Parameter - - ExprNumberLiteral - - Parameter - - ExprNumberLiteral + - ParameterWithDefault + - Parameter + - ParameterWithDefault + - Parameter + - ParameterWithDefault + - Parameter + - ParameterWithDefault + - Parameter + - ExprNumberLiteral + - Parameter + - ParameterWithDefault + - Parameter + - ExprNumberLiteral + - ParameterWithDefault + - Parameter + - ExprNumberLiteral - Parameter - StmtPass diff --git a/crates/ruff_python_ast/tests/snapshots/preorder__function_positional_only_with_default.snap b/crates/ruff_python_ast/tests/snapshots/preorder__function_positional_only_with_default.snap index fdc755b1f0270..6511aa3468297 100644 --- a/crates/ruff_python_ast/tests/snapshots/preorder__function_positional_only_with_default.snap +++ b/crates/ruff_python_ast/tests/snapshots/preorder__function_positional_only_with_default.snap @@ -5,11 +5,14 @@ expression: trace - ModModule - StmtFunctionDef - Parameters - - Parameter - - Parameter - - ExprNumberLiteral - - Parameter - - ExprNumberLiteral + - ParameterWithDefault + - Parameter + - ParameterWithDefault + - Parameter + - ExprNumberLiteral + - ParameterWithDefault + - Parameter + - ExprNumberLiteral - Parameter - StmtPass diff --git a/crates/ruff_python_ast/tests/snapshots/preorder__function_type_parameters.snap b/crates/ruff_python_ast/tests/snapshots/preorder__function_type_parameters.snap index 47aa1ecf6a7f5..11b98d0fa78e3 100644 --- a/crates/ruff_python_ast/tests/snapshots/preorder__function_type_parameters.snap +++ b/crates/ruff_python_ast/tests/snapshots/preorder__function_type_parameters.snap @@ -4,11 +4,12 @@ expression: trace --- - ModModule - StmtFunctionDef - - TypeParamTypeVar - - ExprName - - TypeParamTypeVar - - TypeParamTypeVarTuple - - TypeParamParamSpec + - TypeParams + - TypeParamTypeVar + - ExprName + - TypeParamTypeVar + - TypeParamTypeVarTuple + - TypeParamParamSpec - Parameters - StmtExpr - ExprEllipsisLiteral diff --git a/crates/ruff_python_ast/tests/snapshots/preorder__match_class_pattern.snap b/crates/ruff_python_ast/tests/snapshots/preorder__match_class_pattern.snap index da4fe2cd9750c..dbe56f11ff3bd 100644 --- a/crates/ruff_python_ast/tests/snapshots/preorder__match_class_pattern.snap +++ b/crates/ruff_python_ast/tests/snapshots/preorder__match_class_pattern.snap @@ -8,21 +8,26 @@ expression: trace - MatchCase - PatternMatchClass - ExprName - - PatternMatchValue - - ExprNumberLiteral - - PatternMatchValue - - ExprNumberLiteral + - PatternArguments + - PatternMatchValue + - ExprNumberLiteral + - PatternMatchValue + - ExprNumberLiteral - StmtExpr - ExprEllipsisLiteral - MatchCase - PatternMatchClass - ExprName - - PatternMatchValue - - ExprNumberLiteral - - PatternMatchValue - - ExprNumberLiteral - - PatternMatchValue - - ExprNumberLiteral + - PatternArguments + - PatternKeyword + - PatternMatchValue + - ExprNumberLiteral + - PatternKeyword + - PatternMatchValue + - ExprNumberLiteral + - PatternKeyword + - PatternMatchValue + - ExprNumberLiteral - StmtExpr - ExprEllipsisLiteral diff --git a/crates/ruff_python_ast/tests/snapshots/preorder__type_aliases.snap b/crates/ruff_python_ast/tests/snapshots/preorder__type_aliases.snap index 56c170d9b8558..56d6aec5c0dec 100644 --- a/crates/ruff_python_ast/tests/snapshots/preorder__type_aliases.snap +++ b/crates/ruff_python_ast/tests/snapshots/preorder__type_aliases.snap @@ -5,11 +5,12 @@ expression: trace - ModModule - StmtTypeAlias - ExprName - - TypeParamTypeVar - - ExprName - - TypeParamTypeVar - - TypeParamTypeVarTuple - - TypeParamParamSpec + - TypeParams + - TypeParamTypeVar + - ExprName + - TypeParamTypeVar + - TypeParamTypeVarTuple + - TypeParamParamSpec - ExprSubscript - ExprName - ExprName From b9186479276b3e64492ebae31ce6ebd60c63cde6 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 6 Dec 2023 12:05:34 -0500 Subject: [PATCH 124/197] Avoid removing parentheses on ctypes.WinError (#9027) Re-resolves https://github.com/astral-sh/ruff/issues/6730. --- .../resources/test/fixtures/flake8_raise/RSE102.py | 11 +++++++++++ .../rules/unnecessary_paren_on_raise_exception.rs | 4 +--- ...nnecessary-paren-on-raise-exception_RSE102.py.snap | 5 +++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_raise/RSE102.py b/crates/ruff_linter/resources/test/fixtures/flake8_raise/RSE102.py index 0a750b97cb190..bba0e98b17caf 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_raise/RSE102.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_raise/RSE102.py @@ -82,3 +82,14 @@ def error(): # RSE102 raise Foo() + +# OK +raise ctypes.WinError() + + +def func(): + pass + + +# OK +raise func() diff --git a/crates/ruff_linter/src/rules/flake8_raise/rules/unnecessary_paren_on_raise_exception.rs b/crates/ruff_linter/src/rules/flake8_raise/rules/unnecessary_paren_on_raise_exception.rs index 4a0bffc74bc7d..a056bbc755f8d 100644 --- a/crates/ruff_linter/src/rules/flake8_raise/rules/unnecessary_paren_on_raise_exception.rs +++ b/crates/ruff_linter/src/rules/flake8_raise/rules/unnecessary_paren_on_raise_exception.rs @@ -78,9 +78,7 @@ pub(crate) fn unnecessary_paren_on_raise_exception(checker: &mut Checker, expr: // `ctypes.WinError()` is a function, not a class. It's part of the standard library, so // we might as well get it right. - if exception_type - .as_ref() - .is_some_and(ExceptionType::is_builtin) + if exception_type.is_none() && checker .semantic() .resolve_call_path(func) diff --git a/crates/ruff_linter/src/rules/flake8_raise/snapshots/ruff_linter__rules__flake8_raise__tests__unnecessary-paren-on-raise-exception_RSE102.py.snap b/crates/ruff_linter/src/rules/flake8_raise/snapshots/ruff_linter__rules__flake8_raise__tests__unnecessary-paren-on-raise-exception_RSE102.py.snap index 37b632cc2563b..d1d89829c673f 100644 --- a/crates/ruff_linter/src/rules/flake8_raise/snapshots/ruff_linter__rules__flake8_raise__tests__unnecessary-paren-on-raise-exception_RSE102.py.snap +++ b/crates/ruff_linter/src/rules/flake8_raise/snapshots/ruff_linter__rules__flake8_raise__tests__unnecessary-paren-on-raise-exception_RSE102.py.snap @@ -266,6 +266,8 @@ RSE102.py:84:10: RSE102 [*] Unnecessary parentheses on raised exception 83 | # RSE102 84 | raise Foo() | ^^ RSE102 +85 | +86 | # OK | = help: Remove unnecessary parentheses @@ -275,5 +277,8 @@ RSE102.py:84:10: RSE102 [*] Unnecessary parentheses on raised exception 83 83 | # RSE102 84 |-raise Foo() 84 |+raise Foo +85 85 | +86 86 | # OK +87 87 | raise ctypes.WinError() From af88ffc57e8aad1135e48cebaa333a0fa88fa5e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20S=C3=BAkup?= Date: Wed, 6 Dec 2023 18:07:59 +0100 Subject: [PATCH 125/197] Add openSUSE Tumbleweed into install doc (#8996) --- docs/installation.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/installation.md b/docs/installation.md index e0a1e882e93f9..a5ef50f35018a 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -48,6 +48,12 @@ on the testing repositories: apk add ruff ``` +For **openSUSE Tumbleweed** users, Ruff is also available in the distribution repository: + +```shell +sudo zypper install python3-ruff +``` + On **Docker**, it is published as `ghcr.io/astral-sh/ruff`, tagged for each release and `latest` for the latest release. From f484df54700a5b613994e89a69f34758f8405a13 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 6 Dec 2023 21:33:38 -0500 Subject: [PATCH 126/197] Document use of math.isnan for self-comparisons (#9033) Closes https://github.com/astral-sh/ruff/issues/8833. --- .../src/rules/pylint/rules/comparison_with_itself.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/ruff_linter/src/rules/pylint/rules/comparison_with_itself.rs b/crates/ruff_linter/src/rules/pylint/rules/comparison_with_itself.rs index ce02b12fff433..8aa58e70e8026 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/comparison_with_itself.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/comparison_with_itself.rs @@ -21,6 +21,14 @@ use crate::rules::pylint::helpers::CmpOpExt; /// foo == foo /// ``` /// +/// In some cases, self-comparisons are used to determine whether a float is +/// NaN. Instead, prefer `math.isnan`: +/// ```python +/// import math +/// +/// math.isnan(foo) +/// ``` +/// /// ## References /// - [Python documentation: Comparisons](https://docs.python.org/3/reference/expressions.html#comparisons) #[violation] From 9361e22fe919f5ddc70dfd7ad35c24e0b89166f5 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Wed, 6 Dec 2023 20:47:36 -0600 Subject: [PATCH 127/197] Avoid `ANN2xx` autofix for abstract methods with empty body (#9034) ## Summary This PR updates the `ANN201`, `ANN202`, `ANN205`, and `ANN206` rules to not create a fix for the return type when it's an abstract method and the function body is empty i.e., it only contains either a pass statement, docstring or an ellipsis literal. fixes: #9004 ## Test Plan Add the following test cases: - Abstract method with pass statement - Abstract method with docstring - Abstract method with ellipsis literal - Abstract method with possible return type --- .../flake8_annotations/auto_return_type.py | 35 +++++ .../flake8_annotations/rules/definition.rs | 127 ++++++++++++------ ..._annotations__tests__auto_return_type.snap | 68 ++++++++++ ...tations__tests__auto_return_type_py38.snap | 68 ++++++++++ 4 files changed, 254 insertions(+), 44 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py b/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py index ab75a50da712c..60d89cbec5cdc 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_annotations/auto_return_type.py @@ -147,3 +147,38 @@ def func(x: int): while x > 0: break return 1 + + +import abc +from abc import abstractmethod + + +class Foo(abc.ABC): + @abstractmethod + def method(self): + pass + + @abc.abstractmethod + def method(self): + """Docstring.""" + + @abc.abstractmethod + def method(self): + ... + + @staticmethod + @abstractmethod + def method(): + pass + + @classmethod + @abstractmethod + def method(cls): + pass + + @abstractmethod + def method(self): + if self.x > 0: + return 1 + else: + return 1.5 diff --git a/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs b/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs index 9360d0dfdd258..dee00d6667831 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs +++ b/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs @@ -537,6 +537,19 @@ fn check_dynamically_typed( } } +fn is_empty_body(body: &[Stmt]) -> bool { + body.iter().all(|stmt| match stmt { + Stmt::Pass(_) => true, + Stmt::Expr(ast::StmtExpr { value, range: _ }) => { + matches!( + value.as_ref(), + Expr::StringLiteral(_) | Expr::EllipsisLiteral(_) + ) + } + _ => false, + }) +} + /// Generate flake8-annotation checks for a given `Definition`. pub(crate) fn definition( checker: &Checker, @@ -725,16 +738,22 @@ pub(crate) fn definition( ) { if is_method && visibility::is_classmethod(decorator_list, checker.semantic()) { if checker.enabled(Rule::MissingReturnTypeClassMethod) { - let return_type = auto_return_type(function) - .and_then(|return_type| { - return_type.into_expression( - checker.importer(), - function.parameters.start(), - checker.semantic(), - checker.settings.target_version, - ) - }) - .map(|(return_type, edits)| (checker.generator().expr(&return_type), edits)); + let return_type = if visibility::is_abstract(decorator_list, checker.semantic()) + && is_empty_body(body) + { + None + } else { + auto_return_type(function) + .and_then(|return_type| { + return_type.into_expression( + checker.importer(), + function.parameters.start(), + checker.semantic(), + checker.settings.target_version, + ) + }) + .map(|(return_type, edits)| (checker.generator().expr(&return_type), edits)) + }; let mut diagnostic = Diagnostic::new( MissingReturnTypeClassMethod { name: name.to_string(), @@ -752,16 +771,22 @@ pub(crate) fn definition( } } else if is_method && visibility::is_staticmethod(decorator_list, checker.semantic()) { if checker.enabled(Rule::MissingReturnTypeStaticMethod) { - let return_type = auto_return_type(function) - .and_then(|return_type| { - return_type.into_expression( - checker.importer(), - function.parameters.start(), - checker.semantic(), - checker.settings.target_version, - ) - }) - .map(|(return_type, edits)| (checker.generator().expr(&return_type), edits)); + let return_type = if visibility::is_abstract(decorator_list, checker.semantic()) + && is_empty_body(body) + { + None + } else { + auto_return_type(function) + .and_then(|return_type| { + return_type.into_expression( + checker.importer(), + function.parameters.start(), + checker.semantic(), + checker.settings.target_version, + ) + }) + .map(|(return_type, edits)| (checker.generator().expr(&return_type), edits)) + }; let mut diagnostic = Diagnostic::new( MissingReturnTypeStaticMethod { name: name.to_string(), @@ -818,18 +843,25 @@ pub(crate) fn definition( match visibility { visibility::Visibility::Public => { if checker.enabled(Rule::MissingReturnTypeUndocumentedPublicFunction) { - let return_type = auto_return_type(function) - .and_then(|return_type| { - return_type.into_expression( - checker.importer(), - function.parameters.start(), - checker.semantic(), - checker.settings.target_version, - ) - }) - .map(|(return_type, edits)| { - (checker.generator().expr(&return_type), edits) - }); + let return_type = + if visibility::is_abstract(decorator_list, checker.semantic()) + && is_empty_body(body) + { + None + } else { + auto_return_type(function) + .and_then(|return_type| { + return_type.into_expression( + checker.importer(), + function.parameters.start(), + checker.semantic(), + checker.settings.target_version, + ) + }) + .map(|(return_type, edits)| { + (checker.generator().expr(&return_type), edits) + }) + }; let mut diagnostic = Diagnostic::new( MissingReturnTypeUndocumentedPublicFunction { name: name.to_string(), @@ -853,18 +885,25 @@ pub(crate) fn definition( } visibility::Visibility::Private => { if checker.enabled(Rule::MissingReturnTypePrivateFunction) { - let return_type = auto_return_type(function) - .and_then(|return_type| { - return_type.into_expression( - checker.importer(), - function.parameters.start(), - checker.semantic(), - checker.settings.target_version, - ) - }) - .map(|(return_type, edits)| { - (checker.generator().expr(&return_type), edits) - }); + let return_type = + if visibility::is_abstract(decorator_list, checker.semantic()) + && is_empty_body(body) + { + None + } else { + auto_return_type(function) + .and_then(|return_type| { + return_type.into_expression( + checker.importer(), + function.parameters.start(), + checker.semantic(), + checker.settings.target_version, + ) + }) + .map(|(return_type, edits)| { + (checker.generator().expr(&return_type), edits) + }) + }; let mut diagnostic = Diagnostic::new( MissingReturnTypePrivateFunction { name: name.to_string(), diff --git a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap index 6fcbb95d029f6..72b8e8b9a66cc 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap +++ b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type.snap @@ -427,4 +427,72 @@ auto_return_type.py:146:5: ANN201 [*] Missing return type annotation for public 148 148 | break 149 149 | return 1 +auto_return_type.py:158:9: ANN201 Missing return type annotation for public function `method` + | +156 | class Foo(abc.ABC): +157 | @abstractmethod +158 | def method(self): + | ^^^^^^ ANN201 +159 | pass + | + = help: Add return type annotation + +auto_return_type.py:162:9: ANN201 Missing return type annotation for public function `method` + | +161 | @abc.abstractmethod +162 | def method(self): + | ^^^^^^ ANN201 +163 | """Docstring.""" + | + = help: Add return type annotation + +auto_return_type.py:166:9: ANN201 Missing return type annotation for public function `method` + | +165 | @abc.abstractmethod +166 | def method(self): + | ^^^^^^ ANN201 +167 | ... + | + = help: Add return type annotation + +auto_return_type.py:171:9: ANN205 Missing return type annotation for staticmethod `method` + | +169 | @staticmethod +170 | @abstractmethod +171 | def method(): + | ^^^^^^ ANN205 +172 | pass + | + = help: Add return type annotation + +auto_return_type.py:176:9: ANN206 Missing return type annotation for classmethod `method` + | +174 | @classmethod +175 | @abstractmethod +176 | def method(cls): + | ^^^^^^ ANN206 +177 | pass + | + = help: Add return type annotation + +auto_return_type.py:180:9: ANN201 [*] Missing return type annotation for public function `method` + | +179 | @abstractmethod +180 | def method(self): + | ^^^^^^ ANN201 +181 | if self.x > 0: +182 | return 1 + | + = help: Add return type annotation: `float` + +ℹ Unsafe fix +177 177 | pass +178 178 | +179 179 | @abstractmethod +180 |- def method(self): + 180 |+ def method(self) -> float: +181 181 | if self.x > 0: +182 182 | return 1 +183 183 | else: + diff --git a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type_py38.snap b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type_py38.snap index d91484ca3fe71..7667c2299de9e 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type_py38.snap +++ b/crates/ruff_linter/src/rules/flake8_annotations/snapshots/ruff_linter__rules__flake8_annotations__tests__auto_return_type_py38.snap @@ -482,4 +482,72 @@ auto_return_type.py:146:5: ANN201 [*] Missing return type annotation for public 148 149 | break 149 150 | return 1 +auto_return_type.py:158:9: ANN201 Missing return type annotation for public function `method` + | +156 | class Foo(abc.ABC): +157 | @abstractmethod +158 | def method(self): + | ^^^^^^ ANN201 +159 | pass + | + = help: Add return type annotation + +auto_return_type.py:162:9: ANN201 Missing return type annotation for public function `method` + | +161 | @abc.abstractmethod +162 | def method(self): + | ^^^^^^ ANN201 +163 | """Docstring.""" + | + = help: Add return type annotation + +auto_return_type.py:166:9: ANN201 Missing return type annotation for public function `method` + | +165 | @abc.abstractmethod +166 | def method(self): + | ^^^^^^ ANN201 +167 | ... + | + = help: Add return type annotation + +auto_return_type.py:171:9: ANN205 Missing return type annotation for staticmethod `method` + | +169 | @staticmethod +170 | @abstractmethod +171 | def method(): + | ^^^^^^ ANN205 +172 | pass + | + = help: Add return type annotation + +auto_return_type.py:176:9: ANN206 Missing return type annotation for classmethod `method` + | +174 | @classmethod +175 | @abstractmethod +176 | def method(cls): + | ^^^^^^ ANN206 +177 | pass + | + = help: Add return type annotation + +auto_return_type.py:180:9: ANN201 [*] Missing return type annotation for public function `method` + | +179 | @abstractmethod +180 | def method(self): + | ^^^^^^ ANN201 +181 | if self.x > 0: +182 | return 1 + | + = help: Add return type annotation: `float` + +ℹ Unsafe fix +177 177 | pass +178 178 | +179 179 | @abstractmethod +180 |- def method(self): + 180 |+ def method(self) -> float: +181 181 | if self.x > 0: +182 182 | return 1 +183 183 | else: + From bbb0a0c3600f629533a19405ffd526776ab2f946 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 6 Dec 2023 22:05:56 -0500 Subject: [PATCH 128/197] Ignore underscore references in type annotations (#9036) ## Summary Occasionally, valid code needs to use `argparse._SubParsersAction` in a type annotation. This isn't great, but it's indicative of the fact that public interfaces can return private types. If you accessed that private type via a private interface, then we should be flagging the call site, rather than the annotation. Closes https://github.com/astral-sh/ruff/issues/9013. --- .../src/rules/flake8_self/rules/private_member_access.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/ruff_linter/src/rules/flake8_self/rules/private_member_access.rs b/crates/ruff_linter/src/rules/flake8_self/rules/private_member_access.rs index 543c4d36d7348..fdbf3e8def12b 100644 --- a/crates/ruff_linter/src/rules/flake8_self/rules/private_member_access.rs +++ b/crates/ruff_linter/src/rules/flake8_self/rules/private_member_access.rs @@ -66,6 +66,10 @@ pub(crate) fn private_member_access(checker: &mut Checker, expr: &Expr) { return; }; + if checker.semantic().in_annotation() { + return; + } + if (attr.starts_with("__") && !attr.ends_with("__")) || (attr.starts_with('_') && !attr.starts_with("__")) { From 06c9f625b69425396021ec98a08a1bc862627b37 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Wed, 6 Dec 2023 21:14:58 -0600 Subject: [PATCH 129/197] Fix detection of changed files in CI (#9035) These were literals instead of expressions... and were consequently not evaluated. Fixes bug from #8225 --- .github/workflows/ci.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 749caccb064c0..3cee20113daaf 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -86,7 +86,7 @@ jobs: name: "cargo clippy" runs-on: ubuntu-latest needs: determine_changes - if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' + if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }} steps: - uses: actions/checkout@v4 - name: "Install Rust toolchain" @@ -102,7 +102,7 @@ jobs: cargo-test-linux: runs-on: ubuntu-latest needs: determine_changes - if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' + if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }} name: "cargo test (linux)" steps: - uses: actions/checkout@v4 @@ -128,7 +128,7 @@ jobs: cargo-test-windows: runs-on: windows-latest needs: determine_changes - if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' + if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }} name: "cargo test (windows)" steps: - uses: actions/checkout@v4 @@ -147,7 +147,7 @@ jobs: cargo-test-wasm: runs-on: ubuntu-latest needs: determine_changes - if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' + if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }} name: "cargo test (wasm)" steps: - uses: actions/checkout@v4 @@ -168,7 +168,7 @@ jobs: cargo-fuzz: runs-on: ubuntu-latest needs: determine_changes - if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' + if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }} name: "cargo fuzz" steps: - uses: actions/checkout@v4 @@ -187,7 +187,7 @@ jobs: name: "test scripts" runs-on: ubuntu-latest needs: determine_changes - if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' + if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }} steps: - uses: actions/checkout@v4 - name: "Install Rust toolchain" @@ -321,7 +321,7 @@ jobs: name: "cargo udeps" runs-on: ubuntu-latest needs: determine_changes - if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' + if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }} steps: - uses: actions/checkout@v4 - name: "Install nightly Rust toolchain" @@ -444,7 +444,7 @@ jobs: needs: - cargo-test-linux - determine_changes - if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' + if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }} steps: - uses: extractions/setup-just@v1 env: @@ -483,7 +483,7 @@ jobs: benchmarks: runs-on: ubuntu-latest needs: determine_changes - if: needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' + if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }} steps: - name: "Checkout Branch" uses: actions/checkout@v4 From acab5f3cf2d0d5347bbfb0fd33e1f8fdd55bf87a Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 6 Dec 2023 22:43:21 -0500 Subject: [PATCH 130/197] Enable `printf-string-formatting` fix with comments on right-hand side (#9037) ## Summary This was added in https://github.com/astral-sh/ruff/pull/6364 (as a follow-on to https://github.com/astral-sh/ruff/pull/6342), but I don't think it applies in the same way, because we don't _remove_ the right-hand side when converting from `%`-style formatting to `.format` calls. Closes https://github.com/astral-sh/ruff/issues/8107. --- .../test/fixtures/pyupgrade/UP031_0.py | 7 ++++ .../rules/printf_string_formatting.rs | 16 +++------ ...__rules__pyupgrade__tests__UP031_0.py.snap | 34 ++++++++++++++++++- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP031_0.py b/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP031_0.py index 9544e11c4c632..00fef079b6e30 100644 --- a/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP031_0.py +++ b/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP031_0.py @@ -110,3 +110,10 @@ "%s" % ( x, # comment ) + + +path = "%s-%s-%s.pem" % ( + safe_domain_name(cn), # common name, which should be filename safe because it is IDNA-encoded, but in case of a malformed cert make sure it's ok to use as a filename + cert.not_valid_after.date().isoformat().replace("-", ""), # expiration date + hexlify(cert.fingerprint(hashes.SHA256())).decode("ascii")[0:8], # fingerprint prefix +) diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs index 576b0dacbcf91..4a340e3369699 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/printf_string_formatting.rs @@ -490,18 +490,10 @@ pub(crate) fn printf_string_formatting(checker: &mut Checker, expr: &Expr, right contents.push_str(&format!(".format{params_string}")); let mut diagnostic = Diagnostic::new(PrintfStringFormatting, expr.range()); - // Avoid fix if there are comments within the right-hand side: - // ``` - // "%s" % ( - // 0, # 0 - // ) - // ``` - if !checker.indexer().comment_ranges().intersects(right.range()) { - diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( - contents, - expr.range(), - ))); - } + diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( + contents, + expr.range(), + ))); checker.diagnostics.push(diagnostic); } diff --git a/crates/ruff_linter/src/rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP031_0.py.snap b/crates/ruff_linter/src/rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP031_0.py.snap index a06ca5060c82b..fd5827fcfa413 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP031_0.py.snap +++ b/crates/ruff_linter/src/rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP031_0.py.snap @@ -896,7 +896,7 @@ UP031_0.py:104:5: UP031 [*] Use format specifiers instead of percent format 109 108 | 110 109 | "%s" % ( -UP031_0.py:110:1: UP031 Use format specifiers instead of percent format +UP031_0.py:110:1: UP031 [*] Use format specifiers instead of percent format | 108 | ) 109 | @@ -907,4 +907,36 @@ UP031_0.py:110:1: UP031 Use format specifiers instead of percent format | = help: Replace with format specifiers +ℹ Unsafe fix +107 107 | % (x,) +108 108 | ) +109 109 | +110 |-"%s" % ( + 110 |+"{}".format( +111 111 | x, # comment +112 112 | ) +113 113 | + +UP031_0.py:115:8: UP031 [*] Use format specifiers instead of percent format + | +115 | path = "%s-%s-%s.pem" % ( + | ________^ +116 | | safe_domain_name(cn), # common name, which should be filename safe because it is IDNA-encoded, but in case of a malformed cert make sure it's ok to use as a filename +117 | | cert.not_valid_after.date().isoformat().replace("-", ""), # expiration date +118 | | hexlify(cert.fingerprint(hashes.SHA256())).decode("ascii")[0:8], # fingerprint prefix +119 | | ) + | |_^ UP031 + | + = help: Replace with format specifiers + +ℹ Unsafe fix +112 112 | ) +113 113 | +114 114 | +115 |-path = "%s-%s-%s.pem" % ( + 115 |+path = "{}-{}-{}.pem".format( +116 116 | safe_domain_name(cn), # common name, which should be filename safe because it is IDNA-encoded, but in case of a malformed cert make sure it's ok to use as a filename +117 117 | cert.not_valid_after.date().isoformat().replace("-", ""), # expiration date +118 118 | hexlify(cert.fingerprint(hashes.SHA256())).decode("ascii")[0:8], # fingerprint prefix + From d22ce5372d845f095833ba3dbf4dc803794b454f Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Wed, 6 Dec 2023 21:55:12 -0600 Subject: [PATCH 131/197] Fix determine changes detection of "code" changes (#9038) Replaces https://github.com/astral-sh/ruff/pull/9035 Fixes https://github.com/astral-sh/ruff/pull/8225 The issue appears to be that `*/**` was used instead of `**/*` which did not match _any_ changed file as desired --- .github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3cee20113daaf..4ab9aec9000e8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -48,8 +48,8 @@ jobs: - "!crates/ruff_dev/**" - "!crates/ruff_shrinking/**" - scripts/* - - .github/workflows/ci.yaml - python/** + - .github/workflows/ci.yaml formatter: - Cargo.toml @@ -68,7 +68,7 @@ jobs: - .github/workflows/ci.yaml code: - - "*/**" + - "**/*" - "!**/*.md" - "!docs/**" - "!assets/**" From 946b308197c38726e35e9e54784b2018b0155cdb Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 6 Dec 2023 22:56:23 -0500 Subject: [PATCH 132/197] Ensure that from-style imports are always ordered first in `__future__` (#9039) Closes https://github.com/astral-sh/ruff/issues/8823. --- .../force_sort_within_sections_future.py | 2 ++ .../test/fixtures/isort/future_from.py | 2 ++ crates/ruff_linter/src/rules/isort/mod.rs | 4 ++- crates/ruff_linter/src/rules/isort/order.rs | 32 ++++++++++++++++++- ..._force_sort_within_sections_future.py.snap | 16 ++++++++++ ...__rules__isort__tests__future_from.py.snap | 16 ++++++++++ 6 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/isort/force_sort_within_sections_future.py create mode 100644 crates/ruff_linter/resources/test/fixtures/isort/future_from.py create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__force_sort_within_sections_force_sort_within_sections_future.py.snap create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__future_from.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/isort/force_sort_within_sections_future.py b/crates/ruff_linter/resources/test/fixtures/isort/force_sort_within_sections_future.py new file mode 100644 index 0000000000000..3698d72a9c55e --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/isort/force_sort_within_sections_future.py @@ -0,0 +1,2 @@ +import __future__ +from __future__ import annotations diff --git a/crates/ruff_linter/resources/test/fixtures/isort/future_from.py b/crates/ruff_linter/resources/test/fixtures/isort/future_from.py new file mode 100644 index 0000000000000..3698d72a9c55e --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/isort/future_from.py @@ -0,0 +1,2 @@ +import __future__ +from __future__ import annotations diff --git a/crates/ruff_linter/src/rules/isort/mod.rs b/crates/ruff_linter/src/rules/isort/mod.rs index 60b511847c909..0cb8655c13cd6 100644 --- a/crates/ruff_linter/src/rules/isort/mod.rs +++ b/crates/ruff_linter/src/rules/isort/mod.rs @@ -180,7 +180,7 @@ fn format_import_block( continue; }; - let imports = order_imports(import_block, settings); + let imports = order_imports(import_block, import_section, settings); // Add a blank line between every section. if is_first_block { @@ -291,6 +291,7 @@ mod tests { #[test_case(Path::new("force_sort_within_sections.py"))] #[test_case(Path::new("force_to_top.py"))] #[test_case(Path::new("force_wrap_aliases.py"))] + #[test_case(Path::new("future_from.py"))] #[test_case(Path::new("if_elif_else.py"))] #[test_case(Path::new("import_from_after_import.py"))] #[test_case(Path::new("inline_comments.py"))] @@ -701,6 +702,7 @@ mod tests { #[test_case(Path::new("force_sort_within_sections.py"))] #[test_case(Path::new("force_sort_within_sections_with_as_names.py"))] + #[test_case(Path::new("force_sort_within_sections_future.py"))] fn force_sort_within_sections(path: &Path) -> Result<()> { let snapshot = format!("force_sort_within_sections_{}", path.to_string_lossy()); let mut diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/isort/order.rs b/crates/ruff_linter/src/rules/isort/order.rs index 25430b84ad6f9..7f1f6f97fccb3 100644 --- a/crates/ruff_linter/src/rules/isort/order.rs +++ b/crates/ruff_linter/src/rules/isort/order.rs @@ -1,4 +1,5 @@ use crate::rules::isort::sorting::ImportStyle; +use crate::rules::isort::{ImportSection, ImportType}; use itertools::Itertools; use super::settings::Settings; @@ -8,6 +9,7 @@ use super::types::{AliasData, CommentSet, ImportBlock, ImportFromStatement}; pub(crate) fn order_imports<'a>( block: ImportBlock<'a>, + section: &ImportSection, settings: &Settings, ) -> Vec> { let straight_imports = block.import.into_iter(); @@ -52,7 +54,35 @@ pub(crate) fn order_imports<'a>( }, ); - let ordered_imports = if settings.force_sort_within_sections { + let ordered_imports = if matches!(section, ImportSection::Known(ImportType::Future)) { + from_imports + .sorted_by_cached_key(|(import_from, _, _, aliases)| { + ModuleKey::from_module( + import_from.module, + None, + import_from.level, + aliases.first().map(|(alias, _)| (alias.name, alias.asname)), + ImportStyle::From, + settings, + ) + }) + .map(ImportFrom) + .chain( + straight_imports + .sorted_by_cached_key(|(alias, _)| { + ModuleKey::from_module( + Some(alias.name), + alias.asname, + None, + None, + ImportStyle::Straight, + settings, + ) + }) + .map(Import), + ) + .collect() + } else if settings.force_sort_within_sections { straight_imports .map(Import) .chain(from_imports.map(ImportFrom)) diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__force_sort_within_sections_force_sort_within_sections_future.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__force_sort_within_sections_force_sort_within_sections_future.py.snap new file mode 100644 index 0000000000000..6864d488b75ed --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__force_sort_within_sections_force_sort_within_sections_future.py.snap @@ -0,0 +1,16 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- +force_sort_within_sections_future.py:1:1: I001 [*] Import block is un-sorted or un-formatted + | +1 | / import __future__ +2 | | from __future__ import annotations + | + = help: Organize imports + +ℹ Safe fix + 1 |+from __future__ import annotations +1 2 | import __future__ +2 |-from __future__ import annotations + + diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__future_from.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__future_from.py.snap new file mode 100644 index 0000000000000..f3f5cd2a3574d --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__future_from.py.snap @@ -0,0 +1,16 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- +future_from.py:1:1: I001 [*] Import block is un-sorted or un-formatted + | +1 | / import __future__ +2 | | from __future__ import annotations + | + = help: Organize imports + +ℹ Safe fix + 1 |+from __future__ import annotations +1 2 | import __future__ +2 |-from __future__ import annotations + + From 981a0703ed03de805d78826a40026a23983fa419 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Thu, 7 Dec 2023 13:41:00 +0900 Subject: [PATCH 133/197] Use double quotes for all docstrings, including single-quoted docstrings (#9020) --- .../test/fixtures/ruff/docstring.options.json | 3 + .../resources/test/fixtures/ruff/docstring.py | 5 + .../src/expression/string/mod.rs | 7 +- .../tests/snapshots/format@docstring.py.snap | 198 ++++++++++++++++++ 4 files changed, 209 insertions(+), 4 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring.options.json b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring.options.json index 28553e727b70f..e1a76386a0556 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring.options.json @@ -14,5 +14,8 @@ { "indent_style": "tab", "indent_width": 4 + }, + { + "quote_style": "single" } ] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring.py index d7d4d9b119b17..98a5a730f44f6 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring.py @@ -150,3 +150,8 @@ def tabbed_indent(self): Normal indented line - autor """ + + +def single_quoted(): + ' content\ ' + return diff --git a/crates/ruff_python_formatter/src/expression/string/mod.rs b/crates/ruff_python_formatter/src/expression/string/mod.rs index 5a7a6a1b4677b..c7e896daf2c90 100644 --- a/crates/ruff_python_formatter/src/expression/string/mod.rs +++ b/crates/ruff_python_formatter/src/expression/string/mod.rs @@ -213,7 +213,8 @@ impl<'a> Format> for FormatString<'a> { let normalized = string_part.normalize( Quoting::CanChange, &locator, - f.options().quote_style(), + // Per PEP 8 and PEP 257, always prefer double quotes for docstrings + QuoteStyle::Double, parent_docstring_quote_style, ); docstring::format(&normalized, f) @@ -323,9 +324,7 @@ impl StringPart { configured_style: QuoteStyle, parent_docstring_quote_style: Option, ) -> NormalizedString<'a> { - // Per PEP 8 and PEP 257, always prefer double quotes for docstrings - // and triple-quoted strings. (We assume docstrings are always - // triple-quoted.) + // Per PEP 8, always prefer double quotes for triple-quoted strings. let preferred_style = if self.quotes.triple { // ... unless we're formatting a code snippet inside a docstring, // then we specifically want to invert our quote style to avoid diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap index bac8a446b18a1..84e737e97a6c6 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap @@ -156,6 +156,11 @@ class TabbedIndent: Normal indented line - autor """ + + +def single_quoted(): + ' content\ ' + return ``` ## Outputs @@ -324,6 +329,11 @@ class TabbedIndent: Normal indented line - autor """ + + +def single_quoted(): + "content\ " + return ``` @@ -492,6 +502,11 @@ class TabbedIndent: Normal indented line - autor """ + + +def single_quoted(): + "content\ " + return ``` @@ -660,6 +675,11 @@ class TabbedIndent: Normal indented line - autor """ + + +def single_quoted(): + "content\ " + return ``` @@ -828,6 +848,184 @@ class TabbedIndent: Normal indented line - autor """ + + +def single_quoted(): + "content\ " + return +``` + + +### Output 5 +``` +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Single +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +preview = Disabled +``` + +```python +def single_line_backslashes1(): + """content\ """ + return + + +def single_line_backslashes2(): + """content\\""" + return + + +def single_line_backslashes3(): + """content\\\ """ + return + + +def multiline_backslashes1(): + """This is a docstring with + some lines of text\ """ + return + + +def multiline_backslashes2(): + """This is a docstring with + some lines of text\\""" + return + + +def multiline_backslashes3(): + """This is a docstring with + some lines of text\\\ """ + return + + +def multiple_negatively_indented_docstring_lines(): + """a + b + c + d + e + """ + + +def overindentend_docstring(): + """a + over-indented + """ + + +def comment_before_docstring(): + # don't lose this function comment ... + """Does nothing. + + But it has comments + """ # ... neither lose this function comment + + +class CommentBeforeDocstring: + # don't lose this class comment ... + """Empty class. + + But it has comments + """ # ... neither lose this class comment + + +class IndentMeSome: + def doc_string_without_linebreak_after_colon(self): + """This is somewhat strange + a + b + We format this a is the docstring had started properly indented on the next + line if the target indentation. This may we incorrect since source and target + indentation can be incorrect, but this is also an edge case. + """ + + +class IgnoreImplicitlyConcatenatedStrings: + """""" '' + + +def docstring_that_ends_with_quote_and_a_line_break1(): + """ + he said "the news of my death have been greatly exaggerated" + """ + + +def docstring_that_ends_with_quote_and_a_line_break2(): + """he said "the news of my death have been greatly exaggerated" """ + + +def docstring_that_ends_with_quote_and_a_line_break3(): + """he said "the news of my death have been greatly exaggerated" """ + + +class ByteDocstring: + b""" has leading whitespace""" + first_statement = 1 + + +class CommentAfterDocstring1: + """Browse module classes and functions in IDLE.""" + + # This class is also the base class for pathbrowser.PathBrowser. + + def __init__(self): + pass + + +class CommentAfterDocstring2: + """Browse module classes and functions in IDLE.""" + + # This class is also the base class for pathbrowser.PathBrowser. + + def __init__(self): + pass + + +class CommentAfterDocstring3: + """Browse module classes and functions in IDLE.""" + + # This class is also the base class for pathbrowser.PathBrowser. + def __init__(self): + pass + + +class CommentAfterDocstring4: + """Browse module classes and functions in IDLE.""" + + # This class is also the base class for pathbrowser.PathBrowser. + def __init__(self): + pass + + +class CommentAfterDocstring5: + """Browse module classes and functions in IDLE.""" + + # This class is also the base class for pathbrowser.PathBrowser. + + +def f(): + """Browse module classes and functions in IDLE.""" + # ^ Do not insert a newline above here + + pass + + +class TabbedIndent: + def tabbed_indent(self): + """check for correct tabbed formatting + ^^^^^^^^^^ + Normal indented line + - autor + """ + + +def single_quoted(): + "content\ " + return ``` From ebc7ac31cb41482461486906d74d96b33fb56166 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 6 Dec 2023 23:56:14 -0500 Subject: [PATCH 134/197] Avoid invalid combination of `force-sort-within-types` and `lines-between-types` (#9041) Closes https://github.com/astral-sh/ruff/issues/8792. --- ...orce_sort_within_sections_lines_between.py | 4 ++++ crates/ruff_linter/src/rules/isort/mod.rs | 22 +++++++++++++++++++ ...sort_within_sections_lines_between.py.snap | 4 ++++ crates/ruff_workspace/src/options.rs | 11 ++++++++-- 4 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/isort/force_sort_within_sections_lines_between.py create mode 100644 crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__force_sort_within_sections_force_sort_within_sections_lines_between.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/isort/force_sort_within_sections_lines_between.py b/crates/ruff_linter/resources/test/fixtures/isort/force_sort_within_sections_lines_between.py new file mode 100644 index 0000000000000..5459d78bfd12f --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/isort/force_sort_within_sections_lines_between.py @@ -0,0 +1,4 @@ +from a import x +import b +from c import y +import d diff --git a/crates/ruff_linter/src/rules/isort/mod.rs b/crates/ruff_linter/src/rules/isort/mod.rs index 0cb8655c13cd6..d77a818aa8fff 100644 --- a/crates/ruff_linter/src/rules/isort/mod.rs +++ b/crates/ruff_linter/src/rules/isort/mod.rs @@ -200,6 +200,7 @@ fn format_import_block( // Add a blank lines between direct and from imports. if settings.from_first && lines_between_types > 0 + && !settings.force_sort_within_sections && line_insertion == Some(LineInsertion::Necessary) { for _ in 0..lines_between_types { @@ -225,6 +226,7 @@ fn format_import_block( // Add a blank lines between direct and from imports. if !settings.from_first && lines_between_types > 0 + && !settings.force_sort_within_sections && line_insertion == Some(LineInsertion::Necessary) { for _ in 0..lines_between_types { @@ -722,6 +724,26 @@ mod tests { Ok(()) } + #[test_case(Path::new("force_sort_within_sections_lines_between.py"))] + fn force_sort_within_sections_lines_between(path: &Path) -> Result<()> { + let snapshot = format!("force_sort_within_sections_{}", path.to_string_lossy()); + let mut diagnostics = test_path( + Path::new("isort").join(path).as_path(), + &LinterSettings { + isort: super::settings::Settings { + force_sort_within_sections: true, + lines_between_types: 2, + ..super::settings::Settings::default() + }, + src: vec![test_resource_path("fixtures/isort")], + ..LinterSettings::for_rule(Rule::UnsortedImports) + }, + )?; + diagnostics.sort_by_key(Ranged::start); + assert_messages!(snapshot, diagnostics); + Ok(()) + } + #[test_case(Path::new("comment.py"))] #[test_case(Path::new("comments_and_newlines.py"))] #[test_case(Path::new("docstring.py"))] diff --git a/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__force_sort_within_sections_force_sort_within_sections_lines_between.py.snap b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__force_sort_within_sections_force_sort_within_sections_lines_between.py.snap new file mode 100644 index 0000000000000..ed369f0fd61f0 --- /dev/null +++ b/crates/ruff_linter/src/rules/isort/snapshots/ruff_linter__rules__isort__tests__force_sort_within_sections_force_sort_within_sections_lines_between.py.snap @@ -0,0 +1,4 @@ +--- +source: crates/ruff_linter/src/rules/isort/mod.rs +--- + diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index 442b8d7d2e16d..1d8386d80ab1d 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -2109,6 +2109,13 @@ impl IsortOptions { warn_user_once!("`sections` is ignored when `no-sections` is set to `true`"); } + // Verify that if `force_sort_within_sections` is `True`, then `lines_between_types` is set to `0`. + let force_sort_within_sections = self.force_sort_within_sections.unwrap_or_default(); + let lines_between_types = self.lines_between_types.unwrap_or_default(); + if force_sort_within_sections && lines_between_types != 0 { + warn_user_once!("`lines-between-types` is ignored when `force-sort-within-sections` is set to `true`"); + } + // Extract any configuration options that deal with user-defined sections. let mut section_order: Vec<_> = self .section_order @@ -2240,7 +2247,7 @@ impl IsortOptions { required_imports: BTreeSet::from_iter(self.required_imports.unwrap_or_default()), combine_as_imports: self.combine_as_imports.unwrap_or(false), force_single_line: self.force_single_line.unwrap_or(false), - force_sort_within_sections: self.force_sort_within_sections.unwrap_or(false), + force_sort_within_sections, case_sensitive: self.case_sensitive.unwrap_or(false), force_wrap_aliases: self.force_wrap_aliases.unwrap_or(false), detect_same_package: self.detect_same_package.unwrap_or(true), @@ -2263,7 +2270,7 @@ impl IsortOptions { variables: BTreeSet::from_iter(self.variables.unwrap_or_default()), no_lines_before: BTreeSet::from_iter(no_lines_before), lines_after_imports: self.lines_after_imports.unwrap_or(-1), - lines_between_types: self.lines_between_types.unwrap_or_default(), + lines_between_types, forced_separate: Vec::from_iter(self.forced_separate.unwrap_or_default()), section_order, no_sections, From fcc08894cf68111cdef31b6b071d9716502312e9 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Thu, 7 Dec 2023 00:01:55 -0500 Subject: [PATCH 135/197] Fix documentation snafu that recommended invalid settings (#9018) --- docs/configuration.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index e2a3cfb37cc8e..08a33ffad2b34 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -301,21 +301,20 @@ For example, `ruff check /path/to/excluded/file.py` will always lint `file.py`. ### Default inclusions -By default, Ruff will discover files matching `*.py`, `*.ipy`, or `pyproject.toml`. +By default, Ruff will discover files matching `*.py`, `*.ipy`, or `pyproject.toml`. To lint or format files with additional file extensions, use the [`extend-include`](settings.md#extend-include) setting. === "pyproject.toml" ```toml - [tool.ruff.lint] + [tool.ruff] extend-include = ["*.ipynb"] ``` === "ruff.toml" ```toml - [lint] extend-include = ["*.ipynb"] ``` @@ -325,14 +324,13 @@ You can also change the default selection using the [`include`](settings.md#incl === "pyproject.toml" ```toml - [tool.ruff.lint] + [tool.ruff] include = ["pyproject.toml", "src/**/*.py", "scripts/**/*.py"] ``` === "ruff.toml" ```toml - [lint] include = ["pyproject.toml", "src/**/*.py", "scripts/**/*.py"] ``` From cdac90ef687d8cc8e57f058c8161fb2ae7082ee7 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Thu, 7 Dec 2023 10:28:05 -0600 Subject: [PATCH 136/197] New AST nodes for f-string elements (#8835) Rebase of #6365 authored by @davidszotten. ## Summary This PR updates the AST structure for an f-string elements. The main **motivation** behind this change is to have a dedicated node for the string part of an f-string. Previously, the existing `ExprStringLiteral` node was used for this purpose which isn't exactly correct. The `ExprStringLiteral` node should include the quotes as well in the range but the f-string literal element doesn't include the quote as it's a specific part within an f-string. For example, ```python f"foo {x}" # ^^^^ # This is the literal part of an f-string ``` The introduction of `FStringElement` enum is helpful which represent either the literal part or the expression part of an f-string. ### Rule Updates This means that there'll be two nodes representing a string depending on the context. One for a normal string literal while the other is a string literal within an f-string. The AST checker is updated to accommodate this change. The rules which work on string literal are updated to check on the literal part of f-string as well. #### Notes 1. The `Expr::is_literal_expr` method would check for `ExprStringLiteral` and return true if so. But now that we don't represent the literal part of an f-string using that node, this improves the method's behavior and confines to the actual expression. We do have the `FStringElement::is_literal` method. 2. We avoid checking if we're in a f-string context before adding to `string_type_definitions` because the f-string literal is now a dedicated node and not part of `Expr`. 3. Annotations cannot use f-string so we avoid changing any rules which work on annotation and checks for `ExprStringLiteral`. ## Test Plan - All references of `Expr::StringLiteral` were checked to see if any of the rules require updating to account for the f-string literal element node. - New test cases are added for rules which check against the literal part of an f-string. - Check the ecosystem results and ensure it remains unchanged. ## Performance There's a performance penalty in the parser. The reason for this remains unknown as it seems that the generated assembly code is now different for the `__reduce154` function. The reduce function body is just popping the `ParenthesizedExpr` on top of the stack and pushing it with the new location. - The size of `FStringElement` enum is the same as `Expr` which is what it replaces in `FString::format_spec` - The size of `FStringExpressionElement` is the same as `ExprFormattedValue` which is what it replaces I tried reducing the `Expr` enum from 80 bytes to 72 bytes but it hardly resulted in any performance gain. The difference can be seen here: - Original profile: https://share.firefox.dev/3Taa7ES - Profile after boxing some node fields: https://share.firefox.dev/3GsNXpD ### Backtracking I tried backtracking the changes to see if any of the isolated change produced this regression. The problem here is that the overall change is so small that there's only a single checkpoint where I can backtrack and that checkpoint results in the same regression. This checkpoint is to revert using `Expr` to the `FString::format_spec` field. After this point, the change would revert back to the original implementation. ## Review process The review process is similar to #7927. The first set of commits update the node structure, parser, and related AST files. Then, further commits update the linter and formatter part to account for the AST change. --------- Co-authored-by: David Szotten --- .../test/fixtures/flake8_bandit/S104.py | 1 + .../test/fixtures/flake8_bandit/S108.py | 3 + .../test/fixtures/flake8_pyi/PYI053.py | 1 + .../test/fixtures/flake8_pyi/PYI053.pyi | 4 + .../src/checkers/ast/analyze/expression.rs | 53 +- crates/ruff_linter/src/checkers/ast/mod.rs | 19 +- .../rules/hardcoded_bind_all_interfaces.rs | 14 +- .../rules/hardcoded_tmp_directory.rs | 9 +- ...s__flake8_bandit__tests__S104_S104.py.snap | 24 +- ...s__flake8_bandit__tests__S108_S108.py.snap | 21 +- ...es__flake8_bandit__tests__S108_extend.snap | 29 +- .../src/rules/flake8_comprehensions/fixes.rs | 2 +- .../rules/string_or_bytes_too_long.rs | 20 +- ..._flake8_pyi__tests__PYI053_PYI053.pyi.snap | 27 +- .../flake8_pytest_style/rules/helpers.rs | 16 +- crates/ruff_linter/src/rules/flynt/helpers.rs | 38 +- .../flynt/rules/static_join_to_fstring.rs | 10 +- .../rules/f_string_missing_placeholders.rs | 13 +- .../pylint/rules/assert_on_string_literal.rs | 30 +- .../pyupgrade/rules/use_pep604_annotation.rs | 1 - .../explicit_f_string_type_conversion.rs | 14 +- .../src/rules/ruff/rules/unreachable.rs | 1 - .../tryceratops/rules/raise_vanilla_args.rs | 8 +- crates/ruff_python_ast/src/comparable.rs | 57 +- crates/ruff_python_ast/src/expression.rs | 9 - crates/ruff_python_ast/src/helpers.rs | 54 +- crates/ruff_python_ast/src/node.rs | 163 ++- crates/ruff_python_ast/src/nodes.rs | 75 +- crates/ruff_python_ast/src/relocate.rs | 3 - crates/ruff_python_ast/src/visitor.rs | 55 +- .../ruff_python_ast/src/visitor/preorder.rs | 27 +- .../src/visitor/transformer.rs | 55 +- .../tests/snapshots/preorder__f_strings.snap | 21 +- .../tests/snapshots/visitor__f_strings.snap | 20 +- crates/ruff_python_ast/tests/visitor.rs | 28 +- crates/ruff_python_codegen/src/generator.rs | 54 +- crates/ruff_python_formatter/generate.py | 12 +- .../src/expression/mod.rs | 6 - .../src/expression/string/mod.rs | 9 +- crates/ruff_python_formatter/src/generated.rs | 36 - crates/ruff_python_parser/src/invalid.rs | 1 - crates/ruff_python_parser/src/python.lalrpop | 31 +- crates/ruff_python_parser/src/python.rs | 1080 +++++++++-------- ...ython_parser__parser__tests__fstrings.snap | 576 +++------ ..._parser__tests__fstrings_with_unicode.snap | 60 +- ...parser__parser__tests__parse_f_string.snap | 16 +- ...uff_python_parser__parser__tests__try.snap | 44 +- ...ython_parser__parser__tests__try_star.snap | 84 +- ...string__tests__fstring_constant_range.snap | 56 +- ...ing__tests__fstring_escaped_character.snap | 22 +- ...tring__tests__fstring_escaped_newline.snap | 22 +- ...ing__tests__fstring_line_continuation.snap | 22 +- ...__fstring_parse_self_documenting_base.snap | 8 +- ...ring_parse_self_documenting_base_more.snap | 42 +- ...fstring_parse_self_documenting_format.snap | 49 +- ...ing__tests__fstring_unescaped_newline.snap | 22 +- ...r__string__tests__parse_empty_fstring.snap | 2 +- ...tring__tests__parse_f_string_concat_1.snap | 16 +- ...tring__tests__parse_f_string_concat_2.snap | 16 +- ...tring__tests__parse_f_string_concat_3.snap | 22 +- ...tring__tests__parse_f_string_concat_4.snap | 22 +- ..._parser__string__tests__parse_fstring.snap | 28 +- ...__string__tests__parse_fstring_equals.snap | 8 +- ...ring_nested_concatenation_string_spec.snap | 83 +- ...ing__tests__parse_fstring_nested_spec.snap | 55 +- ...sts__parse_fstring_nested_string_spec.snap | 65 +- ...ring__tests__parse_fstring_not_equals.snap | 8 +- ..._tests__parse_fstring_not_nested_spec.snap | 49 +- ...ts__parse_fstring_self_doc_prec_space.snap | 8 +- ...parse_fstring_self_doc_trailing_space.snap | 8 +- ...ring__tests__parse_fstring_yield_expr.snap | 8 +- ...ing__tests__parse_u_f_string_concat_1.snap | 16 +- ...ing__tests__parse_u_f_string_concat_2.snap | 16 +- ...on_parser__string__tests__raw_fstring.snap | 8 +- ...ing__tests__triple_quoted_raw_fstring.snap | 8 +- crates/ruff_python_parser/src/string.rs | 9 +- .../src/analyze/type_inference.rs | 1 - 77 files changed, 1711 insertions(+), 1922 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S104.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S104.py index 3bbab01871247..7e50db007619c 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S104.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S104.py @@ -8,6 +8,7 @@ def func(address): # Error "0.0.0.0" '0.0.0.0' +f"0.0.0.0" # Error diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S108.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S108.py index 1689af66e63c5..c7cc7dd4809f5 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S108.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S108.py @@ -5,6 +5,9 @@ with open("/tmp/abc", "w") as f: f.write("def") +with open(f"/tmp/abc", "w") as f: + f.write("def") + with open("/var/tmp/123", "w") as f: f.write("def") diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.py b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.py index 8b2811eb63467..640d1fb42b87c 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.py @@ -32,6 +32,7 @@ def f8(x: bytes = b"50 character byte stringgggggggggggggggggggggggggg\xff") -> foo: str = "50 character stringggggggggggggggggggggggggggggggg" bar: str = "51 character stringgggggggggggggggggggggggggggggggg" +baz: str = f"51 character stringgggggggggggggggggggggggggggggggg" baz: bytes = b"50 character byte stringgggggggggggggggggggggggggg" diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.pyi index 71064d9bdbd02..e87388ec9acbb 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.pyi +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.pyi @@ -29,6 +29,10 @@ baz: bytes = b"50 character byte stringgggggggggggggggggggggggggg" # OK qux: bytes = b"51 character byte stringggggggggggggggggggggggggggg\xff" # Error: PYI053 +ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK + +fbar: str = f"51 character stringgggggggggggggggggggggggggggggggg" # Error: PYI053 + class Demo: """Docstrings are excluded from this rule. Some padding.""" # OK diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 381a53adbd1dd..45cbcea34e8f5 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -4,6 +4,7 @@ use ruff_python_literal::cformat::{CFormatError, CFormatErrorType}; use ruff_diagnostics::Diagnostic; use ruff_python_ast::types::Node; +use ruff_python_ast::AstNode; use ruff_python_semantic::analyze::typing; use ruff_python_semantic::ScopeKind; use ruff_text_size::Ranged; @@ -1006,6 +1007,30 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { pyupgrade::rules::unicode_kind_prefix(checker, string_literal); } } + for literal in value.elements().filter_map(|element| element.as_literal()) { + if checker.enabled(Rule::HardcodedBindAllInterfaces) { + flake8_bandit::rules::hardcoded_bind_all_interfaces( + checker, + &literal.value, + literal.range, + ); + } + if checker.enabled(Rule::HardcodedTempFile) { + flake8_bandit::rules::hardcoded_tmp_directory( + checker, + &literal.value, + literal.range, + ); + } + if checker.source_type.is_stub() { + if checker.enabled(Rule::StringOrBytesTooLong) { + flake8_pyi::rules::string_or_bytes_too_long( + checker, + literal.as_any_node_ref(), + ); + } + } + } } Expr::BinOp(ast::ExprBinOp { left, @@ -1270,30 +1295,36 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { refurb::rules::math_constant(checker, number_literal); } } - Expr::BytesLiteral(_) => { + Expr::BytesLiteral(bytes_literal) => { if checker.source_type.is_stub() && checker.enabled(Rule::StringOrBytesTooLong) { - flake8_pyi::rules::string_or_bytes_too_long(checker, expr); + flake8_pyi::rules::string_or_bytes_too_long( + checker, + bytes_literal.as_any_node_ref(), + ); } } - Expr::StringLiteral(string) => { + Expr::StringLiteral(string_literal @ ast::ExprStringLiteral { value, range }) => { if checker.enabled(Rule::HardcodedBindAllInterfaces) { - if let Some(diagnostic) = - flake8_bandit::rules::hardcoded_bind_all_interfaces(string) - { - checker.diagnostics.push(diagnostic); - } + flake8_bandit::rules::hardcoded_bind_all_interfaces( + checker, + value.to_str(), + *range, + ); } if checker.enabled(Rule::HardcodedTempFile) { - flake8_bandit::rules::hardcoded_tmp_directory(checker, string); + flake8_bandit::rules::hardcoded_tmp_directory(checker, value.to_str(), *range); } if checker.enabled(Rule::UnicodeKindPrefix) { - for string_part in string.value.parts() { + for string_part in value.parts() { pyupgrade::rules::unicode_kind_prefix(checker, string_part); } } if checker.source_type.is_stub() { if checker.enabled(Rule::StringOrBytesTooLong) { - flake8_pyi::rules::string_or_bytes_too_long(checker, expr); + flake8_pyi::rules::string_or_bytes_too_long( + checker, + string_literal.as_any_node_ref(), + ); } } } diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 31069ac6c55fd..21a0a944115dd 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -815,8 +815,7 @@ where fn visit_expr(&mut self, expr: &'b Expr) { // Step 0: Pre-processing - if !self.semantic.in_f_string() - && !self.semantic.in_typing_literal() + if !self.semantic.in_typing_literal() && !self.semantic.in_deferred_type_definition() && self.semantic.in_type_definition() && self.semantic.future_annotations() @@ -1238,10 +1237,7 @@ where } } Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { - if self.semantic.in_type_definition() - && !self.semantic.in_typing_literal() - && !self.semantic.in_f_string() - { + if self.semantic.in_type_definition() && !self.semantic.in_typing_literal() { self.deferred.string_type_definitions.push(( expr.range(), value.to_str(), @@ -1326,17 +1322,6 @@ where self.semantic.flags = flags_snapshot; } - fn visit_format_spec(&mut self, format_spec: &'b Expr) { - match format_spec { - Expr::FString(ast::ExprFString { value, .. }) => { - for expr in value.elements() { - self.visit_expr(expr); - } - } - _ => unreachable!("Unexpected expression for format_spec"), - } - } - fn visit_parameters(&mut self, parameters: &'b Parameters) { // Step 1: Binding. // Bind, but intentionally avoid walking default expressions, as we handle them diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs index 49b16b66cd7fa..d5cf806f868f2 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs @@ -1,6 +1,8 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::ExprStringLiteral; +use ruff_text_size::TextRange; + +use crate::checkers::ast::Checker; /// ## What it does /// Checks for hardcoded bindings to all network interfaces (`0.0.0.0`). @@ -34,10 +36,10 @@ impl Violation for HardcodedBindAllInterfaces { } /// S104 -pub(crate) fn hardcoded_bind_all_interfaces(string: &ExprStringLiteral) -> Option { - if string.value.to_str() == "0.0.0.0" { - Some(Diagnostic::new(HardcodedBindAllInterfaces, string.range)) - } else { - None +pub(crate) fn hardcoded_bind_all_interfaces(checker: &mut Checker, value: &str, range: TextRange) { + if value == "0.0.0.0" { + checker + .diagnostics + .push(Diagnostic::new(HardcodedBindAllInterfaces, range)); } } diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs index 09de15f20b91e..469084ad435fb 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs @@ -1,4 +1,5 @@ use ruff_python_ast::{self as ast, Expr}; +use ruff_text_size::TextRange; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; @@ -51,13 +52,13 @@ impl Violation for HardcodedTempFile { } /// S108 -pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, string: &ast::ExprStringLiteral) { +pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, value: &str, range: TextRange) { if !checker .settings .flake8_bandit .hardcoded_tmp_directory .iter() - .any(|prefix| string.value.to_str().starts_with(prefix)) + .any(|prefix| value.starts_with(prefix)) { return; } @@ -76,8 +77,8 @@ pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, string: &ast::ExprS checker.diagnostics.push(Diagnostic::new( HardcodedTempFile { - string: string.value.to_string(), + string: value.to_string(), }, - string.range, + range, )); } diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S104_S104.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S104_S104.py.snap index 192731979437a..b3b9ad07d38d4 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S104_S104.py.snap +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S104_S104.py.snap @@ -7,6 +7,7 @@ S104.py:9:1: S104 Possible binding to all interfaces 9 | "0.0.0.0" | ^^^^^^^^^ S104 10 | '0.0.0.0' +11 | f"0.0.0.0" | S104.py:10:1: S104 Possible binding to all interfaces @@ -15,21 +16,30 @@ S104.py:10:1: S104 Possible binding to all interfaces 9 | "0.0.0.0" 10 | '0.0.0.0' | ^^^^^^^^^ S104 +11 | f"0.0.0.0" | -S104.py:14:6: S104 Possible binding to all interfaces +S104.py:11:3: S104 Possible binding to all interfaces | -13 | # Error -14 | func("0.0.0.0") + 9 | "0.0.0.0" +10 | '0.0.0.0' +11 | f"0.0.0.0" + | ^^^^^^^ S104 + | + +S104.py:15:6: S104 Possible binding to all interfaces + | +14 | # Error +15 | func("0.0.0.0") | ^^^^^^^^^ S104 | -S104.py:18:9: S104 Possible binding to all interfaces +S104.py:19:9: S104 Possible binding to all interfaces | -17 | def my_func(): -18 | x = "0.0.0.0" +18 | def my_func(): +19 | x = "0.0.0.0" | ^^^^^^^^^ S104 -19 | print(x) +20 | print(x) | diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_S108.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_S108.py.snap index 9ecf1141d98a2..7336a5015aa28 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_S108.py.snap +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_S108.py.snap @@ -10,22 +10,31 @@ S108.py:5:11: S108 Probable insecure usage of temporary file or directory: "/tmp 6 | f.write("def") | -S108.py:8:11: S108 Probable insecure usage of temporary file or directory: "/var/tmp/123" +S108.py:8:13: S108 Probable insecure usage of temporary file or directory: "/tmp/abc" | 6 | f.write("def") 7 | -8 | with open("/var/tmp/123", "w") as f: - | ^^^^^^^^^^^^^^ S108 +8 | with open(f"/tmp/abc", "w") as f: + | ^^^^^^^^ S108 9 | f.write("def") | -S108.py:11:11: S108 Probable insecure usage of temporary file or directory: "/dev/shm/unit/test" +S108.py:11:11: S108 Probable insecure usage of temporary file or directory: "/var/tmp/123" | 9 | f.write("def") 10 | -11 | with open("/dev/shm/unit/test", "w") as f: - | ^^^^^^^^^^^^^^^^^^^^ S108 +11 | with open("/var/tmp/123", "w") as f: + | ^^^^^^^^^^^^^^ S108 +12 | f.write("def") + | + +S108.py:14:11: S108 Probable insecure usage of temporary file or directory: "/dev/shm/unit/test" + | 12 | f.write("def") +13 | +14 | with open("/dev/shm/unit/test", "w") as f: + | ^^^^^^^^^^^^^^^^^^^^ S108 +15 | f.write("def") | diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_extend.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_extend.snap index 998bc900593bf..b562794a05d7c 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_extend.snap +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_extend.snap @@ -10,30 +10,39 @@ S108.py:5:11: S108 Probable insecure usage of temporary file or directory: "/tmp 6 | f.write("def") | -S108.py:8:11: S108 Probable insecure usage of temporary file or directory: "/var/tmp/123" +S108.py:8:13: S108 Probable insecure usage of temporary file or directory: "/tmp/abc" | 6 | f.write("def") 7 | -8 | with open("/var/tmp/123", "w") as f: - | ^^^^^^^^^^^^^^ S108 +8 | with open(f"/tmp/abc", "w") as f: + | ^^^^^^^^ S108 9 | f.write("def") | -S108.py:11:11: S108 Probable insecure usage of temporary file or directory: "/dev/shm/unit/test" +S108.py:11:11: S108 Probable insecure usage of temporary file or directory: "/var/tmp/123" | 9 | f.write("def") 10 | -11 | with open("/dev/shm/unit/test", "w") as f: - | ^^^^^^^^^^^^^^^^^^^^ S108 +11 | with open("/var/tmp/123", "w") as f: + | ^^^^^^^^^^^^^^ S108 +12 | f.write("def") + | + +S108.py:14:11: S108 Probable insecure usage of temporary file or directory: "/dev/shm/unit/test" + | 12 | f.write("def") +13 | +14 | with open("/dev/shm/unit/test", "w") as f: + | ^^^^^^^^^^^^^^^^^^^^ S108 +15 | f.write("def") | -S108.py:15:11: S108 Probable insecure usage of temporary file or directory: "/foo/bar" +S108.py:18:11: S108 Probable insecure usage of temporary file or directory: "/foo/bar" | -14 | # not ok by config -15 | with open("/foo/bar", "w") as f: +17 | # not ok by config +18 | with open("/foo/bar", "w") as f: | ^^^^^^^^^^ S108 -16 | f.write("def") +19 | f.write("def") | diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/fixes.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/fixes.rs index 7772b430dc1ad..6c08ddf4a39eb 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/fixes.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/fixes.rs @@ -1083,7 +1083,7 @@ pub(crate) fn fix_unnecessary_map( // If the expression is embedded in an f-string, surround it with spaces to avoid // syntax errors. if matches!(object_type, ObjectType::Set | ObjectType::Dict) { - if parent.is_some_and(Expr::is_formatted_value_expr) { + if parent.is_some_and(Expr::is_f_string_expr) { content = format!(" {content} "); } } diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/string_or_bytes_too_long.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/string_or_bytes_too_long.rs index d8fa801c942f9..1e6aec11fe05a 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/string_or_bytes_too_long.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/string_or_bytes_too_long.rs @@ -1,8 +1,7 @@ -use ruff_python_ast::{self as ast, Expr}; - use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::is_docstring_stmt; +use ruff_python_ast::{self as ast, AnyNodeRef}; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -44,25 +43,30 @@ impl AlwaysFixableViolation for StringOrBytesTooLong { } /// PYI053 -pub(crate) fn string_or_bytes_too_long(checker: &mut Checker, expr: &Expr) { +pub(crate) fn string_or_bytes_too_long(checker: &mut Checker, node: AnyNodeRef) { // Ignore docstrings. if is_docstring_stmt(checker.semantic().current_statement()) { return; } - let length = match expr { - Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => value.chars().count(), - Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => value.len(), + let length = match node { + AnyNodeRef::ExprStringLiteral(ast::ExprStringLiteral { value, .. }) => { + value.chars().count() + } + AnyNodeRef::ExprBytesLiteral(ast::ExprBytesLiteral { value, .. }) => value.len(), + AnyNodeRef::FStringLiteralElement(ast::FStringLiteralElement { value, .. }) => { + value.chars().count() + } _ => return, }; if length <= 50 { return; } - let mut diagnostic = Diagnostic::new(StringOrBytesTooLong, expr.range()); + let mut diagnostic = Diagnostic::new(StringOrBytesTooLong, node.range()); diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( "...".to_string(), - expr.range(), + node.range(), ))); checker.diagnostics.push(diagnostic); } diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI053_PYI053.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI053_PYI053.pyi.snap index 2e8fd1a1a3f5b..f0a6ebc9055fb 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI053_PYI053.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI053_PYI053.pyi.snap @@ -90,7 +90,7 @@ PYI053.pyi:30:14: PYI053 [*] String and bytes literals longer than 50 characters 30 | qux: bytes = b"51 character byte stringggggggggggggggggggggggggggg\xff" # Error: PYI053 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI053 31 | -32 | class Demo: +32 | ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK | = help: Replace with `...` @@ -101,7 +101,28 @@ PYI053.pyi:30:14: PYI053 [*] String and bytes literals longer than 50 characters 30 |-qux: bytes = b"51 character byte stringggggggggggggggggggggggggggg\xff" # Error: PYI053 30 |+qux: bytes = ... # Error: PYI053 31 31 | -32 32 | class Demo: -33 33 | """Docstrings are excluded from this rule. Some padding.""" # OK +32 32 | ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK +33 33 | + +PYI053.pyi:34:15: PYI053 [*] String and bytes literals longer than 50 characters are not permitted + | +32 | ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK +33 | +34 | fbar: str = f"51 character stringgggggggggggggggggggggggggggggggg" # Error: PYI053 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI053 +35 | +36 | class Demo: + | + = help: Replace with `...` + +ℹ Safe fix +31 31 | +32 32 | ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK +33 33 | +34 |-fbar: str = f"51 character stringgggggggggggggggggggggggggggggggg" # Error: PYI053 + 34 |+fbar: str = f"..." # Error: PYI053 +35 35 | +36 36 | class Demo: +37 37 | """Docstrings are excluded from this rule. Some padding.""" # OK diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs index 34303d204c415..8bc9f4423b440 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs @@ -58,15 +58,25 @@ pub(super) fn is_empty_or_null_string(expr: &Expr) -> bool { Expr::FString(ast::ExprFString { value, .. }) => { value.parts().all(|f_string_part| match f_string_part { ast::FStringPart::Literal(literal) => literal.is_empty(), - ast::FStringPart::FString(f_string) => { - f_string.values.iter().all(is_empty_or_null_string) - } + ast::FStringPart::FString(f_string) => f_string + .elements + .iter() + .all(is_empty_or_null_fstring_element), }) } _ => false, } } +fn is_empty_or_null_fstring_element(element: &ast::FStringElement) -> bool { + match element { + ast::FStringElement::Literal(ast::FStringLiteralElement { value, .. }) => value.is_empty(), + ast::FStringElement::Expression(ast::FStringExpressionElement { expression, .. }) => { + is_empty_or_null_string(expression) + } + } +} + pub(super) fn split_names(names: &str) -> Vec<&str> { // Match the following pytest code: // [x.strip() for x in argnames.split(",") if x.strip()] diff --git a/crates/ruff_linter/src/rules/flynt/helpers.rs b/crates/ruff_linter/src/rules/flynt/helpers.rs index 83c6b131461be..7a6af204d13f9 100644 --- a/crates/ruff_linter/src/rules/flynt/helpers.rs +++ b/crates/ruff_linter/src/rules/flynt/helpers.rs @@ -1,25 +1,23 @@ use ruff_python_ast::{self as ast, Arguments, ConversionFlag, Expr}; use ruff_text_size::TextRange; -/// Wrap an expression in a `FormattedValue` with no special formatting. -fn to_formatted_value_expr(inner: &Expr) -> Expr { - let node = ast::ExprFormattedValue { - value: Box::new(inner.clone()), +/// Wrap an expression in a [`ast::FStringElement::Expression`] with no special formatting. +fn to_f_string_expression_element(inner: &Expr) -> ast::FStringElement { + ast::FStringElement::Expression(ast::FStringExpressionElement { + expression: Box::new(inner.clone()), debug_text: None, conversion: ConversionFlag::None, format_spec: None, range: TextRange::default(), - }; - node.into() + }) } -/// Convert a string to a constant string expression. -pub(super) fn to_constant_string(s: &str) -> Expr { - let node = ast::StringLiteral { - value: s.to_string(), - ..ast::StringLiteral::default() - }; - node.into() +/// Convert a string to a [`ast::FStringElement::Literal`]. +pub(super) fn to_f_string_literal_element(s: &str) -> ast::FStringElement { + ast::FStringElement::Literal(ast::FStringLiteralElement { + value: s.to_owned(), + range: TextRange::default(), + }) } /// Figure out if `expr` represents a "simple" call @@ -51,15 +49,19 @@ fn is_simple_callee(func: &Expr) -> bool { } /// Convert an expression to a f-string element (if it looks like a good idea). -pub(super) fn to_f_string_element(expr: &Expr) -> Option { +pub(super) fn to_f_string_element(expr: &Expr) -> Option { match expr { - // These are directly handled by `unparse_f_string_element`: - Expr::StringLiteral(_) | Expr::FString(_) | Expr::FormattedValue(_) => Some(expr.clone()), + Expr::StringLiteral(ast::ExprStringLiteral { value, range }) => { + Some(ast::FStringElement::Literal(ast::FStringLiteralElement { + value: value.to_string(), + range: *range, + })) + } // These should be pretty safe to wrap in a formatted value. Expr::NumberLiteral(_) | Expr::BooleanLiteral(_) | Expr::Name(_) | Expr::Attribute(_) => { - Some(to_formatted_value_expr(expr)) + Some(to_f_string_expression_element(expr)) } - Expr::Call(_) if is_simple_call(expr) => Some(to_formatted_value_expr(expr)), + Expr::Call(_) if is_simple_call(expr) => Some(to_f_string_expression_element(expr)), _ => None, } } diff --git a/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs b/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs index 4f37fafe35994..86c77bbb0ed73 100644 --- a/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs +++ b/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs @@ -78,7 +78,7 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option { return Some(node.into()); } - let mut fstring_elems = Vec::with_capacity(joinees.len() * 2); + let mut f_string_elements = Vec::with_capacity(joinees.len() * 2); let mut first = true; for expr in joinees { @@ -88,13 +88,13 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option { return None; } if !std::mem::take(&mut first) { - fstring_elems.push(helpers::to_constant_string(joiner)); + f_string_elements.push(helpers::to_f_string_literal_element(joiner)); } - fstring_elems.push(helpers::to_f_string_element(expr)?); + f_string_elements.push(helpers::to_f_string_element(expr)?); } let node = ast::FString { - values: fstring_elems, + elements: f_string_elements, range: TextRange::default(), }; Some(node.into()) @@ -127,7 +127,7 @@ pub(crate) fn static_join_to_fstring(checker: &mut Checker, expr: &Expr, joiner: }; // Try to build the fstring (internally checks whether e.g. the elements are - // convertible to f-string parts). + // convertible to f-string elements). let Some(new_expr) = build_fstring(joiner, joinees) else { return; }; diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs b/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs index f2adeb69d76ab..36263f332809e 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs @@ -1,6 +1,6 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{self as ast, Expr}; +use ruff_python_ast as ast; use ruff_source_file::Locator; use ruff_text_size::{Ranged, TextRange, TextSize}; @@ -47,11 +47,12 @@ impl AlwaysFixableViolation for FStringMissingPlaceholders { /// F541 pub(crate) fn f_string_missing_placeholders(checker: &mut Checker, expr: &ast::ExprFString) { - if expr - .value - .f_strings() - .any(|f_string| f_string.values.iter().any(Expr::is_formatted_value_expr)) - { + if expr.value.f_strings().any(|f_string| { + f_string + .elements + .iter() + .any(ast::FStringElement::is_expression) + }) { return; } diff --git a/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs b/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs index fee8f01a5c575..034c9b3126a56 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs @@ -72,24 +72,26 @@ pub(crate) fn assert_on_string_literal(checker: &mut Checker, test: &Expr) { Expr::FString(ast::ExprFString { value, .. }) => { let kind = if value.parts().all(|f_string_part| match f_string_part { ast::FStringPart::Literal(literal) => literal.is_empty(), - ast::FStringPart::FString(f_string) => f_string.values.iter().all(|value| { - if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = value { - value.is_empty() - } else { - false - } - }), + ast::FStringPart::FString(f_string) => { + f_string.elements.iter().all(|element| match element { + ast::FStringElement::Literal(ast::FStringLiteralElement { + value, .. + }) => value.is_empty(), + ast::FStringElement::Expression(_) => false, + }) + } }) { Kind::Empty } else if value.parts().any(|f_string_part| match f_string_part { ast::FStringPart::Literal(literal) => !literal.is_empty(), - ast::FStringPart::FString(f_string) => f_string.values.iter().any(|value| { - if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = value { - !value.is_empty() - } else { - false - } - }), + ast::FStringPart::FString(f_string) => { + f_string.elements.iter().any(|element| match element { + ast::FStringElement::Literal(ast::FStringLiteralElement { + value, .. + }) => !value.is_empty(), + ast::FStringElement::Expression(_) => false, + }) + } }) { Kind::NonEmpty } else { diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs index 70aa2cec0eeaf..5332be054f86b 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs @@ -180,7 +180,6 @@ fn is_allowed_value(expr: &Expr) -> bool { | Expr::GeneratorExp(_) | Expr::Compare(_) | Expr::Call(_) - | Expr::FormattedValue(_) | Expr::FString(_) | Expr::StringLiteral(_) | Expr::BytesLiteral(_) diff --git a/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs b/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs index d30a04705ea76..7fe11923d2222 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs @@ -53,10 +53,12 @@ impl AlwaysFixableViolation for ExplicitFStringTypeConversion { /// RUF010 pub(crate) fn explicit_f_string_type_conversion(checker: &mut Checker, f_string: &ast::FString) { - for (index, expr) in f_string.values.iter().enumerate() { - let Some(ast::ExprFormattedValue { - value, conversion, .. - }) = expr.as_formatted_value_expr() + for (index, element) in f_string.elements.iter().enumerate() { + let Some(ast::FStringExpressionElement { + expression, + conversion, + .. + }) = element.as_expression() else { continue; }; @@ -75,7 +77,7 @@ pub(crate) fn explicit_f_string_type_conversion(checker: &mut Checker, f_string: range: _, }, .. - }) = value.as_ref() + }) = expression.as_ref() else { continue; }; @@ -110,7 +112,7 @@ pub(crate) fn explicit_f_string_type_conversion(checker: &mut Checker, f_string: continue; } - let mut diagnostic = Diagnostic::new(ExplicitFStringTypeConversion, value.range()); + let mut diagnostic = Diagnostic::new(ExplicitFStringTypeConversion, expression.range()); diagnostic.try_set_fix(|| { convert_call_to_conversion_flag(f_string, index, checker.locator(), checker.stylist()) }); diff --git a/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs b/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs index e94cb4179d3e9..5445aabd3eea1 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs @@ -635,7 +635,6 @@ impl<'stmt> BasicBlocksBuilder<'stmt> { | Expr::Set(_) | Expr::Compare(_) | Expr::Call(_) - | Expr::FormattedValue(_) | Expr::FString(_) | Expr::StringLiteral(_) | Expr::BytesLiteral(_) diff --git a/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs b/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs index acb257705063b..bb35bd8cdc7da 100644 --- a/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs +++ b/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs @@ -98,8 +98,12 @@ fn contains_message(expr: &Expr) -> bool { } } ast::FStringPart::FString(f_string) => { - for value in &f_string.values { - if contains_message(value) { + for literal in f_string + .elements + .iter() + .filter_map(|element| element.as_literal()) + { + if literal.chars().any(char::is_whitespace) { return true; } } diff --git a/crates/ruff_python_ast/src/comparable.rs b/crates/ruff_python_ast/src/comparable.rs index 0fe4a17f8e8b0..b4a94f3544380 100644 --- a/crates/ruff_python_ast/src/comparable.rs +++ b/crates/ruff_python_ast/src/comparable.rs @@ -509,6 +509,41 @@ impl<'a> From<&'a ast::ExceptHandler> for ComparableExceptHandler<'a> { } } +#[derive(Debug, PartialEq, Eq, Hash)] +pub enum ComparableFStringElement<'a> { + Literal(&'a str), + FStringExpressionElement(FStringExpressionElement<'a>), +} + +#[derive(Debug, PartialEq, Eq, Hash)] +pub struct FStringExpressionElement<'a> { + expression: ComparableExpr<'a>, + debug_text: Option<&'a ast::DebugText>, + conversion: ast::ConversionFlag, + format_spec: Option>>, +} + +impl<'a> From<&'a ast::FStringElement> for ComparableFStringElement<'a> { + fn from(fstring_element: &'a ast::FStringElement) -> Self { + match fstring_element { + ast::FStringElement::Literal(ast::FStringLiteralElement { value, .. }) => { + Self::Literal(value) + } + ast::FStringElement::Expression(formatted_value) => { + Self::FStringExpressionElement(FStringExpressionElement { + expression: (&formatted_value.expression).into(), + debug_text: formatted_value.debug_text.as_ref(), + conversion: formatted_value.conversion, + format_spec: formatted_value + .format_spec + .as_ref() + .map(|spec| spec.elements.iter().map(Into::into).collect()), + }) + } + } + } +} + #[derive(Debug, PartialEq, Eq, Hash)] pub struct ComparableElifElseClause<'a> { test: Option>, @@ -562,13 +597,13 @@ impl<'a> From> for ComparableLiteral<'a> { #[derive(Debug, PartialEq, Eq, Hash)] pub struct ComparableFString<'a> { - values: Vec>, + elements: Vec>, } impl<'a> From<&'a ast::FString> for ComparableFString<'a> { fn from(fstring: &'a ast::FString) -> Self { Self { - values: fstring.values.iter().map(Into::into).collect(), + elements: fstring.elements.iter().map(Into::into).collect(), } } } @@ -717,11 +752,11 @@ pub struct ExprCall<'a> { } #[derive(Debug, PartialEq, Eq, Hash)] -pub struct ExprFormattedValue<'a> { +pub struct ExprFStringExpressionElement<'a> { value: Box>, debug_text: Option<&'a ast::DebugText>, conversion: ast::ConversionFlag, - format_spec: Option>>, + format_spec: Vec>, } #[derive(Debug, PartialEq, Eq, Hash)] @@ -813,7 +848,7 @@ pub enum ComparableExpr<'a> { YieldFrom(ExprYieldFrom<'a>), Compare(ExprCompare<'a>), Call(ExprCall<'a>), - FormattedValue(ExprFormattedValue<'a>), + FStringExpressionElement(ExprFStringExpressionElement<'a>), FString(ExprFString<'a>), StringLiteral(ExprStringLiteral<'a>), BytesLiteral(ExprBytesLiteral<'a>), @@ -975,18 +1010,6 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> { func: func.into(), arguments: arguments.into(), }), - ast::Expr::FormattedValue(ast::ExprFormattedValue { - value, - conversion, - debug_text, - format_spec, - range: _, - }) => Self::FormattedValue(ExprFormattedValue { - value: value.into(), - conversion: *conversion, - debug_text: debug_text.as_ref(), - format_spec: format_spec.as_ref().map(Into::into), - }), ast::Expr::FString(ast::ExprFString { value, range: _ }) => { Self::FString(ExprFString { parts: value.parts().map(Into::into).collect(), diff --git a/crates/ruff_python_ast/src/expression.rs b/crates/ruff_python_ast/src/expression.rs index 4bdc46f7dbf8d..a8a86a8ec1ef9 100644 --- a/crates/ruff_python_ast/src/expression.rs +++ b/crates/ruff_python_ast/src/expression.rs @@ -23,7 +23,6 @@ pub enum ExpressionRef<'a> { YieldFrom(&'a ast::ExprYieldFrom), Compare(&'a ast::ExprCompare), Call(&'a ast::ExprCall), - FormattedValue(&'a ast::ExprFormattedValue), FString(&'a ast::ExprFString), StringLiteral(&'a ast::ExprStringLiteral), BytesLiteral(&'a ast::ExprBytesLiteral), @@ -67,7 +66,6 @@ impl<'a> From<&'a Expr> for ExpressionRef<'a> { Expr::YieldFrom(value) => ExpressionRef::YieldFrom(value), Expr::Compare(value) => ExpressionRef::Compare(value), Expr::Call(value) => ExpressionRef::Call(value), - Expr::FormattedValue(value) => ExpressionRef::FormattedValue(value), Expr::FString(value) => ExpressionRef::FString(value), Expr::StringLiteral(value) => ExpressionRef::StringLiteral(value), Expr::BytesLiteral(value) => ExpressionRef::BytesLiteral(value), @@ -172,11 +170,6 @@ impl<'a> From<&'a ast::ExprCall> for ExpressionRef<'a> { Self::Call(value) } } -impl<'a> From<&'a ast::ExprFormattedValue> for ExpressionRef<'a> { - fn from(value: &'a ast::ExprFormattedValue) -> Self { - Self::FormattedValue(value) - } -} impl<'a> From<&'a ast::ExprFString> for ExpressionRef<'a> { fn from(value: &'a ast::ExprFString) -> Self { Self::FString(value) @@ -273,7 +266,6 @@ impl<'a> From> for AnyNodeRef<'a> { ExpressionRef::YieldFrom(expression) => AnyNodeRef::ExprYieldFrom(expression), ExpressionRef::Compare(expression) => AnyNodeRef::ExprCompare(expression), ExpressionRef::Call(expression) => AnyNodeRef::ExprCall(expression), - ExpressionRef::FormattedValue(expression) => AnyNodeRef::ExprFormattedValue(expression), ExpressionRef::FString(expression) => AnyNodeRef::ExprFString(expression), ExpressionRef::StringLiteral(expression) => AnyNodeRef::ExprStringLiteral(expression), ExpressionRef::BytesLiteral(expression) => AnyNodeRef::ExprBytesLiteral(expression), @@ -317,7 +309,6 @@ impl Ranged for ExpressionRef<'_> { ExpressionRef::YieldFrom(expression) => expression.range(), ExpressionRef::Compare(expression) => expression.range(), ExpressionRef::Call(expression) => expression.range(), - ExpressionRef::FormattedValue(expression) => expression.range(), ExpressionRef::FString(expression) => expression.range(), ExpressionRef::StringLiteral(expression) => expression.range(), ExpressionRef::BytesLiteral(expression) => expression.range(), diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index cca590903244b..b9e0866837d6c 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -12,8 +12,8 @@ use crate::parenthesize::parenthesized_range; use crate::statement_visitor::StatementVisitor; use crate::visitor::Visitor; use crate::{ - self as ast, Arguments, CmpOp, ExceptHandler, Expr, MatchCase, Operator, Pattern, Stmt, - TypeParam, + self as ast, Arguments, CmpOp, ExceptHandler, Expr, FStringElement, MatchCase, Operator, + Pattern, Stmt, TypeParam, }; use crate::{AnyNodeRef, ExprContext}; @@ -136,9 +136,9 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool { Expr::BoolOp(ast::ExprBoolOp { values, .. }) => { values.iter().any(|expr| any_over_expr(expr, func)) } - Expr::FString(ast::ExprFString { value, .. }) => { - value.elements().any(|expr| any_over_expr(expr, func)) - } + Expr::FString(ast::ExprFString { value, .. }) => value + .elements() + .any(|expr| any_over_f_string_element(expr, func)), Expr::NamedExpr(ast::ExprNamedExpr { target, value, @@ -231,14 +231,6 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool { .iter() .any(|keyword| any_over_expr(&keyword.value, func)) } - Expr::FormattedValue(ast::ExprFormattedValue { - value, format_spec, .. - }) => { - any_over_expr(value, func) - || format_spec - .as_ref() - .is_some_and(|value| any_over_expr(value, func)) - } Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => { any_over_expr(value, func) || any_over_expr(slice, func) } @@ -315,6 +307,24 @@ pub fn any_over_pattern(pattern: &Pattern, func: &dyn Fn(&Expr) -> bool) -> bool } } +pub fn any_over_f_string_element(element: &FStringElement, func: &dyn Fn(&Expr) -> bool) -> bool { + match element { + FStringElement::Literal(_) => false, + FStringElement::Expression(ast::FStringExpressionElement { + expression, + format_spec, + .. + }) => { + any_over_expr(expression, func) + || format_spec.as_ref().is_some_and(|spec| { + spec.elements + .iter() + .any(|spec_element| any_over_f_string_element(spec_element, func)) + }) + } + } +} + pub fn any_over_stmt(stmt: &Stmt, func: &dyn Fn(&Expr) -> bool) -> bool { match stmt { Stmt::FunctionDef(ast::StmtFunctionDef { @@ -1318,16 +1328,18 @@ impl Truthiness { Expr::FString(ast::ExprFString { value, .. }) => { if value.parts().all(|part| match part { ast::FStringPart::Literal(string_literal) => string_literal.is_empty(), - ast::FStringPart::FString(f_string) => f_string.values.is_empty(), + ast::FStringPart::FString(f_string) => f_string.elements.is_empty(), }) { Self::Falsey - } else if value.elements().any(|expr| { - if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &expr { - !value.is_empty() - } else { - false - } - }) { + } else if value + .elements() + .any(|f_string_element| match f_string_element { + ast::FStringElement::Literal(ast::FStringLiteralElement { + value, .. + }) => !value.is_empty(), + ast::FStringElement::Expression(_) => true, + }) + { Self::Truthy } else { Self::Unknown diff --git a/crates/ruff_python_ast/src/node.rs b/crates/ruff_python_ast/src/node.rs index e21a000d79ae7..94bb5d40d2148 100644 --- a/crates/ruff_python_ast/src/node.rs +++ b/crates/ruff_python_ast/src/node.rs @@ -1,7 +1,7 @@ use crate::visitor::preorder::PreorderVisitor; use crate::{ self as ast, Alias, ArgOrKeyword, Arguments, Comprehension, Decorator, ExceptHandler, Expr, - Keyword, MatchCase, Mod, Parameter, ParameterWithDefault, Parameters, Pattern, + FStringElement, Keyword, MatchCase, Mod, Parameter, ParameterWithDefault, Parameters, Pattern, PatternArguments, PatternKeyword, Stmt, TypeParam, TypeParamParamSpec, TypeParamTypeVar, TypeParamTypeVarTuple, TypeParams, WithItem, }; @@ -71,7 +71,6 @@ pub enum AnyNode { ExprYieldFrom(ast::ExprYieldFrom), ExprCompare(ast::ExprCompare), ExprCall(ast::ExprCall), - ExprFormattedValue(ast::ExprFormattedValue), ExprFString(ast::ExprFString), ExprStringLiteral(ast::ExprStringLiteral), ExprBytesLiteral(ast::ExprBytesLiteral), @@ -88,6 +87,8 @@ pub enum AnyNode { ExprSlice(ast::ExprSlice), ExprIpyEscapeCommand(ast::ExprIpyEscapeCommand), ExceptHandlerExceptHandler(ast::ExceptHandlerExceptHandler), + FStringExpressionElement(ast::FStringExpressionElement), + FStringLiteralElement(ast::FStringLiteralElement), PatternMatchValue(ast::PatternMatchValue), PatternMatchSingleton(ast::PatternMatchSingleton), PatternMatchSequence(ast::PatternMatchSequence), @@ -166,7 +167,8 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) - | AnyNode::ExprFormattedValue(_) + | AnyNode::FStringExpressionElement(_) + | AnyNode::FStringLiteralElement(_) | AnyNode::ExprFString(_) | AnyNode::ExprStringLiteral(_) | AnyNode::ExprBytesLiteral(_) @@ -233,7 +235,6 @@ impl AnyNode { AnyNode::ExprYieldFrom(node) => Some(Expr::YieldFrom(node)), AnyNode::ExprCompare(node) => Some(Expr::Compare(node)), AnyNode::ExprCall(node) => Some(Expr::Call(node)), - AnyNode::ExprFormattedValue(node) => Some(Expr::FormattedValue(node)), AnyNode::ExprFString(node) => Some(Expr::FString(node)), AnyNode::ExprStringLiteral(node) => Some(Expr::StringLiteral(node)), AnyNode::ExprBytesLiteral(node) => Some(Expr::BytesLiteral(node)), @@ -278,6 +279,8 @@ impl AnyNode { | AnyNode::StmtContinue(_) | AnyNode::StmtIpyEscapeCommand(_) | AnyNode::ExceptHandlerExceptHandler(_) + | AnyNode::FStringExpressionElement(_) + | AnyNode::FStringLiteralElement(_) | AnyNode::PatternMatchValue(_) | AnyNode::PatternMatchSingleton(_) | AnyNode::PatternMatchSequence(_) @@ -356,7 +359,8 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) - | AnyNode::ExprFormattedValue(_) + | AnyNode::FStringExpressionElement(_) + | AnyNode::FStringLiteralElement(_) | AnyNode::ExprFString(_) | AnyNode::ExprStringLiteral(_) | AnyNode::ExprBytesLiteral(_) @@ -459,7 +463,8 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) - | AnyNode::ExprFormattedValue(_) + | AnyNode::FStringExpressionElement(_) + | AnyNode::FStringLiteralElement(_) | AnyNode::ExprFString(_) | AnyNode::ExprStringLiteral(_) | AnyNode::ExprBytesLiteral(_) @@ -547,7 +552,8 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) - | AnyNode::ExprFormattedValue(_) + | AnyNode::FStringExpressionElement(_) + | AnyNode::FStringLiteralElement(_) | AnyNode::ExprFString(_) | AnyNode::ExprStringLiteral(_) | AnyNode::ExprBytesLiteral(_) @@ -660,7 +666,8 @@ impl AnyNode { Self::ExprYieldFrom(node) => AnyNodeRef::ExprYieldFrom(node), Self::ExprCompare(node) => AnyNodeRef::ExprCompare(node), Self::ExprCall(node) => AnyNodeRef::ExprCall(node), - Self::ExprFormattedValue(node) => AnyNodeRef::ExprFormattedValue(node), + Self::FStringExpressionElement(node) => AnyNodeRef::FStringExpressionElement(node), + Self::FStringLiteralElement(node) => AnyNodeRef::FStringLiteralElement(node), Self::ExprFString(node) => AnyNodeRef::ExprFString(node), Self::ExprStringLiteral(node) => AnyNodeRef::ExprStringLiteral(node), Self::ExprBytesLiteral(node) => AnyNodeRef::ExprBytesLiteral(node), @@ -2621,12 +2628,12 @@ impl AstNode for ast::ExprCall { visitor.visit_arguments(arguments); } } -impl AstNode for ast::ExprFormattedValue { +impl AstNode for ast::FStringExpressionElement { fn cast(kind: AnyNode) -> Option where Self: Sized, { - if let AnyNode::ExprFormattedValue(node) = kind { + if let AnyNode::FStringExpressionElement(node) = kind { Some(node) } else { None @@ -2634,7 +2641,7 @@ impl AstNode for ast::ExprFormattedValue { } fn cast_ref(kind: AnyNodeRef) -> Option<&Self> { - if let AnyNodeRef::ExprFormattedValue(node) = kind { + if let AnyNodeRef::FStringExpressionElement(node) = kind { Some(node) } else { None @@ -2653,16 +2660,54 @@ impl AstNode for ast::ExprFormattedValue { where V: PreorderVisitor<'a> + ?Sized, { - let ast::ExprFormattedValue { - value, format_spec, .. + let ast::FStringExpressionElement { + expression, + format_spec, + .. } = self; - visitor.visit_expr(value); + visitor.visit_expr(expression); - if let Some(expr) = format_spec { - visitor.visit_format_spec(expr); + if let Some(format_spec) = format_spec { + for spec_part in &format_spec.elements { + visitor.visit_f_string_element(spec_part); + } } } } +impl AstNode for ast::FStringLiteralElement { + fn cast(kind: AnyNode) -> Option + where + Self: Sized, + { + if let AnyNode::FStringLiteralElement(node) = kind { + Some(node) + } else { + None + } + } + + fn cast_ref(kind: AnyNodeRef) -> Option<&Self> { + if let AnyNodeRef::FStringLiteralElement(node) = kind { + Some(node) + } else { + None + } + } + + fn as_any_node_ref(&self) -> AnyNodeRef { + AnyNodeRef::from(self) + } + + fn into_any_node(self) -> AnyNode { + AnyNode::from(self) + } + + fn visit_preorder<'a, V>(&'a self, _visitor: &mut V) + where + V: PreorderVisitor<'a> + ?Sized, + { + } +} impl AstNode for ast::ExprFString { fn cast(kind: AnyNode) -> Option where @@ -4339,10 +4384,10 @@ impl AstNode for ast::FString { where V: PreorderVisitor<'a> + ?Sized, { - let ast::FString { values, range: _ } = self; + let ast::FString { elements, range: _ } = self; - for expr in values { - visitor.visit_expr(expr); + for fstring_element in elements { + visitor.visit_f_string_element(fstring_element); } } } @@ -4467,7 +4512,6 @@ impl From for AnyNode { Expr::YieldFrom(node) => AnyNode::ExprYieldFrom(node), Expr::Compare(node) => AnyNode::ExprCompare(node), Expr::Call(node) => AnyNode::ExprCall(node), - Expr::FormattedValue(node) => AnyNode::ExprFormattedValue(node), Expr::FString(node) => AnyNode::ExprFString(node), Expr::StringLiteral(node) => AnyNode::ExprStringLiteral(node), Expr::BytesLiteral(node) => AnyNode::ExprBytesLiteral(node), @@ -4496,6 +4540,15 @@ impl From for AnyNode { } } +impl From for AnyNode { + fn from(element: FStringElement) -> Self { + match element { + FStringElement::Literal(node) => AnyNode::FStringLiteralElement(node), + FStringElement::Expression(node) => AnyNode::FStringExpressionElement(node), + } + } +} + impl From for AnyNode { fn from(pattern: Pattern) -> Self { match pattern { @@ -4789,9 +4842,15 @@ impl From for AnyNode { } } -impl From for AnyNode { - fn from(node: ast::ExprFormattedValue) -> Self { - AnyNode::ExprFormattedValue(node) +impl From for AnyNode { + fn from(node: ast::FStringExpressionElement) -> Self { + AnyNode::FStringExpressionElement(node) + } +} + +impl From for AnyNode { + fn from(node: ast::FStringLiteralElement) -> Self { + AnyNode::FStringLiteralElement(node) } } @@ -5089,7 +5148,8 @@ impl Ranged for AnyNode { AnyNode::ExprYieldFrom(node) => node.range(), AnyNode::ExprCompare(node) => node.range(), AnyNode::ExprCall(node) => node.range(), - AnyNode::ExprFormattedValue(node) => node.range(), + AnyNode::FStringExpressionElement(node) => node.range(), + AnyNode::FStringLiteralElement(node) => node.range(), AnyNode::ExprFString(node) => node.range(), AnyNode::ExprStringLiteral(node) => node.range(), AnyNode::ExprBytesLiteral(node) => node.range(), @@ -5184,7 +5244,8 @@ pub enum AnyNodeRef<'a> { ExprYieldFrom(&'a ast::ExprYieldFrom), ExprCompare(&'a ast::ExprCompare), ExprCall(&'a ast::ExprCall), - ExprFormattedValue(&'a ast::ExprFormattedValue), + FStringExpressionElement(&'a ast::FStringExpressionElement), + FStringLiteralElement(&'a ast::FStringLiteralElement), ExprFString(&'a ast::ExprFString), ExprStringLiteral(&'a ast::ExprStringLiteral), ExprBytesLiteral(&'a ast::ExprBytesLiteral), @@ -5278,7 +5339,8 @@ impl<'a> AnyNodeRef<'a> { AnyNodeRef::ExprYieldFrom(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprCompare(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprCall(node) => NonNull::from(*node).cast(), - AnyNodeRef::ExprFormattedValue(node) => NonNull::from(*node).cast(), + AnyNodeRef::FStringExpressionElement(node) => NonNull::from(*node).cast(), + AnyNodeRef::FStringLiteralElement(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprFString(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprStringLiteral(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprBytesLiteral(node) => NonNull::from(*node).cast(), @@ -5378,7 +5440,8 @@ impl<'a> AnyNodeRef<'a> { AnyNodeRef::ExprYieldFrom(_) => NodeKind::ExprYieldFrom, AnyNodeRef::ExprCompare(_) => NodeKind::ExprCompare, AnyNodeRef::ExprCall(_) => NodeKind::ExprCall, - AnyNodeRef::ExprFormattedValue(_) => NodeKind::ExprFormattedValue, + AnyNodeRef::FStringExpressionElement(_) => NodeKind::FStringExpressionElement, + AnyNodeRef::FStringLiteralElement(_) => NodeKind::FStringLiteralElement, AnyNodeRef::ExprFString(_) => NodeKind::ExprFString, AnyNodeRef::ExprStringLiteral(_) => NodeKind::ExprStringLiteral, AnyNodeRef::ExprBytesLiteral(_) => NodeKind::ExprBytesLiteral, @@ -5473,7 +5536,8 @@ impl<'a> AnyNodeRef<'a> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) - | AnyNodeRef::ExprFormattedValue(_) + | AnyNodeRef::FStringExpressionElement(_) + | AnyNodeRef::FStringLiteralElement(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprStringLiteral(_) | AnyNodeRef::ExprBytesLiteral(_) @@ -5540,7 +5604,6 @@ impl<'a> AnyNodeRef<'a> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) - | AnyNodeRef::ExprFormattedValue(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprStringLiteral(_) | AnyNodeRef::ExprBytesLiteral(_) @@ -5585,6 +5648,8 @@ impl<'a> AnyNodeRef<'a> { | AnyNodeRef::StmtContinue(_) | AnyNodeRef::StmtIpyEscapeCommand(_) | AnyNodeRef::ExceptHandlerExceptHandler(_) + | AnyNodeRef::FStringExpressionElement(_) + | AnyNodeRef::FStringLiteralElement(_) | AnyNodeRef::PatternMatchValue(_) | AnyNodeRef::PatternMatchSingleton(_) | AnyNodeRef::PatternMatchSequence(_) @@ -5662,7 +5727,8 @@ impl<'a> AnyNodeRef<'a> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) - | AnyNodeRef::ExprFormattedValue(_) + | AnyNodeRef::FStringExpressionElement(_) + | AnyNodeRef::FStringLiteralElement(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprStringLiteral(_) | AnyNodeRef::ExprBytesLiteral(_) @@ -5765,7 +5831,8 @@ impl<'a> AnyNodeRef<'a> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) - | AnyNodeRef::ExprFormattedValue(_) + | AnyNodeRef::FStringExpressionElement(_) + | AnyNodeRef::FStringLiteralElement(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprStringLiteral(_) | AnyNodeRef::ExprBytesLiteral(_) @@ -5853,7 +5920,8 @@ impl<'a> AnyNodeRef<'a> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) - | AnyNodeRef::ExprFormattedValue(_) + | AnyNodeRef::FStringExpressionElement(_) + | AnyNodeRef::FStringLiteralElement(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprStringLiteral(_) | AnyNodeRef::ExprBytesLiteral(_) @@ -5975,7 +6043,8 @@ impl<'a> AnyNodeRef<'a> { AnyNodeRef::ExprYieldFrom(node) => node.visit_preorder(visitor), AnyNodeRef::ExprCompare(node) => node.visit_preorder(visitor), AnyNodeRef::ExprCall(node) => node.visit_preorder(visitor), - AnyNodeRef::ExprFormattedValue(node) => node.visit_preorder(visitor), + AnyNodeRef::FStringExpressionElement(node) => node.visit_preorder(visitor), + AnyNodeRef::FStringLiteralElement(node) => node.visit_preorder(visitor), AnyNodeRef::ExprFString(node) => node.visit_preorder(visitor), AnyNodeRef::ExprStringLiteral(node) => node.visit_preorder(visitor), AnyNodeRef::ExprBytesLiteral(node) => node.visit_preorder(visitor), @@ -6354,9 +6423,15 @@ impl<'a> From<&'a ast::ExprCall> for AnyNodeRef<'a> { } } -impl<'a> From<&'a ast::ExprFormattedValue> for AnyNodeRef<'a> { - fn from(node: &'a ast::ExprFormattedValue) -> Self { - AnyNodeRef::ExprFormattedValue(node) +impl<'a> From<&'a ast::FStringExpressionElement> for AnyNodeRef<'a> { + fn from(node: &'a ast::FStringExpressionElement) -> Self { + AnyNodeRef::FStringExpressionElement(node) + } +} + +impl<'a> From<&'a ast::FStringLiteralElement> for AnyNodeRef<'a> { + fn from(node: &'a ast::FStringLiteralElement) -> Self { + AnyNodeRef::FStringLiteralElement(node) } } @@ -6615,7 +6690,6 @@ impl<'a> From<&'a Expr> for AnyNodeRef<'a> { Expr::YieldFrom(node) => AnyNodeRef::ExprYieldFrom(node), Expr::Compare(node) => AnyNodeRef::ExprCompare(node), Expr::Call(node) => AnyNodeRef::ExprCall(node), - Expr::FormattedValue(node) => AnyNodeRef::ExprFormattedValue(node), Expr::FString(node) => AnyNodeRef::ExprFString(node), Expr::StringLiteral(node) => AnyNodeRef::ExprStringLiteral(node), Expr::BytesLiteral(node) => AnyNodeRef::ExprBytesLiteral(node), @@ -6644,6 +6718,15 @@ impl<'a> From<&'a Mod> for AnyNodeRef<'a> { } } +impl<'a> From<&'a FStringElement> for AnyNodeRef<'a> { + fn from(element: &'a FStringElement) -> Self { + match element { + FStringElement::Expression(node) => AnyNodeRef::FStringExpressionElement(node), + FStringElement::Literal(node) => AnyNodeRef::FStringLiteralElement(node), + } + } +} + impl<'a> From<&'a Pattern> for AnyNodeRef<'a> { fn from(pattern: &'a Pattern) -> Self { match pattern { @@ -6772,7 +6855,8 @@ impl Ranged for AnyNodeRef<'_> { AnyNodeRef::ExprYieldFrom(node) => node.range(), AnyNodeRef::ExprCompare(node) => node.range(), AnyNodeRef::ExprCall(node) => node.range(), - AnyNodeRef::ExprFormattedValue(node) => node.range(), + AnyNodeRef::FStringExpressionElement(node) => node.range(), + AnyNodeRef::FStringLiteralElement(node) => node.range(), AnyNodeRef::ExprFString(node) => node.range(), AnyNodeRef::ExprStringLiteral(node) => node.range(), AnyNodeRef::ExprBytesLiteral(node) => node.range(), @@ -6869,7 +6953,8 @@ pub enum NodeKind { ExprYieldFrom, ExprCompare, ExprCall, - ExprFormattedValue, + FStringExpressionElement, + FStringLiteralElement, ExprFString, ExprStringLiteral, ExprBytesLiteral, diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index 32ddbeef59a46..964742af492e7 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -590,8 +590,6 @@ pub enum Expr { Compare(ExprCompare), #[is(name = "call_expr")] Call(ExprCall), - #[is(name = "formatted_value_expr")] - FormattedValue(ExprFormattedValue), #[is(name = "f_string_expr")] FString(ExprFString), #[is(name = "string_literal_expr")] @@ -919,19 +917,51 @@ impl From for Expr { } } +#[derive(Clone, Debug, PartialEq)] +pub struct FStringFormatSpec { + pub range: TextRange, + pub elements: Vec, +} + +impl Ranged for FStringFormatSpec { + fn range(&self) -> TextRange { + self.range + } +} + /// See also [FormattedValue](https://docs.python.org/3/library/ast.html#ast.FormattedValue) #[derive(Clone, Debug, PartialEq)] -pub struct ExprFormattedValue { +pub struct FStringExpressionElement { pub range: TextRange, - pub value: Box, + pub expression: Box, pub debug_text: Option, pub conversion: ConversionFlag, - pub format_spec: Option>, + pub format_spec: Option>, +} + +impl Ranged for FStringExpressionElement { + fn range(&self) -> TextRange { + self.range + } } -impl From for Expr { - fn from(payload: ExprFormattedValue) -> Self { - Expr::FormattedValue(payload) +#[derive(Clone, Debug, PartialEq)] +pub struct FStringLiteralElement { + pub range: TextRange, + pub value: String, +} + +impl Ranged for FStringLiteralElement { + fn range(&self) -> TextRange { + self.range + } +} + +impl Deref for FStringLiteralElement { + type Target = str; + + fn deref(&self) -> &Self::Target { + self.value.as_str() } } @@ -1064,7 +1094,7 @@ impl FStringValue { self.parts().filter_map(|part| part.as_f_string()) } - /// Returns an iterator over all the f-string elements contained in this value. + /// Returns an iterator over all the [`FStringElement`] contained in this value. /// /// An f-string element is what makes up an [`FString`] i.e., it is either a /// string literal or an expression. In the following example, @@ -1075,8 +1105,8 @@ impl FStringValue { /// /// The f-string elements returned would be string literal (`"bar "`), /// expression (`x`) and string literal (`"qux"`). - pub fn elements(&self) -> impl Iterator { - self.f_strings().flat_map(|fstring| fstring.values.iter()) + pub fn elements(&self) -> impl Iterator { + self.f_strings().flat_map(|fstring| fstring.elements.iter()) } } @@ -1113,7 +1143,7 @@ impl Ranged for FStringPart { #[derive(Clone, Debug, PartialEq)] pub struct FString { pub range: TextRange, - pub values: Vec, + pub elements: Vec, } impl Ranged for FString { @@ -1132,6 +1162,21 @@ impl From for Expr { } } +#[derive(Clone, Debug, PartialEq, is_macro::Is)] +pub enum FStringElement { + Literal(FStringLiteralElement), + Expression(FStringExpressionElement), +} + +impl Ranged for FStringElement { + fn range(&self) -> TextRange { + match self { + FStringElement::Literal(node) => node.range(), + FStringElement::Expression(node) => node.range(), + } + } +} + /// An AST node that represents either a single string literal or an implicitly /// concatenated string literals. #[derive(Clone, Debug, Default, PartialEq)] @@ -3483,11 +3528,6 @@ impl Ranged for crate::nodes::ExprCall { self.range } } -impl Ranged for crate::nodes::ExprFormattedValue { - fn range(&self) -> TextRange { - self.range - } -} impl Ranged for crate::nodes::ExprFString { fn range(&self) -> TextRange { self.range @@ -3553,7 +3593,6 @@ impl Ranged for crate::Expr { Self::YieldFrom(node) => node.range(), Self::Compare(node) => node.range(), Self::Call(node) => node.range(), - Self::FormattedValue(node) => node.range(), Self::FString(node) => node.range(), Self::StringLiteral(node) => node.range(), Self::BytesLiteral(node) => node.range(), diff --git a/crates/ruff_python_ast/src/relocate.rs b/crates/ruff_python_ast/src/relocate.rs index 19a126b3567ac..5c189fb4c6a73 100644 --- a/crates/ruff_python_ast/src/relocate.rs +++ b/crates/ruff_python_ast/src/relocate.rs @@ -68,9 +68,6 @@ impl Transformer for Relocator { Expr::Call(nodes::ExprCall { range, .. }) => { *range = self.range; } - Expr::FormattedValue(nodes::ExprFormattedValue { range, .. }) => { - *range = self.range; - } Expr::FString(nodes::ExprFString { range, .. }) => { *range = self.range; } diff --git a/crates/ruff_python_ast/src/visitor.rs b/crates/ruff_python_ast/src/visitor.rs index 3a0781f0724b9..15a9985b5cf7b 100644 --- a/crates/ruff_python_ast/src/visitor.rs +++ b/crates/ruff_python_ast/src/visitor.rs @@ -5,9 +5,9 @@ pub mod transformer; use crate::{ self as ast, Alias, Arguments, BoolOp, BytesLiteral, CmpOp, Comprehension, Decorator, - ElifElseClause, ExceptHandler, Expr, ExprContext, FString, FStringPart, Keyword, MatchCase, - Operator, Parameter, Parameters, Pattern, PatternArguments, PatternKeyword, Stmt, - StringLiteral, TypeParam, TypeParamTypeVar, TypeParams, UnaryOp, WithItem, + ElifElseClause, ExceptHandler, Expr, ExprContext, FString, FStringElement, FStringPart, + Keyword, MatchCase, Operator, Parameter, Parameters, Pattern, PatternArguments, PatternKeyword, + Stmt, StringLiteral, TypeParam, TypeParamTypeVar, TypeParams, UnaryOp, WithItem, }; /// A trait for AST visitors. Visits all nodes in the AST recursively in evaluation-order. @@ -53,9 +53,6 @@ pub trait Visitor<'a> { fn visit_except_handler(&mut self, except_handler: &'a ExceptHandler) { walk_except_handler(self, except_handler); } - fn visit_format_spec(&mut self, format_spec: &'a Expr) { - walk_format_spec(self, format_spec); - } fn visit_arguments(&mut self, arguments: &'a Arguments) { walk_arguments(self, arguments); } @@ -101,6 +98,9 @@ pub trait Visitor<'a> { fn visit_f_string(&mut self, f_string: &'a FString) { walk_f_string(self, f_string); } + fn visit_f_string_element(&mut self, f_string_element: &'a FStringElement) { + walk_f_string_element(self, f_string_element); + } fn visit_string_literal(&mut self, string_literal: &'a StringLiteral) { walk_string_literal(self, string_literal); } @@ -476,14 +476,6 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) { visitor.visit_expr(func); visitor.visit_arguments(arguments); } - Expr::FormattedValue(ast::ExprFormattedValue { - value, format_spec, .. - }) => { - visitor.visit_expr(value); - if let Some(expr) = format_spec { - visitor.visit_format_spec(expr); - } - } Expr::FString(ast::ExprFString { value, .. }) => { for part in value.parts() { match part { @@ -598,16 +590,6 @@ pub fn walk_except_handler<'a, V: Visitor<'a> + ?Sized>( } } -pub fn walk_f_string<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, f_string: &'a FString) { - for expr in &f_string.values { - visitor.visit_expr(expr); - } -} - -pub fn walk_format_spec<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, format_spec: &'a Expr) { - visitor.visit_expr(format_spec); -} - pub fn walk_arguments<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, arguments: &'a Arguments) { // Note that the there might be keywords before the last arg, e.g. in // f(*args, a=2, *args2, **kwargs)`, but we follow Python in evaluating first `args` and then @@ -757,6 +739,31 @@ pub fn walk_pattern_keyword<'a, V: Visitor<'a> + ?Sized>( visitor.visit_pattern(&pattern_keyword.pattern); } +pub fn walk_f_string<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, f_string: &'a FString) { + for f_string_element in &f_string.elements { + visitor.visit_f_string_element(f_string_element); + } +} + +pub fn walk_f_string_element<'a, V: Visitor<'a> + ?Sized>( + visitor: &mut V, + f_string_element: &'a FStringElement, +) { + if let ast::FStringElement::Expression(ast::FStringExpressionElement { + expression, + format_spec, + .. + }) = f_string_element + { + visitor.visit_expr(expression); + if let Some(format_spec) = format_spec { + for spec_element in &format_spec.elements { + visitor.visit_f_string_element(spec_element); + } + } + } +} + pub fn walk_expr_context<'a, V: Visitor<'a> + ?Sized>( _visitor: &V, _expr_context: &'a ExprContext, diff --git a/crates/ruff_python_ast/src/visitor/preorder.rs b/crates/ruff_python_ast/src/visitor/preorder.rs index ad5cbceccc65b..d560cb5fb0973 100644 --- a/crates/ruff_python_ast/src/visitor/preorder.rs +++ b/crates/ruff_python_ast/src/visitor/preorder.rs @@ -1,6 +1,6 @@ use crate::{ Alias, Arguments, BoolOp, BytesLiteral, CmpOp, Comprehension, Decorator, ElifElseClause, - ExceptHandler, Expr, FString, Keyword, MatchCase, Mod, Operator, Parameter, + ExceptHandler, Expr, FString, FStringElement, Keyword, MatchCase, Mod, Operator, Parameter, ParameterWithDefault, Parameters, Pattern, PatternArguments, PatternKeyword, Singleton, Stmt, StringLiteral, TypeParam, TypeParams, UnaryOp, WithItem, }; @@ -74,11 +74,6 @@ pub trait PreorderVisitor<'a> { walk_except_handler(self, except_handler); } - #[inline] - fn visit_format_spec(&mut self, format_spec: &'a Expr) { - walk_format_spec(self, format_spec); - } - #[inline] fn visit_arguments(&mut self, arguments: &'a Arguments) { walk_arguments(self, arguments); @@ -158,6 +153,11 @@ pub trait PreorderVisitor<'a> { walk_f_string(self, f_string); } + #[inline] + fn visit_f_string_element(&mut self, f_string_element: &'a FStringElement) { + walk_f_string_element(self, f_string_element); + } + #[inline] fn visit_string_literal(&mut self, string_literal: &'a StringLiteral) { walk_string_literal(self, string_literal); @@ -289,7 +289,6 @@ where Expr::YieldFrom(expr) => expr.visit_preorder(visitor), Expr::Compare(expr) => expr.visit_preorder(visitor), Expr::Call(expr) => expr.visit_preorder(visitor), - Expr::FormattedValue(expr) => expr.visit_preorder(visitor), Expr::FString(expr) => expr.visit_preorder(visitor), Expr::StringLiteral(expr) => expr.visit_preorder(visitor), Expr::BytesLiteral(expr) => expr.visit_preorder(visitor), @@ -518,6 +517,20 @@ where visitor.leave_node(node); } +pub fn walk_f_string_element<'a, V: PreorderVisitor<'a> + ?Sized>( + visitor: &mut V, + f_string_element: &'a FStringElement, +) { + let node = AnyNodeRef::from(f_string_element); + if visitor.enter_node(node).is_traverse() { + match f_string_element { + FStringElement::Expression(element) => element.visit_preorder(visitor), + FStringElement::Literal(element) => element.visit_preorder(visitor), + } + } + visitor.leave_node(node); +} + pub fn walk_bool_op<'a, V>(_visitor: &mut V, _bool_op: &'a BoolOp) where V: PreorderVisitor<'a> + ?Sized, diff --git a/crates/ruff_python_ast/src/visitor/transformer.rs b/crates/ruff_python_ast/src/visitor/transformer.rs index b193aa6c299f0..36ee7687f33c0 100644 --- a/crates/ruff_python_ast/src/visitor/transformer.rs +++ b/crates/ruff_python_ast/src/visitor/transformer.rs @@ -1,8 +1,8 @@ use crate::{ self as ast, Alias, Arguments, BoolOp, BytesLiteral, CmpOp, Comprehension, Decorator, - ElifElseClause, ExceptHandler, Expr, ExprContext, FString, Keyword, MatchCase, Operator, - Parameter, Parameters, Pattern, PatternArguments, PatternKeyword, Stmt, StringLiteral, - TypeParam, TypeParamTypeVar, TypeParams, UnaryOp, WithItem, + ElifElseClause, ExceptHandler, Expr, ExprContext, FString, FStringElement, Keyword, MatchCase, + Operator, Parameter, Parameters, Pattern, PatternArguments, PatternKeyword, Stmt, + StringLiteral, TypeParam, TypeParamTypeVar, TypeParams, UnaryOp, WithItem, }; /// A trait for transforming ASTs. Visits all nodes in the AST recursively in evaluation-order. @@ -40,9 +40,6 @@ pub trait Transformer { fn visit_except_handler(&self, except_handler: &mut ExceptHandler) { walk_except_handler(self, except_handler); } - fn visit_format_spec(&self, format_spec: &mut Expr) { - walk_format_spec(self, format_spec); - } fn visit_arguments(&self, arguments: &mut Arguments) { walk_arguments(self, arguments); } @@ -88,6 +85,9 @@ pub trait Transformer { fn visit_f_string(&self, f_string: &mut FString) { walk_f_string(self, f_string); } + fn visit_f_string_element(&self, f_string_element: &mut FStringElement) { + walk_f_string_element(self, f_string_element); + } fn visit_string_literal(&self, string_literal: &mut StringLiteral) { walk_string_literal(self, string_literal); } @@ -463,14 +463,6 @@ pub fn walk_expr(visitor: &V, expr: &mut Expr) { visitor.visit_expr(func); visitor.visit_arguments(arguments); } - Expr::FormattedValue(ast::ExprFormattedValue { - value, format_spec, .. - }) => { - visitor.visit_expr(value); - if let Some(expr) = format_spec { - visitor.visit_format_spec(expr); - } - } Expr::FString(ast::ExprFString { value, .. }) => { for f_string_part in value.parts_mut() { match f_string_part { @@ -584,16 +576,6 @@ pub fn walk_except_handler( } } -pub fn walk_f_string(visitor: &V, f_string: &mut FString) { - for expr in &mut f_string.values { - visitor.visit_expr(expr); - } -} - -pub fn walk_format_spec(visitor: &V, format_spec: &mut Expr) { - visitor.visit_expr(format_spec); -} - pub fn walk_arguments(visitor: &V, arguments: &mut Arguments) { // Note that the there might be keywords before the last arg, e.g. in // f(*args, a=2, *args2, **kwargs)`, but we follow Python in evaluating first `args` and then @@ -743,6 +725,31 @@ pub fn walk_pattern_keyword( visitor.visit_pattern(&mut pattern_keyword.pattern); } +pub fn walk_f_string(visitor: &V, f_string: &mut FString) { + for element in &mut f_string.elements { + visitor.visit_f_string_element(element); + } +} + +pub fn walk_f_string_element( + visitor: &V, + f_string_element: &mut FStringElement, +) { + if let ast::FStringElement::Expression(ast::FStringExpressionElement { + expression, + format_spec, + .. + }) = f_string_element + { + visitor.visit_expr(expression); + if let Some(format_spec) = format_spec { + for spec_element in &mut format_spec.elements { + visitor.visit_f_string_element(spec_element); + } + } + } +} + pub fn walk_expr_context(_visitor: &V, _expr_context: &mut ExprContext) {} pub fn walk_bool_op(_visitor: &V, _bool_op: &mut BoolOp) {} diff --git a/crates/ruff_python_ast/tests/snapshots/preorder__f_strings.snap b/crates/ruff_python_ast/tests/snapshots/preorder__f_strings.snap index 613106d59e320..043c58064b48e 100644 --- a/crates/ruff_python_ast/tests/snapshots/preorder__f_strings.snap +++ b/crates/ruff_python_ast/tests/snapshots/preorder__f_strings.snap @@ -7,19 +7,12 @@ expression: trace - ExprFString - StringLiteral - FString - - ExprStringLiteral - - StringLiteral - - ExprFormattedValue + - FStringLiteralElement + - FStringExpressionElement - ExprName - - ExprFString - - ExprFString - - FString - - ExprStringLiteral - - StringLiteral - - ExprFormattedValue - - ExprName - - ExprStringLiteral - - StringLiteral - - ExprStringLiteral - - StringLiteral + - FStringLiteralElement + - FStringExpressionElement + - ExprName + - FStringLiteralElement + - FStringLiteralElement diff --git a/crates/ruff_python_ast/tests/snapshots/visitor__f_strings.snap b/crates/ruff_python_ast/tests/snapshots/visitor__f_strings.snap index 195de7cd4b40a..a5c8a8b905927 100644 --- a/crates/ruff_python_ast/tests/snapshots/visitor__f_strings.snap +++ b/crates/ruff_python_ast/tests/snapshots/visitor__f_strings.snap @@ -5,17 +5,13 @@ expression: trace - StmtExpr - ExprFString - StringLiteral - - ExprStringLiteral - - StringLiteral - - ExprFormattedValue - - ExprName - - ExprFString - - ExprStringLiteral - - StringLiteral - - ExprFormattedValue + - FString + - FStringLiteralElement + - FStringExpressionElement + - ExprName + - FStringLiteralElement + - FStringExpressionElement - ExprName - - ExprStringLiteral - - StringLiteral - - ExprStringLiteral - - StringLiteral + - FStringLiteralElement + - FStringLiteralElement diff --git a/crates/ruff_python_ast/tests/visitor.rs b/crates/ruff_python_ast/tests/visitor.rs index 3e4a32ebdd126..46af0903b6fcf 100644 --- a/crates/ruff_python_ast/tests/visitor.rs +++ b/crates/ruff_python_ast/tests/visitor.rs @@ -7,13 +7,15 @@ use ruff_python_parser::{parse_tokens, Mode}; use ruff_python_ast::visitor::{ walk_alias, walk_bytes_literal, walk_comprehension, walk_except_handler, walk_expr, - walk_keyword, walk_match_case, walk_parameter, walk_parameters, walk_pattern, walk_stmt, - walk_string_literal, walk_type_param, walk_with_item, Visitor, + walk_f_string, walk_f_string_element, walk_keyword, walk_match_case, walk_parameter, + walk_parameters, walk_pattern, walk_stmt, walk_string_literal, walk_type_param, walk_with_item, + Visitor, }; use ruff_python_ast::AnyNodeRef; use ruff_python_ast::{ - Alias, BoolOp, BytesLiteral, CmpOp, Comprehension, ExceptHandler, Expr, Keyword, MatchCase, - Operator, Parameter, Parameters, Pattern, Stmt, StringLiteral, TypeParam, UnaryOp, WithItem, + Alias, BoolOp, BytesLiteral, CmpOp, Comprehension, ExceptHandler, Expr, FString, + FStringElement, Keyword, MatchCase, Operator, Parameter, Parameters, Pattern, Stmt, + StringLiteral, TypeParam, UnaryOp, WithItem, }; #[test] @@ -255,12 +257,6 @@ impl Visitor<'_> for RecordVisitor { self.exit_node(); } - fn visit_format_spec(&mut self, format_spec: &Expr) { - self.enter_node(format_spec); - walk_expr(self, format_spec); - self.exit_node(); - } - fn visit_parameters(&mut self, parameters: &Parameters) { self.enter_node(parameters); walk_parameters(self, parameters); @@ -320,4 +316,16 @@ impl Visitor<'_> for RecordVisitor { walk_bytes_literal(self, bytes_literal); self.exit_node(); } + + fn visit_f_string(&mut self, f_string: &FString) { + self.enter_node(f_string); + walk_f_string(self, f_string); + self.exit_node(); + } + + fn visit_f_string_element(&mut self, f_string_element: &FStringElement) { + self.enter_node(f_string_element); + walk_f_string_element(self, f_string_element); + self.exit_node(); + } } diff --git a/crates/ruff_python_codegen/src/generator.rs b/crates/ruff_python_codegen/src/generator.rs index cb1a8fedabf5d..9baacbdbd3ac0 100644 --- a/crates/ruff_python_codegen/src/generator.rs +++ b/crates/ruff_python_codegen/src/generator.rs @@ -1069,18 +1069,6 @@ impl<'a> Generator<'a> { } self.p(")"); } - Expr::FormattedValue(ast::ExprFormattedValue { - value, - debug_text, - conversion, - format_spec, - range: _, - }) => self.unparse_formatted( - value, - debug_text.as_ref(), - *conversion, - format_spec.as_deref(), - ), Expr::FString(ast::ExprFString { value, .. }) => { self.unparse_f_string_value(value, false); } @@ -1300,24 +1288,24 @@ impl<'a> Generator<'a> { self.unparse_string_literal(string_literal); } ast::FStringPart::FString(f_string) => { - self.unparse_f_string(&f_string.values, is_spec); + self.unparse_f_string(&f_string.elements, is_spec); } } } } - fn unparse_f_string_body(&mut self, values: &[Expr], is_spec: bool) { + fn unparse_f_string_body(&mut self, values: &[ast::FStringElement]) { for value in values { - self.unparse_f_string_elem(value, is_spec); + self.unparse_f_string_element(value); } } - fn unparse_formatted( + fn unparse_f_string_expression_element( &mut self, val: &Expr, debug_text: Option<&DebugText>, conversion: ConversionFlag, - spec: Option<&Expr>, + spec: Option<&ast::FStringFormatSpec>, ) { let mut generator = Generator::new(self.indent, self.quote, self.line_ending); generator.unparse_expr(val, precedence::FORMATTED_VALUE); @@ -1347,44 +1335,40 @@ impl<'a> Generator<'a> { if let Some(spec) = spec { self.p(":"); - self.unparse_f_string_elem(spec, true); + self.unparse_f_string(&spec.elements, true); } self.p("}"); } - fn unparse_f_string_elem(&mut self, expr: &Expr, is_spec: bool) { - match expr { - Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { - self.unparse_f_string_literal(value.to_str()); + fn unparse_f_string_element(&mut self, element: &ast::FStringElement) { + match element { + ast::FStringElement::Literal(ast::FStringLiteralElement { value, .. }) => { + self.unparse_f_string_literal_element(value); } - Expr::FString(ast::ExprFString { value, .. }) => { - self.unparse_f_string_value(value, is_spec); - } - Expr::FormattedValue(ast::ExprFormattedValue { - value, + ast::FStringElement::Expression(ast::FStringExpressionElement { + expression, debug_text, conversion, format_spec, range: _, - }) => self.unparse_formatted( - value, + }) => self.unparse_f_string_expression_element( + expression, debug_text.as_ref(), *conversion, format_spec.as_deref(), ), - _ => unreachable!(), } } - fn unparse_f_string_literal(&mut self, s: &str) { + fn unparse_f_string_literal_element(&mut self, s: &str) { let s = s.replace('{', "{{").replace('}', "}}"); self.p(&s); } - fn unparse_f_string(&mut self, values: &[Expr], is_spec: bool) { + fn unparse_f_string(&mut self, values: &[ast::FStringElement], is_spec: bool) { if is_spec { - self.unparse_f_string_body(values, is_spec); + self.unparse_f_string_body(values); } else { self.p("f"); let mut generator = Generator::new( @@ -1395,7 +1379,7 @@ impl<'a> Generator<'a> { }, self.line_ending, ); - generator.unparse_f_string_body(values, is_spec); + generator.unparse_f_string_body(values); let body = &generator.buffer; self.p_str_repr(body); } @@ -1716,7 +1700,7 @@ class Foo: } #[test] - fn self_documenting_f_string() { + fn self_documenting_fstring() { assert_round_trip!(r#"f"{ chr(65) = }""#); assert_round_trip!(r#"f"{ chr(65) = !s}""#); assert_round_trip!(r#"f"{ chr(65) = !r}""#); diff --git a/crates/ruff_python_formatter/generate.py b/crates/ruff_python_formatter/generate.py index 52c256dd17767..16fddd11fbd7e 100755 --- a/crates/ruff_python_formatter/generate.py +++ b/crates/ruff_python_formatter/generate.py @@ -30,10 +30,14 @@ def rustfmt(code: str) -> str: node_lines = ( nodes_file.split("pub enum AnyNode {")[1].split("}")[0].strip().splitlines() ) -nodes = [ - node_line.split("(")[1].split(")")[0].split("::")[-1].split("<")[0] - for node_line in node_lines -] +nodes = [] +for node_line in node_lines: + node = node_line.split("(")[1].split(")")[0].split("::")[-1].split("<")[0] + # These nodes aren't used in the formatter as the formatting of them is handled + # in one of the other nodes containing them. + if node in ("FStringLiteralElement", "FStringExpressionElement"): + continue + nodes.append(node) print(nodes) # %% diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index 1fb97009e4b64..435c39dedcc25 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -36,7 +36,6 @@ pub(crate) mod expr_dict; pub(crate) mod expr_dict_comp; pub(crate) mod expr_ellipsis_literal; pub(crate) mod expr_f_string; -pub(crate) mod expr_formatted_value; pub(crate) mod expr_generator_exp; pub(crate) mod expr_if_exp; pub(crate) mod expr_ipy_escape_command; @@ -97,7 +96,6 @@ impl FormatRule> for FormatExpr { Expr::YieldFrom(expr) => expr.format().fmt(f), Expr::Compare(expr) => expr.format().fmt(f), Expr::Call(expr) => expr.format().fmt(f), - Expr::FormattedValue(expr) => expr.format().fmt(f), Expr::FString(expr) => expr.format().fmt(f), Expr::StringLiteral(expr) => expr.format().fmt(f), Expr::BytesLiteral(expr) => expr.format().fmt(f), @@ -286,7 +284,6 @@ fn format_with_parentheses_comments( Expr::YieldFrom(expr) => FormatNodeRule::fmt_fields(expr.format().rule(), expr, f), Expr::Compare(expr) => FormatNodeRule::fmt_fields(expr.format().rule(), expr, f), Expr::Call(expr) => FormatNodeRule::fmt_fields(expr.format().rule(), expr, f), - Expr::FormattedValue(expr) => FormatNodeRule::fmt_fields(expr.format().rule(), expr, f), Expr::FString(expr) => FormatNodeRule::fmt_fields(expr.format().rule(), expr, f), Expr::StringLiteral(expr) => FormatNodeRule::fmt_fields(expr.format().rule(), expr, f), Expr::BytesLiteral(expr) => FormatNodeRule::fmt_fields(expr.format().rule(), expr, f), @@ -488,7 +485,6 @@ impl NeedsParentheses for Expr { Expr::YieldFrom(expr) => expr.needs_parentheses(parent, context), Expr::Compare(expr) => expr.needs_parentheses(parent, context), Expr::Call(expr) => expr.needs_parentheses(parent, context), - Expr::FormattedValue(expr) => expr.needs_parentheses(parent, context), Expr::FString(expr) => expr.needs_parentheses(parent, context), Expr::StringLiteral(expr) => expr.needs_parentheses(parent, context), Expr::BytesLiteral(expr) => expr.needs_parentheses(parent, context), @@ -746,7 +742,6 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> { Expr::Tuple(_) | Expr::NamedExpr(_) | Expr::GeneratorExp(_) - | Expr::FormattedValue(_) | Expr::FString(_) | Expr::StringLiteral(_) | Expr::BytesLiteral(_) @@ -1098,7 +1093,6 @@ pub(crate) fn is_expression_huggable(expr: &Expr, context: &PyFormatContext) -> | Expr::YieldFrom(_) | Expr::Compare(_) | Expr::Call(_) - | Expr::FormattedValue(_) | Expr::FString(_) | Expr::Attribute(_) | Expr::Subscript(_) diff --git a/crates/ruff_python_formatter/src/expression/string/mod.rs b/crates/ruff_python_formatter/src/expression/string/mod.rs index c7e896daf2c90..260f2da239d32 100644 --- a/crates/ruff_python_formatter/src/expression/string/mod.rs +++ b/crates/ruff_python_formatter/src/expression/string/mod.rs @@ -52,8 +52,11 @@ impl<'a> AnyString<'a> { .trim_start_matches(|c| c != '"' && c != '\''); let triple_quoted = unprefixed.starts_with(r#"""""#) || unprefixed.starts_with(r"'''"); - if f_string.value.elements().any(|value| match value { - Expr::FormattedValue(ast::ExprFormattedValue { range, .. }) => { + if f_string.value.elements().any(|element| match element { + ast::FStringElement::Expression(ast::FStringExpressionElement { + range, + .. + }) => { let string_content = locator.slice(*range); if triple_quoted { string_content.contains(r#"""""#) || string_content.contains("'''") @@ -61,7 +64,7 @@ impl<'a> AnyString<'a> { string_content.contains(['"', '\'']) } } - _ => false, + ast::FStringElement::Literal(_) => false, }) { Quoting::Preserve } else { diff --git a/crates/ruff_python_formatter/src/generated.rs b/crates/ruff_python_formatter/src/generated.rs index 30b5bb122ae9e..5b01cd16f842b 100644 --- a/crates/ruff_python_formatter/src/generated.rs +++ b/crates/ruff_python_formatter/src/generated.rs @@ -1534,42 +1534,6 @@ impl<'ast> IntoFormat> for ast::ExprCall { } } -impl FormatRule> - for crate::expression::expr_formatted_value::FormatExprFormattedValue -{ - #[inline] - fn fmt(&self, node: &ast::ExprFormattedValue, f: &mut PyFormatter) -> FormatResult<()> { - FormatNodeRule::::fmt(self, node, f) - } -} -impl<'ast> AsFormat> for ast::ExprFormattedValue { - type Format<'a> = FormatRefWithRule< - 'a, - ast::ExprFormattedValue, - crate::expression::expr_formatted_value::FormatExprFormattedValue, - PyFormatContext<'ast>, - >; - fn format(&self) -> Self::Format<'_> { - FormatRefWithRule::new( - self, - crate::expression::expr_formatted_value::FormatExprFormattedValue::default(), - ) - } -} -impl<'ast> IntoFormat> for ast::ExprFormattedValue { - type Format = FormatOwnedWithRule< - ast::ExprFormattedValue, - crate::expression::expr_formatted_value::FormatExprFormattedValue, - PyFormatContext<'ast>, - >; - fn into_format(self) -> Self::Format { - FormatOwnedWithRule::new( - self, - crate::expression::expr_formatted_value::FormatExprFormattedValue::default(), - ) - } -} - impl FormatRule> for crate::expression::expr_f_string::FormatExprFString { diff --git a/crates/ruff_python_parser/src/invalid.rs b/crates/ruff_python_parser/src/invalid.rs index 8424567113f73..91f81bd5eac48 100644 --- a/crates/ruff_python_parser/src/invalid.rs +++ b/crates/ruff_python_parser/src/invalid.rs @@ -59,7 +59,6 @@ pub(crate) fn assignment_target(target: &Expr) -> Result<(), LexicalError> { YieldFrom(ref e) => Err(err(e.range.start())), Compare(ref e) => Err(err(e.range.start())), Call(ref e) => Err(err(e.range.start())), - FormattedValue(ref e) => Err(err(e.range.start())), // FString is recursive, but all its forms are invalid as an // assignment target, so we can reject it without exploring it. FString(ref e) => Err(err(e.range.start())), diff --git a/crates/ruff_python_parser/src/python.lalrpop b/crates/ruff_python_parser/src/python.lalrpop index 46eef9cf961f3..aa87fcd72d4f0 100644 --- a/crates/ruff_python_parser/src/python.lalrpop +++ b/crates/ruff_python_parser/src/python.lalrpop @@ -11,7 +11,7 @@ use crate::{ lexer::{LexicalError, LexicalErrorType}, function::{ArgumentList, parse_arguments, validate_pos_params, validate_arguments}, context::set_context, - string::{StringType, concatenated_strings, parse_fstring_middle, parse_string_literal}, + string::{StringType, concatenated_strings, parse_fstring_literal_element, parse_string_literal}, token::{self, StringKind}, invalid, }; @@ -1611,23 +1611,23 @@ StringLiteral: StringType = { }; FStringExpr: StringType = { - FStringStart FStringEnd => { + FStringStart FStringEnd => { StringType::FString(ast::FString { - values, + elements, range: (location..end_location).into() }) } }; -FStringMiddlePattern: ast::Expr = { +FStringMiddlePattern: ast::FStringElement = { FStringReplacementField, =>? { let (source, is_raw) = fstring_middle; - Ok(parse_fstring_middle(&source, is_raw, (location..end_location).into())?) + Ok(parse_fstring_literal_element(&source, is_raw, (location..end_location).into())?) } }; -FStringReplacementField: ast::Expr = { +FStringReplacementField: ast::FStringElement = { "{" "}" =>? { if value.expr.is_lambda_expr() && !value.is_parenthesized() { return Err(LexicalError { @@ -1651,30 +1651,27 @@ FStringReplacementField: ast::Expr = { } }); Ok( - ast::ExprFormattedValue { - value: Box::new(value.into()), + ast::FStringElement::Expression(ast::FStringExpressionElement { + expression: Box::new(value.into()), debug_text, conversion: conversion.map_or(ast::ConversionFlag::None, |(_, conversion_flag)| { conversion_flag }), format_spec: format_spec.map(Box::new), range: (location..end_location).into(), - } - .into() + }) ) } }; -FStringFormatSpecSuffix: ast::Expr = { +FStringFormatSpecSuffix: ast::FStringFormatSpec = { ":" => format_spec }; -FStringFormatSpec: ast::Expr = { - => { - ast::FString { - values, - range: (location..end_location).into() - }.into() +FStringFormatSpec: ast::FStringFormatSpec = { + => ast::FStringFormatSpec { + elements, + range: (location..end_location).into(), }, }; diff --git a/crates/ruff_python_parser/src/python.rs b/crates/ruff_python_parser/src/python.rs index 3e04daf83a8b7..5771d7099f737 100644 --- a/crates/ruff_python_parser/src/python.rs +++ b/crates/ruff_python_parser/src/python.rs @@ -1,5 +1,5 @@ // auto-generated: "lalrpop 0.20.0" -// sha3: bf21214efe22cee1db2a8fe27c1793b02afee5017a8474a3543f4d8526c1c0ec +// sha3: 031689e389556292d9dbd8a1b1ff8ca29bac76d83f1b345630481d620b89e1c2 use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; use ruff_python_ast::{self as ast, Int, IpyEscapeKind}; use crate::{ @@ -8,7 +8,7 @@ use crate::{ lexer::{LexicalError, LexicalErrorType}, function::{ArgumentList, parse_arguments, validate_pos_params, validate_arguments}, context::set_context, - string::{StringType, concatenated_strings, parse_fstring_middle, parse_string_literal}, + string::{StringType, concatenated_strings, parse_fstring_literal_element, parse_string_literal}, token::{self, StringKind}, invalid, }; @@ -32,7 +32,7 @@ mod __parse__Top { lexer::{LexicalError, LexicalErrorType}, function::{ArgumentList, parse_arguments, validate_pos_params, validate_arguments}, context::set_context, - string::{StringType, concatenated_strings, parse_fstring_middle, parse_string_literal}, + string::{StringType, concatenated_strings, parse_fstring_literal_element, parse_string_literal}, token::{self, StringKind}, invalid, }; @@ -117,38 +117,41 @@ mod __parse__Top { Variant67((TextSize, ast::ConversionFlag)), Variant68(core::option::Option<(TextSize, ast::ConversionFlag)>), Variant69(StringType), - Variant70(alloc::vec::Vec), - Variant71(core::option::Option<(Option<(TextSize, TextSize, Option)>, ast::Expr)>), - Variant72(ast::Alias), - Variant73(Vec), - Variant74(u32), - Variant75(alloc::vec::Vec), - Variant76((Option, Option)), - Variant77(ast::MatchCase), - Variant78(alloc::vec::Vec), - Variant79(ast::PatternKeyword), - Variant80((ast::Expr, ast::Pattern)), - Variant81(ast::Number), - Variant82(Vec), - Variant83(Vec), - Variant84(Vec<(ast::Expr, ast::Pattern)>), - Variant85(Vec), - Variant86(Vec), - Variant87((Vec, Vec)), - Variant88(core::option::Option), - Variant89(ast::PatternArguments), - Variant90(ast::Comprehension), - Variant91(alloc::vec::Vec), - Variant92(Option), - Variant93(core::option::Option>), - Variant94(Vec), - Variant95(ast::Mod), - Variant96(Vec), - Variant97(ast::TypeParam), - Variant98(ast::TypeParams), - Variant99(core::option::Option), - Variant100(ast::UnaryOp), - Variant101(core::option::Option<(String, bool)>), + Variant70(ast::FStringFormatSpec), + Variant71(core::option::Option), + Variant72(ast::FStringElement), + Variant73(alloc::vec::Vec), + Variant74(core::option::Option<(Option<(TextSize, TextSize, Option)>, ast::Expr)>), + Variant75(ast::Alias), + Variant76(Vec), + Variant77(u32), + Variant78(alloc::vec::Vec), + Variant79((Option, Option)), + Variant80(ast::MatchCase), + Variant81(alloc::vec::Vec), + Variant82(ast::PatternKeyword), + Variant83((ast::Expr, ast::Pattern)), + Variant84(ast::Number), + Variant85(Vec), + Variant86(Vec), + Variant87(Vec<(ast::Expr, ast::Pattern)>), + Variant88(Vec), + Variant89(Vec), + Variant90((Vec, Vec)), + Variant91(core::option::Option), + Variant92(ast::PatternArguments), + Variant93(ast::Comprehension), + Variant94(alloc::vec::Vec), + Variant95(Option), + Variant96(core::option::Option>), + Variant97(Vec), + Variant98(ast::Mod), + Variant99(Vec), + Variant100(ast::TypeParam), + Variant101(ast::TypeParams), + Variant102(core::option::Option), + Variant103(ast::UnaryOp), + Variant104(core::option::Option<(String, bool)>), } const __ACTION: &[i16] = &[ // State 0 @@ -13866,7 +13869,7 @@ mod __parse__Top { Ok(v) => v, Err(e) => return Some(Err(e)), }; - __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + __symbols.push((__start, __Symbol::Variant72(__nt), __end)); (1, 144) } 374 => { @@ -13885,7 +13888,7 @@ mod __parse__Top { // FStringReplacementField = "{", TestListOrYieldExpr, "=", FStringConversion, FStringFormatSpecSuffix, "}" => ActionFn(1581); assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); - let __sym4 = __pop_Variant44(__symbols); + let __sym4 = __pop_Variant70(__symbols); let __sym3 = __pop_Variant67(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant15(__symbols); @@ -13896,7 +13899,7 @@ mod __parse__Top { Ok(v) => v, Err(e) => return Some(Err(e)), }; - __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + __symbols.push((__start, __Symbol::Variant72(__nt), __end)); (6, 147) } 379 => { @@ -13913,14 +13916,14 @@ mod __parse__Top { Ok(v) => v, Err(e) => return Some(Err(e)), }; - __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + __symbols.push((__start, __Symbol::Variant72(__nt), __end)); (5, 147) } 380 => { // FStringReplacementField = "{", TestListOrYieldExpr, "=", FStringFormatSpecSuffix, "}" => ActionFn(1583); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); - let __sym3 = __pop_Variant44(__symbols); + let __sym3 = __pop_Variant70(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); @@ -13930,7 +13933,7 @@ mod __parse__Top { Ok(v) => v, Err(e) => return Some(Err(e)), }; - __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + __symbols.push((__start, __Symbol::Variant72(__nt), __end)); (5, 147) } 381 => { @@ -13946,14 +13949,14 @@ mod __parse__Top { Ok(v) => v, Err(e) => return Some(Err(e)), }; - __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + __symbols.push((__start, __Symbol::Variant72(__nt), __end)); (4, 147) } 382 => { // FStringReplacementField = "{", TestListOrYieldExpr, FStringConversion, FStringFormatSpecSuffix, "}" => ActionFn(1585); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); - let __sym3 = __pop_Variant44(__symbols); + let __sym3 = __pop_Variant70(__symbols); let __sym2 = __pop_Variant67(__symbols); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); @@ -13963,7 +13966,7 @@ mod __parse__Top { Ok(v) => v, Err(e) => return Some(Err(e)), }; - __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + __symbols.push((__start, __Symbol::Variant72(__nt), __end)); (5, 147) } 383 => { @@ -13979,14 +13982,14 @@ mod __parse__Top { Ok(v) => v, Err(e) => return Some(Err(e)), }; - __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + __symbols.push((__start, __Symbol::Variant72(__nt), __end)); (4, 147) } 384 => { // FStringReplacementField = "{", TestListOrYieldExpr, FStringFormatSpecSuffix, "}" => ActionFn(1587); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); - let __sym2 = __pop_Variant44(__symbols); + let __sym2 = __pop_Variant70(__symbols); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; @@ -13995,7 +13998,7 @@ mod __parse__Top { Ok(v) => v, Err(e) => return Some(Err(e)), }; - __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + __symbols.push((__start, __Symbol::Variant72(__nt), __end)); (4, 147) } 385 => { @@ -14010,7 +14013,7 @@ mod __parse__Top { Ok(v) => v, Err(e) => return Some(Err(e)), }; - __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + __symbols.push((__start, __Symbol::Variant72(__nt), __end)); (3, 147) } 386 => { @@ -14360,7 +14363,7 @@ mod __parse__Top { } 474 => { // LiteralPattern = TwoOrMore => ActionFn(1354); - let __sym0 = __pop_Variant96(__symbols); + let __sym0 = __pop_Variant99(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = match super::__action1354::<>(source_code, mode, __sym0) { @@ -14670,7 +14673,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1607::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -14691,7 +14694,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym8.2; let __nt = match super::__action1608::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { @@ -14713,7 +14716,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym9.2; let __nt = match super::__action1609::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { @@ -14731,7 +14734,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1610::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -14751,7 +14754,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1611::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -14772,7 +14775,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym8.2; let __nt = match super::__action1612::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { @@ -14792,7 +14795,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1613::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -14814,7 +14817,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym9.2; let __nt = match super::__action1614::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { @@ -14837,7 +14840,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym10.2; let __nt = match super::__action1615::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9, __sym10) { @@ -14856,7 +14859,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1616::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -14877,7 +14880,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym8.2; let __nt = match super::__action1617::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { @@ -14899,7 +14902,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym9.2; let __nt = match super::__action1618::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { @@ -14916,7 +14919,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = match super::__action1619::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { @@ -14935,7 +14938,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1620::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -14955,7 +14958,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1621::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -14971,7 +14974,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = match super::__action1622::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { @@ -14989,7 +14992,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1623::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -15008,7 +15011,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1624::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -15026,7 +15029,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1625::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -15046,7 +15049,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1626::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -15067,7 +15070,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym8.2; let __nt = match super::__action1627::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { @@ -15084,7 +15087,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = match super::__action1628::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { @@ -15103,7 +15106,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1629::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -15123,7 +15126,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1630::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -15137,7 +15140,7 @@ mod __parse__Top { // ParameterList = OneOrMore>, "," => ActionFn(1631); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym1.2; let __nt = match super::__action1631::<>(source_code, mode, __sym0, __sym1) { @@ -15153,7 +15156,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = match super::__action1632::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { @@ -15170,7 +15173,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = match super::__action1633::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { @@ -15188,7 +15191,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1634::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -15208,7 +15211,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1635::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -15229,7 +15232,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym8.2; let __nt = match super::__action1636::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { @@ -15246,7 +15249,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = match super::__action1637::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { @@ -15265,7 +15268,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1638::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -15285,7 +15288,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1639::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -15304,7 +15307,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1640::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -15325,7 +15328,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym8.2; let __nt = match super::__action1641::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { @@ -15347,7 +15350,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym9.2; let __nt = match super::__action1642::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { @@ -15365,7 +15368,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1643::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -15385,7 +15388,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1644::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -15406,7 +15409,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym8.2; let __nt = match super::__action1645::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { @@ -15422,7 +15425,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = match super::__action1646::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { @@ -15440,7 +15443,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1647::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -15459,7 +15462,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1648::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -15474,7 +15477,7 @@ mod __parse__Top { assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = match super::__action1649::<>(source_code, mode, __sym0, __sym1, __sym2) { @@ -15491,7 +15494,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = match super::__action1650::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { @@ -15509,7 +15512,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1651::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -15526,7 +15529,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = match super::__action1652::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { @@ -15545,7 +15548,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1653::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -15565,7 +15568,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1654::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -15581,7 +15584,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = match super::__action1655::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { @@ -15599,7 +15602,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1656::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -15618,7 +15621,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1657::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -15630,7 +15633,7 @@ mod __parse__Top { } 623 => { // ParameterList = OneOrMore> => ActionFn(1658); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = match super::__action1658::<>(source_code, mode, __sym0) { @@ -15645,7 +15648,7 @@ mod __parse__Top { assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = match super::__action1659::<>(source_code, mode, __sym0, __sym1, __sym2) { @@ -15661,7 +15664,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = match super::__action1660::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { @@ -15677,7 +15680,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant9(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = match super::__action1661::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { @@ -15695,7 +15698,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1662::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -15714,7 +15717,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1663::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -15729,7 +15732,7 @@ mod __parse__Top { assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant9(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = match super::__action1664::<>(source_code, mode, __sym0, __sym1, __sym2) { @@ -15746,7 +15749,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = match super::__action1665::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { @@ -15764,7 +15767,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1666::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -16036,7 +16039,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1667::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -16057,7 +16060,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym8.2; let __nt = match super::__action1668::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { @@ -16079,7 +16082,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym9.2; let __nt = match super::__action1669::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { @@ -16097,7 +16100,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1670::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -16117,7 +16120,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1671::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -16138,7 +16141,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym8.2; let __nt = match super::__action1672::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { @@ -16158,7 +16161,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1673::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -16180,7 +16183,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym9.2; let __nt = match super::__action1674::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { @@ -16203,7 +16206,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym10.2; let __nt = match super::__action1675::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9, __sym10) { @@ -16222,7 +16225,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1676::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -16243,7 +16246,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym8.2; let __nt = match super::__action1677::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { @@ -16265,7 +16268,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym9.2; let __nt = match super::__action1678::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { @@ -16282,7 +16285,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = match super::__action1679::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { @@ -16301,7 +16304,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1680::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -16321,7 +16324,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1681::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -16337,7 +16340,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = match super::__action1682::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { @@ -16355,7 +16358,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1683::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -16374,7 +16377,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1684::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -16392,7 +16395,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1685::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -16412,7 +16415,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1686::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -16433,7 +16436,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym8.2; let __nt = match super::__action1687::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { @@ -16450,7 +16453,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = match super::__action1688::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { @@ -16469,7 +16472,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1689::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -16489,7 +16492,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1690::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -16503,7 +16506,7 @@ mod __parse__Top { // ParameterList = OneOrMore>, "," => ActionFn(1691); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym1.2; let __nt = match super::__action1691::<>(source_code, mode, __sym0, __sym1) { @@ -16519,7 +16522,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = match super::__action1692::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { @@ -16536,7 +16539,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = match super::__action1693::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { @@ -16554,7 +16557,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1694::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -16574,7 +16577,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1695::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -16595,7 +16598,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym8.2; let __nt = match super::__action1696::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { @@ -16612,7 +16615,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = match super::__action1697::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { @@ -16631,7 +16634,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1698::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -16651,7 +16654,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1699::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -16670,7 +16673,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1700::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -16691,7 +16694,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym8.2; let __nt = match super::__action1701::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { @@ -16713,7 +16716,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym9.2; let __nt = match super::__action1702::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8, __sym9) { @@ -16731,7 +16734,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1703::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -16751,7 +16754,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1704::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -16772,7 +16775,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym8.2; let __nt = match super::__action1705::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7, __sym8) { @@ -16788,7 +16791,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = match super::__action1706::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { @@ -16806,7 +16809,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1707::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -16825,7 +16828,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1708::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -16840,7 +16843,7 @@ mod __parse__Top { assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = match super::__action1709::<>(source_code, mode, __sym0, __sym1, __sym2) { @@ -16857,7 +16860,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = match super::__action1710::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { @@ -16875,7 +16878,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1711::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -16892,7 +16895,7 @@ mod __parse__Top { let __sym3 = __pop_Variant63(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = match super::__action1712::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { @@ -16911,7 +16914,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1713::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -16931,7 +16934,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym7.2; let __nt = match super::__action1714::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6, __sym7) { @@ -16947,7 +16950,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = match super::__action1715::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { @@ -16965,7 +16968,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1716::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -16984,7 +16987,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1717::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -16996,7 +16999,7 @@ mod __parse__Top { } 701 => { // ParameterList = OneOrMore> => ActionFn(1718); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = match super::__action1718::<>(source_code, mode, __sym0) { @@ -17011,7 +17014,7 @@ mod __parse__Top { assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = match super::__action1719::<>(source_code, mode, __sym0, __sym1, __sym2) { @@ -17027,7 +17030,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = match super::__action1720::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { @@ -17043,7 +17046,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant9(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = match super::__action1721::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3) { @@ -17061,7 +17064,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1722::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -17080,7 +17083,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym6.2; let __nt = match super::__action1723::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5, __sym6) { @@ -17095,7 +17098,7 @@ mod __parse__Top { assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant9(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = match super::__action1724::<>(source_code, mode, __sym0, __sym1, __sym2) { @@ -17112,7 +17115,7 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = match super::__action1725::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4) { @@ -17130,7 +17133,7 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = match super::__action1726::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5) { @@ -17932,7 +17935,7 @@ mod __parse__Top { } 836 => { // String = TwoOrMore => ActionFn(1493); - let __sym0 = __pop_Variant96(__symbols); + let __sym0 = __pop_Variant99(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = match super::__action1493::<>(source_code, mode, __sym0) { @@ -18295,7 +18298,7 @@ mod __parse__Top { } 951 => { // __Top = Top => ActionFn(0); - let __sym0 = __pop_Variant95(__symbols); + let __sym0 = __pop_Variant98(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action0::<>(source_code, mode, __sym0); @@ -18360,13 +18363,13 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant76< + fn __pop_Variant79< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, (Option, Option), TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant76(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant79(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -18420,13 +18423,13 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant87< + fn __pop_Variant90< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, (Vec, Vec), TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant87(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant90(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -18440,13 +18443,13 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant80< + fn __pop_Variant83< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, (ast::Expr, ast::Pattern), TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant80(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant83(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -18510,13 +18513,13 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant92< + fn __pop_Variant95< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, Option, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant92(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant95(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -18570,33 +18573,33 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant84< + fn __pop_Variant87< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, Vec<(ast::Expr, ast::Pattern)>, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant84(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant87(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } - fn __pop_Variant96< + fn __pop_Variant99< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, Vec, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant96(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant99(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } - fn __pop_Variant73< + fn __pop_Variant76< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, Vec, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant73(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant76(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -18610,23 +18613,23 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant82< + fn __pop_Variant85< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, Vec, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant82(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant85(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } - fn __pop_Variant85< + fn __pop_Variant88< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, Vec, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant85(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant88(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -18640,33 +18643,33 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant83< + fn __pop_Variant86< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, Vec, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant83(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant86(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } - fn __pop_Variant94< + fn __pop_Variant97< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, Vec, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant94(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant97(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } - fn __pop_Variant86< + fn __pop_Variant89< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, Vec, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant86(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant89(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -18730,13 +18733,13 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant91< + fn __pop_Variant94< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, alloc::vec::Vec, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant91(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant94(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -18760,23 +18763,23 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant70< + fn __pop_Variant73< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, alloc::vec::Vec, TextSize) + ) -> (TextSize, alloc::vec::Vec, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant70(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant73(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } - fn __pop_Variant78< + fn __pop_Variant81< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, alloc::vec::Vec, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant78(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant81(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -18840,23 +18843,23 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant75< + fn __pop_Variant78< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, alloc::vec::Vec, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant75(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant78(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } - fn __pop_Variant72< + fn __pop_Variant75< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, ast::Alias, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant72(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant75(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -18880,13 +18883,13 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant90< + fn __pop_Variant93< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, ast::Comprehension, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant90(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant93(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -18920,6 +18923,26 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } + fn __pop_Variant72< + >( + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> + ) -> (TextSize, ast::FStringElement, TextSize) + { + match __symbols.pop() { + Some((__l, __Symbol::Variant72(__v), __r)) => (__l, __v, __r), + _ => __symbol_type_mismatch() + } + } + fn __pop_Variant70< + >( + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> + ) -> (TextSize, ast::FStringFormatSpec, TextSize) + { + match __symbols.pop() { + Some((__l, __Symbol::Variant70(__v), __r)) => (__l, __v, __r), + _ => __symbol_type_mismatch() + } + } fn __pop_Variant23< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> @@ -18930,33 +18953,33 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant77< + fn __pop_Variant80< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, ast::MatchCase, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant77(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant80(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } - fn __pop_Variant95< + fn __pop_Variant98< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, ast::Mod, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant95(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant98(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } - fn __pop_Variant81< + fn __pop_Variant84< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, ast::Number, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant81(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant84(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -19010,23 +19033,23 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant89< + fn __pop_Variant92< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, ast::PatternArguments, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant89(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant92(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } - fn __pop_Variant79< + fn __pop_Variant82< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, ast::PatternKeyword, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant79(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant82(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -19050,33 +19073,33 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant97< + fn __pop_Variant100< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, ast::TypeParam, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant97(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant100(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } - fn __pop_Variant98< + fn __pop_Variant101< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, ast::TypeParams, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant98(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant101(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } - fn __pop_Variant100< + fn __pop_Variant103< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, ast::UnaryOp, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant100(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant103(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -19090,13 +19113,13 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant71< + fn __pop_Variant74< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, core::option::Option<(Option<(TextSize, TextSize, Option)>, ast::Expr)>, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant71(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant74(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -19110,13 +19133,13 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant101< + fn __pop_Variant104< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, core::option::Option<(String, bool)>, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant101(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant104(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -19150,13 +19173,13 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant93< + fn __pop_Variant96< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, core::option::Option>, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant93(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant96(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -19220,6 +19243,16 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } + fn __pop_Variant71< + >( + __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> + ) -> (TextSize, core::option::Option, TextSize) + { + match __symbols.pop() { + Some((__l, __Symbol::Variant71(__v), __r)) => (__l, __v, __r), + _ => __symbol_type_mismatch() + } + } fn __pop_Variant24< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> @@ -19250,13 +19283,13 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant88< + fn __pop_Variant91< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, core::option::Option, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant88(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant91(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -19270,13 +19303,13 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant99< + fn __pop_Variant102< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, core::option::Option, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant99(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant102(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -19330,13 +19363,13 @@ mod __parse__Top { _ => __symbol_type_mismatch() } } - fn __pop_Variant74< + fn __pop_Variant77< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> ) -> (TextSize, u32, TextSize) { match __symbols.pop() { - Some((__l, __Symbol::Variant74(__v), __r)) => (__l, __v, __r), + Some((__l, __Symbol::Variant77(__v), __r)) => (__l, __v, __r), _ => __symbol_type_mismatch() } } @@ -21983,7 +22016,7 @@ mod __parse__Top { ) -> (usize, usize) { // Atom<"all"> = Number => ActionFn(1239); - let __sym0 = __pop_Variant81(__symbols); + let __sym0 = __pop_Variant84(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action1239::<>(source_code, mode, __sym0); @@ -22364,7 +22397,7 @@ mod __parse__Top { ) -> (usize, usize) { // Atom<"no-withitems"> = Number => ActionFn(1265); - let __sym0 = __pop_Variant81(__symbols); + let __sym0 = __pop_Variant84(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action1265::<>(source_code, mode, __sym0); @@ -23155,7 +23188,7 @@ mod __parse__Top { let __sym5 = __pop_Variant25(__symbols); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant50(__symbols); - let __sym2 = __pop_Variant98(__symbols); + let __sym2 = __pop_Variant101(__symbols); let __sym1 = __pop_Variant23(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; @@ -23200,7 +23233,7 @@ mod __parse__Top { let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant50(__symbols); - let __sym3 = __pop_Variant98(__symbols); + let __sym3 = __pop_Variant101(__symbols); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant58(__symbols); @@ -23246,7 +23279,7 @@ mod __parse__Top { assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant25(__symbols); let __sym3 = __pop_Variant0(__symbols); - let __sym2 = __pop_Variant98(__symbols); + let __sym2 = __pop_Variant101(__symbols); let __sym1 = __pop_Variant23(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; @@ -23289,7 +23322,7 @@ mod __parse__Top { assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant25(__symbols); let __sym4 = __pop_Variant0(__symbols); - let __sym3 = __pop_Variant98(__symbols); + let __sym3 = __pop_Variant101(__symbols); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant58(__symbols); @@ -23332,7 +23365,7 @@ mod __parse__Top { { // ClassPattern = MatchName, PatternArguments => ActionFn(1298); assert!(__symbols.len() >= 2); - let __sym1 = __pop_Variant89(__symbols); + let __sym1 = __pop_Variant92(__symbols); let __sym0 = __pop_Variant44(__symbols); let __start = __sym0.0; let __end = __sym1.2; @@ -23351,7 +23384,7 @@ mod __parse__Top { { // ClassPattern = MatchNameOrAttr, PatternArguments => ActionFn(1299); assert!(__symbols.len() >= 2); - let __sym1 = __pop_Variant89(__symbols); + let __sym1 = __pop_Variant92(__symbols); let __sym0 = __pop_Variant44(__symbols); let __start = __sym0.0; let __end = __sym1.2; @@ -23626,7 +23659,7 @@ mod __parse__Top { ) -> (usize, usize) { // CompFor = SingleForComprehension+ => ActionFn(237); - let __sym0 = __pop_Variant91(__symbols); + let __sym0 = __pop_Variant94(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action237::<>(source_code, mode, __sym0); @@ -24899,7 +24932,7 @@ mod __parse__Top { // FStringExpr = FStringStart, FStringMiddlePattern+, FStringEnd => ActionFn(1590); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); - let __sym1 = __pop_Variant70(__symbols); + let __sym1 = __pop_Variant73(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; @@ -24920,7 +24953,7 @@ mod __parse__Top { let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); let __nt = super::__action1591::<>(source_code, mode, &__start, &__end); - __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + __symbols.push((__start, __Symbol::Variant70(__nt), __end)); (0, 141) } pub(crate) fn __reduce368< @@ -24933,11 +24966,11 @@ mod __parse__Top { ) -> (usize, usize) { // FStringFormatSpec = FStringMiddlePattern+ => ActionFn(1592); - let __sym0 = __pop_Variant70(__symbols); + let __sym0 = __pop_Variant73(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action1592::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + __symbols.push((__start, __Symbol::Variant70(__nt), __end)); (1, 141) } pub(crate) fn __reduce369< @@ -24951,12 +24984,12 @@ mod __parse__Top { { // FStringFormatSpecSuffix = ":", FStringFormatSpec => ActionFn(222); assert!(__symbols.len() >= 2); - let __sym1 = __pop_Variant44(__symbols); + let __sym1 = __pop_Variant70(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action222::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + __symbols.push((__start, __Symbol::Variant70(__nt), __end)); (2, 142) } pub(crate) fn __reduce370< @@ -24969,11 +25002,11 @@ mod __parse__Top { ) -> (usize, usize) { // FStringFormatSpecSuffix? = FStringFormatSpecSuffix => ActionFn(267); - let __sym0 = __pop_Variant44(__symbols); + let __sym0 = __pop_Variant70(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action267::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant45(__nt), __end)); + __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (1, 143) } pub(crate) fn __reduce371< @@ -24989,7 +25022,7 @@ mod __parse__Top { let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); let __nt = super::__action268::<>(source_code, mode, &__start, &__end); - __symbols.push((__start, __Symbol::Variant45(__nt), __end)); + __symbols.push((__start, __Symbol::Variant71(__nt), __end)); (0, 143) } pub(crate) fn __reduce372< @@ -25002,11 +25035,11 @@ mod __parse__Top { ) -> (usize, usize) { // FStringMiddlePattern = FStringReplacementField => ActionFn(219); - let __sym0 = __pop_Variant44(__symbols); + let __sym0 = __pop_Variant72(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action219::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant44(__nt), __end)); + __symbols.push((__start, __Symbol::Variant72(__nt), __end)); (1, 144) } pub(crate) fn __reduce374< @@ -25022,7 +25055,7 @@ mod __parse__Top { let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); let __nt = super::__action273::<>(source_code, mode, &__start, &__end); - __symbols.push((__start, __Symbol::Variant70(__nt), __end)); + __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (0, 145) } pub(crate) fn __reduce375< @@ -25035,11 +25068,11 @@ mod __parse__Top { ) -> (usize, usize) { // FStringMiddlePattern* = FStringMiddlePattern+ => ActionFn(274); - let __sym0 = __pop_Variant70(__symbols); + let __sym0 = __pop_Variant73(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action274::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant70(__nt), __end)); + __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (1, 145) } pub(crate) fn __reduce376< @@ -25052,11 +25085,11 @@ mod __parse__Top { ) -> (usize, usize) { // FStringMiddlePattern+ = FStringMiddlePattern => ActionFn(456); - let __sym0 = __pop_Variant44(__symbols); + let __sym0 = __pop_Variant72(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action456::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant70(__nt), __end)); + __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (1, 146) } pub(crate) fn __reduce377< @@ -25070,12 +25103,12 @@ mod __parse__Top { { // FStringMiddlePattern+ = FStringMiddlePattern+, FStringMiddlePattern => ActionFn(457); assert!(__symbols.len() >= 2); - let __sym1 = __pop_Variant44(__symbols); - let __sym0 = __pop_Variant70(__symbols); + let __sym1 = __pop_Variant72(__symbols); + let __sym0 = __pop_Variant73(__symbols); let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action457::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant70(__nt), __end)); + __symbols.push((__start, __Symbol::Variant73(__nt), __end)); (2, 146) } pub(crate) fn __reduce386< @@ -25090,7 +25123,7 @@ mod __parse__Top { // Factor<"all"> = UnaryOp, Factor<"all"> => ActionFn(1318); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); - let __sym0 = __pop_Variant100(__symbols); + let __sym0 = __pop_Variant103(__symbols); let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action1318::<>(source_code, mode, __sym0, __sym1); @@ -25126,7 +25159,7 @@ mod __parse__Top { // Factor<"no-withitems"> = UnaryOp, Factor<"all"> => ActionFn(1319); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant15(__symbols); - let __sym0 = __pop_Variant100(__symbols); + let __sym0 = __pop_Variant103(__symbols); let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action1319::<>(source_code, mode, __sym0, __sym1); @@ -25370,7 +25403,7 @@ mod __parse__Top { let __sym6 = __pop_Variant15(__symbols); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant46(__symbols); - let __sym3 = __pop_Variant98(__symbols); + let __sym3 = __pop_Variant101(__symbols); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); @@ -25421,7 +25454,7 @@ mod __parse__Top { let __sym7 = __pop_Variant15(__symbols); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant46(__symbols); - let __sym4 = __pop_Variant98(__symbols); + let __sym4 = __pop_Variant101(__symbols); let __sym3 = __pop_Variant23(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); @@ -25472,7 +25505,7 @@ mod __parse__Top { let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant46(__symbols); - let __sym3 = __pop_Variant98(__symbols); + let __sym3 = __pop_Variant101(__symbols); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); @@ -25519,7 +25552,7 @@ mod __parse__Top { let __sym7 = __pop_Variant25(__symbols); let __sym6 = __pop_Variant0(__symbols); let __sym5 = __pop_Variant46(__symbols); - let __sym4 = __pop_Variant98(__symbols); + let __sym4 = __pop_Variant101(__symbols); let __sym3 = __pop_Variant23(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); @@ -25570,7 +25603,7 @@ mod __parse__Top { let __sym5 = __pop_Variant15(__symbols); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant46(__symbols); - let __sym2 = __pop_Variant98(__symbols); + let __sym2 = __pop_Variant101(__symbols); let __sym1 = __pop_Variant23(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; @@ -25619,7 +25652,7 @@ mod __parse__Top { let __sym6 = __pop_Variant15(__symbols); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant46(__symbols); - let __sym3 = __pop_Variant98(__symbols); + let __sym3 = __pop_Variant101(__symbols); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant58(__symbols); @@ -25668,7 +25701,7 @@ mod __parse__Top { let __sym5 = __pop_Variant25(__symbols); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant46(__symbols); - let __sym2 = __pop_Variant98(__symbols); + let __sym2 = __pop_Variant101(__symbols); let __sym1 = __pop_Variant23(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; @@ -25713,7 +25746,7 @@ mod __parse__Top { let __sym6 = __pop_Variant25(__symbols); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant46(__symbols); - let __sym3 = __pop_Variant98(__symbols); + let __sym3 = __pop_Variant101(__symbols); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant58(__symbols); @@ -25854,7 +25887,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action467::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant71(__nt), __end)); + __symbols.push((__start, __Symbol::Variant74(__nt), __end)); (1, 154) } pub(crate) fn __reduce422< @@ -25870,7 +25903,7 @@ mod __parse__Top { let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); let __nt = super::__action468::<>(source_code, mode, &__start, &__end); - __symbols.push((__start, __Symbol::Variant71(__nt), __end)); + __symbols.push((__start, __Symbol::Variant74(__nt), __end)); (0, 154) } pub(crate) fn __reduce423< @@ -25956,7 +25989,7 @@ mod __parse__Top { { // GlobalStatement = "global", OneOrMore => ActionFn(1332); assert!(__symbols.len() >= 2); - let __sym1 = __pop_Variant82(__symbols); + let __sym1 = __pop_Variant85(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; @@ -26109,7 +26142,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1334::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant72(__nt), __end)); + __symbols.push((__start, __Symbol::Variant75(__nt), __end)); (3, 161) } pub(crate) fn __reduce435< @@ -26126,7 +26159,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action1335::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant72(__nt), __end)); + __symbols.push((__start, __Symbol::Variant75(__nt), __end)); (1, 161) } pub(crate) fn __reduce436< @@ -26146,7 +26179,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1336::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant72(__nt), __end)); + __symbols.push((__start, __Symbol::Variant75(__nt), __end)); (3, 162) } pub(crate) fn __reduce437< @@ -26163,7 +26196,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action1337::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant72(__nt), __end)); + __symbols.push((__start, __Symbol::Variant75(__nt), __end)); (1, 162) } pub(crate) fn __reduce438< @@ -26176,11 +26209,11 @@ mod __parse__Top { ) -> (usize, usize) { // ImportAsNames = OneOrMore> => ActionFn(1338); - let __sym0 = __pop_Variant73(__symbols); + let __sym0 = __pop_Variant76(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action1338::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant73(__nt), __end)); + __symbols.push((__start, __Symbol::Variant76(__nt), __end)); (1, 163) } pub(crate) fn __reduce439< @@ -26196,12 +26229,12 @@ mod __parse__Top { assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); - let __sym1 = __pop_Variant73(__symbols); + let __sym1 = __pop_Variant76(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = super::__action1339::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); - __symbols.push((__start, __Symbol::Variant73(__nt), __end)); + __symbols.push((__start, __Symbol::Variant76(__nt), __end)); (4, 163) } pub(crate) fn __reduce440< @@ -26216,12 +26249,12 @@ mod __parse__Top { // ImportAsNames = "(", OneOrMore>, ")" => ActionFn(1340); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); - let __sym1 = __pop_Variant73(__symbols); + let __sym1 = __pop_Variant76(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1340::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant73(__nt), __end)); + __symbols.push((__start, __Symbol::Variant76(__nt), __end)); (3, 163) } pub(crate) fn __reduce441< @@ -26238,7 +26271,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action1341::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant73(__nt), __end)); + __symbols.push((__start, __Symbol::Variant76(__nt), __end)); (1, 163) } pub(crate) fn __reduce442< @@ -26255,7 +26288,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action64::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant74(__nt), __end)); + __symbols.push((__start, __Symbol::Variant77(__nt), __end)); (1, 164) } pub(crate) fn __reduce443< @@ -26272,7 +26305,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action65::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant74(__nt), __end)); + __symbols.push((__start, __Symbol::Variant77(__nt), __end)); (1, 164) } pub(crate) fn __reduce444< @@ -26288,7 +26321,7 @@ mod __parse__Top { let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); let __nt = super::__action391::<>(source_code, mode, &__start, &__end); - __symbols.push((__start, __Symbol::Variant75(__nt), __end)); + __symbols.push((__start, __Symbol::Variant78(__nt), __end)); (0, 165) } pub(crate) fn __reduce445< @@ -26301,11 +26334,11 @@ mod __parse__Top { ) -> (usize, usize) { // ImportDots* = ImportDots+ => ActionFn(392); - let __sym0 = __pop_Variant75(__symbols); + let __sym0 = __pop_Variant78(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action392::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant75(__nt), __end)); + __symbols.push((__start, __Symbol::Variant78(__nt), __end)); (1, 165) } pub(crate) fn __reduce446< @@ -26318,11 +26351,11 @@ mod __parse__Top { ) -> (usize, usize) { // ImportDots+ = ImportDots => ActionFn(389); - let __sym0 = __pop_Variant74(__symbols); + let __sym0 = __pop_Variant77(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action389::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant75(__nt), __end)); + __symbols.push((__start, __Symbol::Variant78(__nt), __end)); (1, 166) } pub(crate) fn __reduce447< @@ -26336,12 +26369,12 @@ mod __parse__Top { { // ImportDots+ = ImportDots+, ImportDots => ActionFn(390); assert!(__symbols.len() >= 2); - let __sym1 = __pop_Variant74(__symbols); - let __sym0 = __pop_Variant75(__symbols); + let __sym1 = __pop_Variant77(__symbols); + let __sym0 = __pop_Variant78(__symbols); let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action390::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant75(__nt), __end)); + __symbols.push((__start, __Symbol::Variant78(__nt), __end)); (2, 166) } pub(crate) fn __reduce448< @@ -26358,7 +26391,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action1601::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant76(__nt), __end)); + __symbols.push((__start, __Symbol::Variant79(__nt), __end)); (1, 167) } pub(crate) fn __reduce449< @@ -26373,11 +26406,11 @@ mod __parse__Top { // ImportFromLocation = ImportDots+, DottedName => ActionFn(1602); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant23(__symbols); - let __sym0 = __pop_Variant75(__symbols); + let __sym0 = __pop_Variant78(__symbols); let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action1602::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant76(__nt), __end)); + __symbols.push((__start, __Symbol::Variant79(__nt), __end)); (2, 167) } pub(crate) fn __reduce450< @@ -26390,11 +26423,11 @@ mod __parse__Top { ) -> (usize, usize) { // ImportFromLocation = ImportDots+ => ActionFn(63); - let __sym0 = __pop_Variant75(__symbols); + let __sym0 = __pop_Variant78(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action63::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant76(__nt), __end)); + __symbols.push((__start, __Symbol::Variant79(__nt), __end)); (1, 167) } pub(crate) fn __reduce451< @@ -26408,7 +26441,7 @@ mod __parse__Top { { // ImportStatement = "import", OneOrMore> => ActionFn(1342); assert!(__symbols.len() >= 2); - let __sym1 = __pop_Variant73(__symbols); + let __sym1 = __pop_Variant76(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; @@ -26427,9 +26460,9 @@ mod __parse__Top { { // ImportStatement = "from", ImportFromLocation, "import", ImportAsNames => ActionFn(1343); assert!(__symbols.len() >= 4); - let __sym3 = __pop_Variant73(__symbols); + let __sym3 = __pop_Variant76(__symbols); let __sym2 = __pop_Variant0(__symbols); - let __sym1 = __pop_Variant76(__symbols); + let __sym1 = __pop_Variant79(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; @@ -26831,7 +26864,7 @@ mod __parse__Top { assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); - let __sym1 = __pop_Variant84(__symbols); + let __sym1 = __pop_Variant87(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; @@ -26851,7 +26884,7 @@ mod __parse__Top { // MappingPattern = "{", OneOrMore, "}" => ActionFn(1360); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); - let __sym1 = __pop_Variant84(__symbols); + let __sym1 = __pop_Variant87(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; @@ -26918,7 +26951,7 @@ mod __parse__Top { let __sym4 = __pop_Variant23(__symbols); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); - let __sym1 = __pop_Variant84(__symbols); + let __sym1 = __pop_Variant87(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym6.2; @@ -26941,7 +26974,7 @@ mod __parse__Top { let __sym4 = __pop_Variant23(__symbols); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); - let __sym1 = __pop_Variant84(__symbols); + let __sym1 = __pop_Variant87(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; @@ -26968,7 +27001,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym4.2; let __nt = super::__action1223::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); - __symbols.push((__start, __Symbol::Variant77(__nt), __end)); + __symbols.push((__start, __Symbol::Variant80(__nt), __end)); (5, 180) } pub(crate) fn __reduce490< @@ -26989,7 +27022,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym3.2; let __nt = super::__action1224::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); - __symbols.push((__start, __Symbol::Variant77(__nt), __end)); + __symbols.push((__start, __Symbol::Variant80(__nt), __end)); (4, 180) } pub(crate) fn __reduce491< @@ -27002,11 +27035,11 @@ mod __parse__Top { ) -> (usize, usize) { // MatchCase+ = MatchCase => ActionFn(369); - let __sym0 = __pop_Variant77(__symbols); + let __sym0 = __pop_Variant80(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action369::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant78(__nt), __end)); + __symbols.push((__start, __Symbol::Variant81(__nt), __end)); (1, 181) } pub(crate) fn __reduce492< @@ -27020,12 +27053,12 @@ mod __parse__Top { { // MatchCase+ = MatchCase+, MatchCase => ActionFn(370); assert!(__symbols.len() >= 2); - let __sym1 = __pop_Variant77(__symbols); - let __sym0 = __pop_Variant78(__symbols); + let __sym1 = __pop_Variant80(__symbols); + let __sym0 = __pop_Variant81(__symbols); let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action370::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant78(__nt), __end)); + __symbols.push((__start, __Symbol::Variant81(__nt), __end)); (2, 181) } pub(crate) fn __reduce493< @@ -27045,7 +27078,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1365::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant79(__nt), __end)); + __symbols.push((__start, __Symbol::Variant82(__nt), __end)); (3, 182) } pub(crate) fn __reduce494< @@ -27065,7 +27098,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action134::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant80(__nt), __end)); + __symbols.push((__start, __Symbol::Variant83(__nt), __end)); (3, 183) } pub(crate) fn __reduce495< @@ -27137,7 +27170,7 @@ mod __parse__Top { // MatchStatement = "match", TestOrStarNamedExpr, ":", "\n", Indent, MatchCase+, Dedent => ActionFn(862); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); - let __sym5 = __pop_Variant78(__symbols); + let __sym5 = __pop_Variant81(__symbols); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -27161,7 +27194,7 @@ mod __parse__Top { // MatchStatement = "match", TestOrStarNamedExpr, ",", ":", "\n", Indent, MatchCase+, Dedent => ActionFn(1369); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant0(__symbols); - let __sym6 = __pop_Variant78(__symbols); + let __sym6 = __pop_Variant81(__symbols); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -27186,7 +27219,7 @@ mod __parse__Top { // MatchStatement = "match", TwoOrMoreSep, ",", ":", "\n", Indent, MatchCase+, Dedent => ActionFn(1370); assert!(__symbols.len() >= 8); let __sym7 = __pop_Variant0(__symbols); - let __sym6 = __pop_Variant78(__symbols); + let __sym6 = __pop_Variant81(__symbols); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant0(__symbols); @@ -27211,7 +27244,7 @@ mod __parse__Top { // MatchStatement = "match", TwoOrMoreSep, ":", "\n", Indent, MatchCase+, Dedent => ActionFn(1371); assert!(__symbols.len() >= 7); let __sym6 = __pop_Variant0(__symbols); - let __sym5 = __pop_Variant78(__symbols); + let __sym5 = __pop_Variant81(__symbols); let __sym4 = __pop_Variant0(__symbols); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); @@ -27424,7 +27457,7 @@ mod __parse__Top { { // NonlocalStatement = "nonlocal", OneOrMore => ActionFn(1374); assert!(__symbols.len() >= 2); - let __sym1 = __pop_Variant82(__symbols); + let __sym1 = __pop_Variant85(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; @@ -27518,7 +27551,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action246::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant81(__nt), __end)); + __symbols.push((__start, __Symbol::Variant84(__nt), __end)); (1, 195) } pub(crate) fn __reduce519< @@ -27535,7 +27568,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action247::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant81(__nt), __end)); + __symbols.push((__start, __Symbol::Variant84(__nt), __end)); (1, 195) } pub(crate) fn __reduce520< @@ -27552,7 +27585,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action248::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant81(__nt), __end)); + __symbols.push((__start, __Symbol::Variant84(__nt), __end)); (1, 195) } pub(crate) fn __reduce521< @@ -27565,7 +27598,7 @@ mod __parse__Top { ) -> (usize, usize) { // NumberAtom = Number => ActionFn(1377); - let __sym0 = __pop_Variant81(__symbols); + let __sym0 = __pop_Variant84(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action1377::<>(source_code, mode, __sym0); @@ -27696,7 +27729,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action379::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant82(__nt), __end)); + __symbols.push((__start, __Symbol::Variant85(__nt), __end)); (1, 200) } pub(crate) fn __reduce529< @@ -27712,11 +27745,11 @@ mod __parse__Top { assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant82(__symbols); + let __sym0 = __pop_Variant85(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action380::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant82(__nt), __end)); + __symbols.push((__start, __Symbol::Variant85(__nt), __end)); (3, 200) } pub(crate) fn __reduce530< @@ -27736,7 +27769,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1593::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant73(__nt), __end)); + __symbols.push((__start, __Symbol::Variant76(__nt), __end)); (3, 201) } pub(crate) fn __reduce531< @@ -27753,7 +27786,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action1594::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant73(__nt), __end)); + __symbols.push((__start, __Symbol::Variant76(__nt), __end)); (1, 201) } pub(crate) fn __reduce532< @@ -27771,11 +27804,11 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant73(__symbols); + let __sym0 = __pop_Variant76(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = super::__action1595::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); - __symbols.push((__start, __Symbol::Variant73(__nt), __end)); + __symbols.push((__start, __Symbol::Variant76(__nt), __end)); (5, 201) } pub(crate) fn __reduce533< @@ -27791,11 +27824,11 @@ mod __parse__Top { assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant73(__symbols); + let __sym0 = __pop_Variant76(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1596::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant73(__nt), __end)); + __symbols.push((__start, __Symbol::Variant76(__nt), __end)); (3, 201) } pub(crate) fn __reduce534< @@ -27815,7 +27848,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1597::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant73(__nt), __end)); + __symbols.push((__start, __Symbol::Variant76(__nt), __end)); (3, 202) } pub(crate) fn __reduce535< @@ -27832,7 +27865,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action1598::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant73(__nt), __end)); + __symbols.push((__start, __Symbol::Variant76(__nt), __end)); (1, 202) } pub(crate) fn __reduce536< @@ -27850,11 +27883,11 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant73(__symbols); + let __sym0 = __pop_Variant76(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = super::__action1599::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); - __symbols.push((__start, __Symbol::Variant73(__nt), __end)); + __symbols.push((__start, __Symbol::Variant76(__nt), __end)); (5, 202) } pub(crate) fn __reduce537< @@ -27870,11 +27903,11 @@ mod __parse__Top { assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant23(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant73(__symbols); + let __sym0 = __pop_Variant76(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1600::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant73(__nt), __end)); + __symbols.push((__start, __Symbol::Variant76(__nt), __end)); (3, 202) } pub(crate) fn __reduce538< @@ -27887,11 +27920,11 @@ mod __parse__Top { ) -> (usize, usize) { // OneOrMore = MatchKeywordEntry => ActionFn(348); - let __sym0 = __pop_Variant79(__symbols); + let __sym0 = __pop_Variant82(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action348::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant83(__nt), __end)); + __symbols.push((__start, __Symbol::Variant86(__nt), __end)); (1, 203) } pub(crate) fn __reduce539< @@ -27905,13 +27938,13 @@ mod __parse__Top { { // OneOrMore = OneOrMore, ",", MatchKeywordEntry => ActionFn(349); assert!(__symbols.len() >= 3); - let __sym2 = __pop_Variant79(__symbols); + let __sym2 = __pop_Variant82(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant83(__symbols); + let __sym0 = __pop_Variant86(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action349::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant83(__nt), __end)); + __symbols.push((__start, __Symbol::Variant86(__nt), __end)); (3, 203) } pub(crate) fn __reduce540< @@ -27924,11 +27957,11 @@ mod __parse__Top { ) -> (usize, usize) { // OneOrMore = MatchMappingEntry => ActionFn(352); - let __sym0 = __pop_Variant80(__symbols); + let __sym0 = __pop_Variant83(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action352::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant84(__nt), __end)); + __symbols.push((__start, __Symbol::Variant87(__nt), __end)); (1, 204) } pub(crate) fn __reduce541< @@ -27942,13 +27975,13 @@ mod __parse__Top { { // OneOrMore = OneOrMore, ",", MatchMappingEntry => ActionFn(353); assert!(__symbols.len() >= 3); - let __sym2 = __pop_Variant80(__symbols); + let __sym2 = __pop_Variant83(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant84(__symbols); + let __sym0 = __pop_Variant87(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action353::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant84(__nt), __end)); + __symbols.push((__start, __Symbol::Variant87(__nt), __end)); (3, 204) } pub(crate) fn __reduce542< @@ -27965,7 +27998,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action490::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant85(__nt), __end)); + __symbols.push((__start, __Symbol::Variant88(__nt), __end)); (1, 205) } pub(crate) fn __reduce543< @@ -27981,11 +28014,11 @@ mod __parse__Top { assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant11(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action491::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant85(__nt), __end)); + __symbols.push((__start, __Symbol::Variant88(__nt), __end)); (3, 205) } pub(crate) fn __reduce544< @@ -28002,7 +28035,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action479::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant85(__nt), __end)); + __symbols.push((__start, __Symbol::Variant88(__nt), __end)); (1, 206) } pub(crate) fn __reduce545< @@ -28018,11 +28051,11 @@ mod __parse__Top { assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant11(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action480::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant85(__nt), __end)); + __symbols.push((__start, __Symbol::Variant88(__nt), __end)); (3, 206) } pub(crate) fn __reduce546< @@ -28183,11 +28216,11 @@ mod __parse__Top { ) -> (usize, usize) { // OneOrMore = TypeParam => ActionFn(289); - let __sym0 = __pop_Variant97(__symbols); + let __sym0 = __pop_Variant100(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action289::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant86(__nt), __end)); + __symbols.push((__start, __Symbol::Variant89(__nt), __end)); (1, 211) } pub(crate) fn __reduce555< @@ -28201,13 +28234,13 @@ mod __parse__Top { { // OneOrMore = OneOrMore, ",", TypeParam => ActionFn(290); assert!(__symbols.len() >= 3); - let __sym2 = __pop_Variant97(__symbols); + let __sym2 = __pop_Variant100(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant86(__symbols); + let __sym0 = __pop_Variant89(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action290::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant86(__nt), __end)); + __symbols.push((__start, __Symbol::Variant89(__nt), __end)); (3, 211) } pub(crate) fn __reduce556< @@ -28400,11 +28433,11 @@ mod __parse__Top { ) -> (usize, usize) { // ParameterDefs = OneOrMore> => ActionFn(446); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action446::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant87(__nt), __end)); + __symbols.push((__start, __Symbol::Variant90(__nt), __end)); (1, 217) } pub(crate) fn __reduce567< @@ -28420,11 +28453,11 @@ mod __parse__Top { assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action701::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant87(__nt), __end)); + __symbols.push((__start, __Symbol::Variant90(__nt), __end)); (3, 217) } pub(crate) fn __reduce568< @@ -28441,11 +28474,11 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = super::__action702::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); - __symbols.push((__start, __Symbol::Variant87(__nt), __end)); + __symbols.push((__start, __Symbol::Variant90(__nt), __end)); (4, 217) } pub(crate) fn __reduce569< @@ -28458,11 +28491,11 @@ mod __parse__Top { ) -> (usize, usize) { // ParameterDefs = OneOrMore> => ActionFn(454); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action454::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant87(__nt), __end)); + __symbols.push((__start, __Symbol::Variant90(__nt), __end)); (1, 218) } pub(crate) fn __reduce570< @@ -28478,11 +28511,11 @@ mod __parse__Top { assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action709::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant87(__nt), __end)); + __symbols.push((__start, __Symbol::Variant90(__nt), __end)); (3, 218) } pub(crate) fn __reduce571< @@ -28499,11 +28532,11 @@ mod __parse__Top { let __sym3 = __pop_Variant12(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant0(__symbols); - let __sym0 = __pop_Variant85(__symbols); + let __sym0 = __pop_Variant88(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = super::__action710::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); - __symbols.push((__start, __Symbol::Variant87(__nt), __end)); + __symbols.push((__start, __Symbol::Variant90(__nt), __end)); (4, 218) } pub(crate) fn __reduce648< @@ -28676,7 +28709,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action429::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant88(__nt), __end)); + __symbols.push((__start, __Symbol::Variant91(__nt), __end)); (1, 227) } pub(crate) fn __reduce752< @@ -28692,7 +28725,7 @@ mod __parse__Top { let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); let __nt = super::__action430::<>(source_code, mode, &__start, &__end); - __symbols.push((__start, __Symbol::Variant88(__nt), __end)); + __symbols.push((__start, __Symbol::Variant91(__nt), __end)); (0, 227) } pub(crate) fn __reduce753< @@ -28708,14 +28741,14 @@ mod __parse__Top { assert!(__symbols.len() >= 6); let __sym5 = __pop_Variant0(__symbols); let __sym4 = __pop_Variant0(__symbols); - let __sym3 = __pop_Variant83(__symbols); + let __sym3 = __pop_Variant86(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant53(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym5.2; let __nt = super::__action1463::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); - __symbols.push((__start, __Symbol::Variant89(__nt), __end)); + __symbols.push((__start, __Symbol::Variant92(__nt), __end)); (6, 228) } pub(crate) fn __reduce754< @@ -28730,14 +28763,14 @@ mod __parse__Top { // PatternArguments = "(", OneOrMore, ",", OneOrMore, ")" => ActionFn(1464); assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant0(__symbols); - let __sym3 = __pop_Variant83(__symbols); + let __sym3 = __pop_Variant86(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant53(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = super::__action1464::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); - __symbols.push((__start, __Symbol::Variant89(__nt), __end)); + __symbols.push((__start, __Symbol::Variant92(__nt), __end)); (5, 228) } pub(crate) fn __reduce755< @@ -28758,7 +28791,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym3.2; let __nt = super::__action1465::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); - __symbols.push((__start, __Symbol::Variant89(__nt), __end)); + __symbols.push((__start, __Symbol::Variant92(__nt), __end)); (4, 228) } pub(crate) fn __reduce756< @@ -28778,7 +28811,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1466::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant89(__nt), __end)); + __symbols.push((__start, __Symbol::Variant92(__nt), __end)); (3, 228) } pub(crate) fn __reduce757< @@ -28794,12 +28827,12 @@ mod __parse__Top { assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); - let __sym1 = __pop_Variant83(__symbols); + let __sym1 = __pop_Variant86(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = super::__action1467::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); - __symbols.push((__start, __Symbol::Variant89(__nt), __end)); + __symbols.push((__start, __Symbol::Variant92(__nt), __end)); (4, 228) } pub(crate) fn __reduce758< @@ -28814,12 +28847,12 @@ mod __parse__Top { // PatternArguments = "(", OneOrMore, ")" => ActionFn(1468); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); - let __sym1 = __pop_Variant83(__symbols); + let __sym1 = __pop_Variant86(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1468::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant89(__nt), __end)); + __symbols.push((__start, __Symbol::Variant92(__nt), __end)); (3, 228) } pub(crate) fn __reduce759< @@ -28838,7 +28871,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action1469::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant89(__nt), __end)); + __symbols.push((__start, __Symbol::Variant92(__nt), __end)); (2, 228) } pub(crate) fn __reduce760< @@ -29528,7 +29561,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym4.2; let __nt = super::__action1555::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); - __symbols.push((__start, __Symbol::Variant90(__nt), __end)); + __symbols.push((__start, __Symbol::Variant93(__nt), __end)); (5, 239) } pub(crate) fn __reduce796< @@ -29551,7 +29584,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym5.2; let __nt = super::__action1556::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4, __sym5); - __symbols.push((__start, __Symbol::Variant90(__nt), __end)); + __symbols.push((__start, __Symbol::Variant93(__nt), __end)); (6, 239) } pub(crate) fn __reduce797< @@ -29572,7 +29605,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym3.2; let __nt = super::__action1557::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); - __symbols.push((__start, __Symbol::Variant90(__nt), __end)); + __symbols.push((__start, __Symbol::Variant93(__nt), __end)); (4, 239) } pub(crate) fn __reduce798< @@ -29594,7 +29627,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym4.2; let __nt = super::__action1558::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); - __symbols.push((__start, __Symbol::Variant90(__nt), __end)); + __symbols.push((__start, __Symbol::Variant93(__nt), __end)); (5, 239) } pub(crate) fn __reduce799< @@ -29607,11 +29640,11 @@ mod __parse__Top { ) -> (usize, usize) { // SingleForComprehension+ = SingleForComprehension => ActionFn(257); - let __sym0 = __pop_Variant90(__symbols); + let __sym0 = __pop_Variant93(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action257::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant91(__nt), __end)); + __symbols.push((__start, __Symbol::Variant94(__nt), __end)); (1, 240) } pub(crate) fn __reduce800< @@ -29625,12 +29658,12 @@ mod __parse__Top { { // SingleForComprehension+ = SingleForComprehension+, SingleForComprehension => ActionFn(258); assert!(__symbols.len() >= 2); - let __sym1 = __pop_Variant90(__symbols); - let __sym0 = __pop_Variant91(__symbols); + let __sym1 = __pop_Variant93(__symbols); + let __sym0 = __pop_Variant94(__symbols); let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action258::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant91(__nt), __end)); + __symbols.push((__start, __Symbol::Variant94(__nt), __end)); (2, 240) } pub(crate) fn __reduce801< @@ -29649,7 +29682,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action1733::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant92(__nt), __end)); + __symbols.push((__start, __Symbol::Variant95(__nt), __end)); (2, 241) } pub(crate) fn __reduce802< @@ -29666,7 +29699,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action1734::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant92(__nt), __end)); + __symbols.push((__start, __Symbol::Variant95(__nt), __end)); (1, 241) } pub(crate) fn __reduce803< @@ -29679,11 +29712,11 @@ mod __parse__Top { ) -> (usize, usize) { // SliceOp? = SliceOp => ActionFn(277); - let __sym0 = __pop_Variant92(__symbols); + let __sym0 = __pop_Variant95(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action277::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant93(__nt), __end)); + __symbols.push((__start, __Symbol::Variant96(__nt), __end)); (1, 242) } pub(crate) fn __reduce804< @@ -29699,7 +29732,7 @@ mod __parse__Top { let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); let __nt = super::__action278::<>(source_code, mode, &__start, &__end); - __symbols.push((__start, __Symbol::Variant93(__nt), __end)); + __symbols.push((__start, __Symbol::Variant96(__nt), __end)); (0, 242) } pub(crate) fn __reduce805< @@ -30064,7 +30097,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1194::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant94(__nt), __end)); + __symbols.push((__start, __Symbol::Variant97(__nt), __end)); (3, 250) } pub(crate) fn __reduce826< @@ -30085,7 +30118,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym3.2; let __nt = super::__action1195::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); - __symbols.push((__start, __Symbol::Variant94(__nt), __end)); + __symbols.push((__start, __Symbol::Variant97(__nt), __end)); (4, 250) } pub(crate) fn __reduce827< @@ -30104,7 +30137,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action1196::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant94(__nt), __end)); + __symbols.push((__start, __Symbol::Variant97(__nt), __end)); (2, 250) } pub(crate) fn __reduce828< @@ -30124,7 +30157,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1197::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant94(__nt), __end)); + __symbols.push((__start, __Symbol::Variant97(__nt), __end)); (3, 250) } pub(crate) fn __reduce829< @@ -30141,7 +30174,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action10::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant94(__nt), __end)); + __symbols.push((__start, __Symbol::Variant97(__nt), __end)); (1, 250) } pub(crate) fn __reduce830< @@ -30156,11 +30189,11 @@ mod __parse__Top { // Statements = Statements, CompoundStatement => ActionFn(11); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant37(__symbols); - let __sym0 = __pop_Variant94(__symbols); + let __sym0 = __pop_Variant97(__symbols); let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action11::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant94(__nt), __end)); + __symbols.push((__start, __Symbol::Variant97(__nt), __end)); (2, 250) } pub(crate) fn __reduce831< @@ -30177,11 +30210,11 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant37(__symbols); - let __sym0 = __pop_Variant94(__symbols); + let __sym0 = __pop_Variant97(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = super::__action1198::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); - __symbols.push((__start, __Symbol::Variant94(__nt), __end)); + __symbols.push((__start, __Symbol::Variant97(__nt), __end)); (4, 250) } pub(crate) fn __reduce832< @@ -30199,11 +30232,11 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant37(__symbols); let __sym1 = __pop_Variant38(__symbols); - let __sym0 = __pop_Variant94(__symbols); + let __sym0 = __pop_Variant97(__symbols); let __start = __sym0.0; let __end = __sym4.2; let __nt = super::__action1199::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3, __sym4); - __symbols.push((__start, __Symbol::Variant94(__nt), __end)); + __symbols.push((__start, __Symbol::Variant97(__nt), __end)); (5, 250) } pub(crate) fn __reduce833< @@ -30219,11 +30252,11 @@ mod __parse__Top { assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); let __sym1 = __pop_Variant37(__symbols); - let __sym0 = __pop_Variant94(__symbols); + let __sym0 = __pop_Variant97(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1200::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant94(__nt), __end)); + __symbols.push((__start, __Symbol::Variant97(__nt), __end)); (3, 250) } pub(crate) fn __reduce834< @@ -30240,11 +30273,11 @@ mod __parse__Top { let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant37(__symbols); let __sym1 = __pop_Variant38(__symbols); - let __sym0 = __pop_Variant94(__symbols); + let __sym0 = __pop_Variant97(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = super::__action1201::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); - __symbols.push((__start, __Symbol::Variant94(__nt), __end)); + __symbols.push((__start, __Symbol::Variant97(__nt), __end)); (4, 250) } pub(crate) fn __reduce835< @@ -30326,7 +30359,7 @@ mod __parse__Top { { // Subscript = Test<"all">, ":", Test<"all">, SliceOp => ActionFn(1735); assert!(__symbols.len() >= 4); - let __sym3 = __pop_Variant92(__symbols); + let __sym3 = __pop_Variant95(__symbols); let __sym2 = __pop_Variant15(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); @@ -30347,7 +30380,7 @@ mod __parse__Top { { // Subscript = Test<"all">, ":", SliceOp => ActionFn(1736); assert!(__symbols.len() >= 3); - let __sym2 = __pop_Variant92(__symbols); + let __sym2 = __pop_Variant95(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant15(__symbols); let __start = __sym0.0; @@ -30367,7 +30400,7 @@ mod __parse__Top { { // Subscript = ":", Test<"all">, SliceOp => ActionFn(1737); assert!(__symbols.len() >= 3); - let __sym2 = __pop_Variant92(__symbols); + let __sym2 = __pop_Variant95(__symbols); let __sym1 = __pop_Variant15(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; @@ -30387,7 +30420,7 @@ mod __parse__Top { { // Subscript = ":", SliceOp => ActionFn(1738); assert!(__symbols.len() >= 2); - let __sym1 = __pop_Variant92(__symbols); + let __sym1 = __pop_Variant95(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym1.2; @@ -30634,7 +30667,7 @@ mod __parse__Top { // Suite = "\n", Indent, Statements, Dedent => ActionFn(8); assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); - let __sym2 = __pop_Variant94(__symbols); + let __sym2 = __pop_Variant97(__symbols); let __sym1 = __pop_Variant0(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; @@ -31047,7 +31080,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action1503::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant95(__nt), __end)); + __symbols.push((__start, __Symbol::Variant98(__nt), __end)); (2, 268) } pub(crate) fn __reduce881< @@ -31066,7 +31099,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action1750::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant95(__nt), __end)); + __symbols.push((__start, __Symbol::Variant98(__nt), __end)); (2, 268) } pub(crate) fn __reduce882< @@ -31086,7 +31119,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1751::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant95(__nt), __end)); + __symbols.push((__start, __Symbol::Variant98(__nt), __end)); (3, 268) } pub(crate) fn __reduce883< @@ -31320,7 +31353,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action354::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant96(__nt), __end)); + __symbols.push((__start, __Symbol::Variant99(__nt), __end)); (2, 270) } pub(crate) fn __reduce893< @@ -31335,11 +31368,11 @@ mod __parse__Top { // TwoOrMore = TwoOrMore, StringLiteral => ActionFn(355); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant69(__symbols); - let __sym0 = __pop_Variant96(__symbols); + let __sym0 = __pop_Variant99(__symbols); let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action355::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant96(__nt), __end)); + __symbols.push((__start, __Symbol::Variant99(__nt), __end)); (2, 270) } pub(crate) fn __reduce894< @@ -31358,7 +31391,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action275::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant96(__nt), __end)); + __symbols.push((__start, __Symbol::Variant99(__nt), __end)); (2, 271) } pub(crate) fn __reduce895< @@ -31373,11 +31406,11 @@ mod __parse__Top { // TwoOrMore = TwoOrMore, StringLiteralOrFString => ActionFn(276); assert!(__symbols.len() >= 2); let __sym1 = __pop_Variant69(__symbols); - let __sym0 = __pop_Variant96(__symbols); + let __sym0 = __pop_Variant99(__symbols); let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action276::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant96(__nt), __end)); + __symbols.push((__start, __Symbol::Variant99(__nt), __end)); (2, 271) } pub(crate) fn __reduce896< @@ -31570,7 +31603,7 @@ mod __parse__Top { assert!(__symbols.len() >= 5); let __sym4 = __pop_Variant15(__symbols); let __sym3 = __pop_Variant0(__symbols); - let __sym2 = __pop_Variant98(__symbols); + let __sym2 = __pop_Variant101(__symbols); let __sym1 = __pop_Variant44(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; @@ -31617,7 +31650,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1516::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant97(__nt), __end)); + __symbols.push((__start, __Symbol::Variant100(__nt), __end)); (3, 278) } pub(crate) fn __reduce908< @@ -31634,7 +31667,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action1517::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant97(__nt), __end)); + __symbols.push((__start, __Symbol::Variant100(__nt), __end)); (1, 278) } pub(crate) fn __reduce909< @@ -31653,7 +31686,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action1518::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant97(__nt), __end)); + __symbols.push((__start, __Symbol::Variant100(__nt), __end)); (2, 278) } pub(crate) fn __reduce910< @@ -31672,7 +31705,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym1.2; let __nt = super::__action1519::<>(source_code, mode, __sym0, __sym1); - __symbols.push((__start, __Symbol::Variant97(__nt), __end)); + __symbols.push((__start, __Symbol::Variant100(__nt), __end)); (2, 278) } pub(crate) fn __reduce911< @@ -31688,12 +31721,12 @@ mod __parse__Top { assert!(__symbols.len() >= 4); let __sym3 = __pop_Variant0(__symbols); let __sym2 = __pop_Variant0(__symbols); - let __sym1 = __pop_Variant86(__symbols); + let __sym1 = __pop_Variant89(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym3.2; let __nt = super::__action1520::<>(source_code, mode, __sym0, __sym1, __sym2, __sym3); - __symbols.push((__start, __Symbol::Variant98(__nt), __end)); + __symbols.push((__start, __Symbol::Variant101(__nt), __end)); (4, 279) } pub(crate) fn __reduce912< @@ -31708,12 +31741,12 @@ mod __parse__Top { // TypeParams = "[", OneOrMore, "]" => ActionFn(1521); assert!(__symbols.len() >= 3); let __sym2 = __pop_Variant0(__symbols); - let __sym1 = __pop_Variant86(__symbols); + let __sym1 = __pop_Variant89(__symbols); let __sym0 = __pop_Variant0(__symbols); let __start = __sym0.0; let __end = __sym2.2; let __nt = super::__action1521::<>(source_code, mode, __sym0, __sym1, __sym2); - __symbols.push((__start, __Symbol::Variant98(__nt), __end)); + __symbols.push((__start, __Symbol::Variant101(__nt), __end)); (3, 279) } pub(crate) fn __reduce913< @@ -31726,11 +31759,11 @@ mod __parse__Top { ) -> (usize, usize) { // TypeParams? = TypeParams => ActionFn(309); - let __sym0 = __pop_Variant98(__symbols); + let __sym0 = __pop_Variant101(__symbols); let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action309::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant99(__nt), __end)); + __symbols.push((__start, __Symbol::Variant102(__nt), __end)); (1, 280) } pub(crate) fn __reduce914< @@ -31746,7 +31779,7 @@ mod __parse__Top { let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); let __nt = super::__action310::<>(source_code, mode, &__start, &__end); - __symbols.push((__start, __Symbol::Variant99(__nt), __end)); + __symbols.push((__start, __Symbol::Variant102(__nt), __end)); (0, 280) } pub(crate) fn __reduce915< @@ -31800,7 +31833,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action204::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant100(__nt), __end)); + __symbols.push((__start, __Symbol::Variant103(__nt), __end)); (1, 282) } pub(crate) fn __reduce918< @@ -31817,7 +31850,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action205::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant100(__nt), __end)); + __symbols.push((__start, __Symbol::Variant103(__nt), __end)); (1, 282) } pub(crate) fn __reduce919< @@ -31834,7 +31867,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action206::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant100(__nt), __end)); + __symbols.push((__start, __Symbol::Variant103(__nt), __end)); (1, 282) } pub(crate) fn __reduce920< @@ -32461,7 +32494,7 @@ mod __parse__Top { let __start = __sym0.0; let __end = __sym0.2; let __nt = super::__action281::<>(source_code, mode, __sym0); - __symbols.push((__start, __Symbol::Variant101(__nt), __end)); + __symbols.push((__start, __Symbol::Variant104(__nt), __end)); (1, 296) } pub(crate) fn __reduce953< @@ -32477,7 +32510,7 @@ mod __parse__Top { let __start = __lookahead_start.cloned().or_else(|| __symbols.last().map(|s| s.2.clone())).unwrap_or_default(); let __end = __start.clone(); let __nt = super::__action282::<>(source_code, mode, &__start, &__end); - __symbols.push((__start, __Symbol::Variant101(__nt), __end)); + __symbols.push((__start, __Symbol::Variant104(__nt), __end)); (0, 296) } } @@ -36348,14 +36381,14 @@ fn __action218< mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), - (_, values, _): (TextSize, alloc::vec::Vec, TextSize), + (_, elements, _): (TextSize, alloc::vec::Vec, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), ) -> StringType { { StringType::FString(ast::FString { - values, + elements, range: (location..end_location).into() }) } @@ -36367,8 +36400,8 @@ fn __action219< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::Expr, TextSize), -) -> ast::Expr + (_, __0, _): (TextSize, ast::FStringElement, TextSize), +) -> ast::FStringElement { __0 } @@ -36382,11 +36415,11 @@ fn __action220< (_, location, _): (TextSize, TextSize, TextSize), (_, fstring_middle, _): (TextSize, (String, bool), TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { { let (source, is_raw) = fstring_middle; - Ok(parse_fstring_middle(&source, is_raw, (location..end_location).into())?) + Ok(parse_fstring_literal_element(&source, is_raw, (location..end_location).into())?) } } @@ -36401,10 +36434,10 @@ fn __action221< (_, value, _): (TextSize, crate::parser::ParenthesizedExpr, TextSize), (_, debug, _): (TextSize, core::option::Option, TextSize), (_, conversion, _): (TextSize, core::option::Option<(TextSize, ast::ConversionFlag)>, TextSize), - (_, format_spec, _): (TextSize, core::option::Option, TextSize), + (_, format_spec, _): (TextSize, core::option::Option, TextSize), (_, _, _): (TextSize, token::Tok, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { { if value.expr.is_lambda_expr() && !value.is_parenthesized() { @@ -36429,16 +36462,15 @@ fn __action221< } }); Ok( - ast::ExprFormattedValue { - value: Box::new(value.into()), + ast::FStringElement::Expression(ast::FStringExpressionElement { + expression: Box::new(value.into()), debug_text, conversion: conversion.map_or(ast::ConversionFlag::None, |(_, conversion_flag)| { conversion_flag }), format_spec: format_spec.map(Box::new), range: (location..end_location).into(), - } - .into() + }) ) } } @@ -36450,8 +36482,8 @@ fn __action222< source_code: &str, mode: Mode, (_, _, _): (TextSize, token::Tok, TextSize), - (_, format_spec, _): (TextSize, ast::Expr, TextSize), -) -> ast::Expr + (_, format_spec, _): (TextSize, ast::FStringFormatSpec, TextSize), +) -> ast::FStringFormatSpec { format_spec } @@ -36463,15 +36495,13 @@ fn __action223< source_code: &str, mode: Mode, (_, location, _): (TextSize, TextSize, TextSize), - (_, values, _): (TextSize, alloc::vec::Vec, TextSize), + (_, elements, _): (TextSize, alloc::vec::Vec, TextSize), (_, end_location, _): (TextSize, TextSize, TextSize), -) -> ast::Expr +) -> ast::FStringFormatSpec { - { - ast::FString { - values, - range: (location..end_location).into() - }.into() + ast::FStringFormatSpec { + elements, + range: (location..end_location).into(), } } @@ -37142,8 +37172,8 @@ fn __action267< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::Expr, TextSize), -) -> core::option::Option + (_, __0, _): (TextSize, ast::FStringFormatSpec, TextSize), +) -> core::option::Option { Some(__0) } @@ -37156,7 +37186,7 @@ fn __action268< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> core::option::Option +) -> core::option::Option { None } @@ -37219,7 +37249,7 @@ fn __action273< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> alloc::vec::Vec +) -> alloc::vec::Vec { alloc::vec![] } @@ -37230,8 +37260,8 @@ fn __action274< >( source_code: &str, mode: Mode, - (_, v, _): (TextSize, alloc::vec::Vec, TextSize), -) -> alloc::vec::Vec + (_, v, _): (TextSize, alloc::vec::Vec, TextSize), +) -> alloc::vec::Vec { v } @@ -39813,8 +39843,8 @@ fn __action456< >( source_code: &str, mode: Mode, - (_, __0, _): (TextSize, ast::Expr, TextSize), -) -> alloc::vec::Vec + (_, __0, _): (TextSize, ast::FStringElement, TextSize), +) -> alloc::vec::Vec { alloc::vec![__0] } @@ -39825,9 +39855,9 @@ fn __action457< >( source_code: &str, mode: Mode, - (_, v, _): (TextSize, alloc::vec::Vec, TextSize), - (_, e, _): (TextSize, ast::Expr, TextSize), -) -> alloc::vec::Vec + (_, v, _): (TextSize, alloc::vec::Vec, TextSize), + (_, e, _): (TextSize, ast::FStringElement, TextSize), +) -> alloc::vec::Vec { { let mut v = v; v.push(e); v } } @@ -44486,10 +44516,10 @@ fn __action679< __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, token::Tok, TextSize), __4: (TextSize, core::option::Option<(TextSize, ast::ConversionFlag)>, TextSize), - __5: (TextSize, core::option::Option, TextSize), + __5: (TextSize, core::option::Option, TextSize), __6: (TextSize, token::Tok, TextSize), __7: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __3.0; let __end0 = __3.2; @@ -44523,10 +44553,10 @@ fn __action680< __1: (TextSize, token::Tok, TextSize), __2: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __3: (TextSize, core::option::Option<(TextSize, ast::ConversionFlag)>, TextSize), - __4: (TextSize, core::option::Option, TextSize), + __4: (TextSize, core::option::Option, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __2.2; let __end0 = __3.0; @@ -48416,7 +48446,7 @@ fn __action802< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, alloc::vec::Vec, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, TextSize, TextSize), ) -> StringType @@ -48447,9 +48477,9 @@ fn __action803< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), + __0: (TextSize, alloc::vec::Vec, TextSize), __1: (TextSize, TextSize, TextSize), -) -> ast::Expr +) -> ast::FStringFormatSpec { let __start0 = __0.0; let __end0 = __0.0; @@ -48477,7 +48507,7 @@ fn __action804< mode: Mode, __0: (TextSize, (String, bool), TextSize), __1: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.0; let __end0 = __0.0; @@ -48507,10 +48537,10 @@ fn __action805< __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, core::option::Option<(TextSize, ast::ConversionFlag)>, TextSize), - __4: (TextSize, core::option::Option, TextSize), + __4: (TextSize, core::option::Option, TextSize), __5: (TextSize, token::Tok, TextSize), __6: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.0; let __end0 = __0.0; @@ -48544,10 +48574,10 @@ fn __action806< __0: (TextSize, token::Tok, TextSize), __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, core::option::Option<(TextSize, ast::ConversionFlag)>, TextSize), - __3: (TextSize, core::option::Option, TextSize), + __3: (TextSize, core::option::Option, TextSize), __4: (TextSize, token::Tok, TextSize), __5: (TextSize, TextSize, TextSize), -) -> Result> +) -> Result> { let __start0 = __0.0; let __end0 = __0.0; @@ -64442,7 +64472,7 @@ fn __action1313< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, alloc::vec::Vec, TextSize), __2: (TextSize, token::Tok, TextSize), ) -> StringType { @@ -64471,8 +64501,8 @@ fn __action1314< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), -) -> ast::Expr + __0: (TextSize, alloc::vec::Vec, TextSize), +) -> ast::FStringFormatSpec { let __start0 = __0.2; let __end0 = __0.2; @@ -64498,7 +64528,7 @@ fn __action1315< source_code: &str, mode: Mode, __0: (TextSize, (String, bool), TextSize), -) -> Result> +) -> Result> { let __start0 = __0.2; let __end0 = __0.2; @@ -64527,9 +64557,9 @@ fn __action1316< __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, core::option::Option<(TextSize, ast::ConversionFlag)>, TextSize), - __4: (TextSize, core::option::Option, TextSize), + __4: (TextSize, core::option::Option, TextSize), __5: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __5.2; let __end0 = __5.2; @@ -64562,9 +64592,9 @@ fn __action1317< __0: (TextSize, token::Tok, TextSize), __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, core::option::Option<(TextSize, ast::ConversionFlag)>, TextSize), - __3: (TextSize, core::option::Option, TextSize), + __3: (TextSize, core::option::Option, TextSize), __4: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __4.2; let __end0 = __4.2; @@ -72535,9 +72565,9 @@ fn __action1577< __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, (TextSize, ast::ConversionFlag), TextSize), - __4: (TextSize, core::option::Option, TextSize), + __4: (TextSize, core::option::Option, TextSize), __5: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __3.0; let __end0 = __3.2; @@ -72568,9 +72598,9 @@ fn __action1578< __0: (TextSize, token::Tok, TextSize), __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, core::option::Option, TextSize), + __3: (TextSize, core::option::Option, TextSize), __4: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __2.2; let __end0 = __3.0; @@ -72602,9 +72632,9 @@ fn __action1579< __0: (TextSize, token::Tok, TextSize), __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, (TextSize, ast::ConversionFlag), TextSize), - __3: (TextSize, core::option::Option, TextSize), + __3: (TextSize, core::option::Option, TextSize), __4: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __2.0; let __end0 = __2.2; @@ -72633,9 +72663,9 @@ fn __action1580< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), - __2: (TextSize, core::option::Option, TextSize), + __2: (TextSize, core::option::Option, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __1.2; let __end0 = __2.0; @@ -72667,9 +72697,9 @@ fn __action1581< __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, (TextSize, ast::ConversionFlag), TextSize), - __4: (TextSize, ast::Expr, TextSize), + __4: (TextSize, ast::FStringFormatSpec, TextSize), __5: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __4.0; let __end0 = __4.2; @@ -72702,7 +72732,7 @@ fn __action1582< __2: (TextSize, token::Tok, TextSize), __3: (TextSize, (TextSize, ast::ConversionFlag), TextSize), __4: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __3.2; let __end0 = __4.0; @@ -72734,9 +72764,9 @@ fn __action1583< __0: (TextSize, token::Tok, TextSize), __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), - __3: (TextSize, ast::Expr, TextSize), + __3: (TextSize, ast::FStringFormatSpec, TextSize), __4: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __3.0; let __end0 = __3.2; @@ -72767,7 +72797,7 @@ fn __action1584< __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __2.2; let __end0 = __3.0; @@ -72798,9 +72828,9 @@ fn __action1585< __0: (TextSize, token::Tok, TextSize), __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, (TextSize, ast::ConversionFlag), TextSize), - __3: (TextSize, ast::Expr, TextSize), + __3: (TextSize, ast::FStringFormatSpec, TextSize), __4: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __3.0; let __end0 = __3.2; @@ -72831,7 +72861,7 @@ fn __action1586< __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, (TextSize, ast::ConversionFlag), TextSize), __3: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __2.2; let __end0 = __3.0; @@ -72861,9 +72891,9 @@ fn __action1587< mode: Mode, __0: (TextSize, token::Tok, TextSize), __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), - __2: (TextSize, ast::Expr, TextSize), + __2: (TextSize, ast::FStringFormatSpec, TextSize), __3: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __2.0; let __end0 = __2.2; @@ -72892,7 +72922,7 @@ fn __action1588< __0: (TextSize, token::Tok, TextSize), __1: (TextSize, crate::parser::ParenthesizedExpr, TextSize), __2: (TextSize, token::Tok, TextSize), -) -> Result> +) -> Result> { let __start0 = __1.2; let __end0 = __2.0; @@ -72948,7 +72978,7 @@ fn __action1590< source_code: &str, mode: Mode, __0: (TextSize, token::Tok, TextSize), - __1: (TextSize, alloc::vec::Vec, TextSize), + __1: (TextSize, alloc::vec::Vec, TextSize), __2: (TextSize, token::Tok, TextSize), ) -> StringType { @@ -72977,7 +73007,7 @@ fn __action1591< mode: Mode, __lookbehind: &TextSize, __lookahead: &TextSize, -) -> ast::Expr +) -> ast::FStringFormatSpec { let __start0 = *__lookbehind; let __end0 = *__lookahead; @@ -73001,8 +73031,8 @@ fn __action1592< >( source_code: &str, mode: Mode, - __0: (TextSize, alloc::vec::Vec, TextSize), -) -> ast::Expr + __0: (TextSize, alloc::vec::Vec, TextSize), +) -> ast::FStringFormatSpec { let __start0 = __0.0; let __end0 = __0.2; diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings.snap index b7e99b5722981..58c33b7302c9d 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings.snap @@ -14,11 +14,11 @@ expression: parse_ast FString( FString { range: 0..9, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..8, - value: StringLiteral( + expression: StringLiteral( ExprStringLiteral { range: 3..7, value: StringLiteralValue { @@ -57,11 +57,11 @@ expression: parse_ast FString( FString { range: 10..20, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 12..19, - value: Name( + expression: Name( ExprName { range: 13..16, id: "foo", @@ -93,11 +93,11 @@ expression: parse_ast FString( FString { range: 21..28, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 23..27, - value: Tuple( + expression: Tuple( ExprTuple { range: 24..26, elts: [ @@ -138,11 +138,11 @@ expression: parse_ast FString( FString { range: 29..39, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 31..38, - value: Compare( + expression: Compare( ExprCompare { range: 32..36, left: NumberLiteral( @@ -171,21 +171,10 @@ expression: parse_ast debug_text: None, conversion: None, format_spec: Some( - FString( - ExprFString { - range: 37..37, - value: FStringValue { - inner: Single( - FString( - FString { - range: 37..37, - values: [], - }, - ), - ), - }, - }, - ), + FStringFormatSpec { + range: 37..37, + elements: [], + }, ), }, ), @@ -209,11 +198,11 @@ expression: parse_ast FString( FString { range: 40..55, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 42..54, - value: NumberLiteral( + expression: NumberLiteral( ExprNumberLiteral { range: 43..44, value: Int( @@ -224,58 +213,39 @@ expression: parse_ast debug_text: None, conversion: None, format_spec: Some( - FString( - ExprFString { - range: 45..53, - value: FStringValue { - inner: Single( - FString( - FString { - range: 45..53, - values: [ - FormattedValue( - ExprFormattedValue { - range: 45..50, - value: StringLiteral( - ExprStringLiteral { - range: 46..49, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 46..49, - value: "}", - unicode: false, - }, - ), - }, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, + FStringFormatSpec { + range: 45..53, + elements: [ + Expression( + FStringExpressionElement { + range: 45..50, + expression: StringLiteral( + ExprStringLiteral { + range: 46..49, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 46..49, + value: "}", + unicode: false, }, ), - StringLiteral( - ExprStringLiteral { - range: 50..53, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 50..53, - value: ">10", - unicode: false, - }, - ), - }, - }, - ), - ], + }, }, ), - ), - }, - }, - ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + Literal( + FStringLiteralElement { + range: 50..53, + value: ">10", + }, + ), + ], + }, ), }, ), @@ -299,11 +269,11 @@ expression: parse_ast FString( FString { range: 56..71, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 58..70, - value: NumberLiteral( + expression: NumberLiteral( ExprNumberLiteral { range: 59..60, value: Int( @@ -314,58 +284,39 @@ expression: parse_ast debug_text: None, conversion: None, format_spec: Some( - FString( - ExprFString { - range: 61..69, - value: FStringValue { - inner: Single( - FString( - FString { - range: 61..69, - values: [ - FormattedValue( - ExprFormattedValue { - range: 61..66, - value: StringLiteral( - ExprStringLiteral { - range: 62..65, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 62..65, - value: "{", - unicode: false, - }, - ), - }, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - StringLiteral( - ExprStringLiteral { - range: 66..69, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 66..69, - value: ">10", - unicode: false, - }, - ), - }, + FStringFormatSpec { + range: 61..69, + elements: [ + Expression( + FStringExpressionElement { + range: 61..66, + expression: StringLiteral( + ExprStringLiteral { + range: 62..65, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 62..65, + value: "{", + unicode: false, }, ), - ], + }, }, ), - ), - }, - }, - ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + Literal( + FStringLiteralElement { + range: 66..69, + value: ">10", + }, + ), + ], + }, ), }, ), @@ -389,11 +340,11 @@ expression: parse_ast FString( FString { range: 72..86, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 74..85, - value: Name( + expression: Name( ExprName { range: 77..80, id: "foo", @@ -430,11 +381,11 @@ expression: parse_ast FString( FString { range: 87..107, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 89..106, - value: Name( + expression: Name( ExprName { range: 92..95, id: "foo", @@ -449,36 +400,17 @@ expression: parse_ast ), conversion: None, format_spec: Some( - FString( - ExprFString { - range: 100..105, - value: FStringValue { - inner: Single( - FString( - FString { - range: 100..105, - values: [ - StringLiteral( - ExprStringLiteral { - range: 100..105, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 100..105, - value: ".3f ", - unicode: false, - }, - ), - }, - }, - ), - ], - }, - ), - ), - }, - }, - ), + FStringFormatSpec { + range: 100..105, + elements: [ + Literal( + FStringLiteralElement { + range: 100..105, + value: ".3f ", + }, + ), + ], + }, ), }, ), @@ -502,11 +434,11 @@ expression: parse_ast FString( FString { range: 108..126, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 110..125, - value: Name( + expression: Name( ExprName { range: 113..116, id: "foo", @@ -543,11 +475,11 @@ expression: parse_ast FString( FString { range: 127..143, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 129..142, - value: Tuple( + expression: Tuple( ExprTuple { range: 132..136, elts: [ @@ -601,11 +533,11 @@ expression: parse_ast FString( FString { range: 144..170, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 146..169, - value: FString( + expression: FString( ExprFString { range: 147..163, value: FStringValue { @@ -613,11 +545,11 @@ expression: parse_ast FString( FString { range: 147..163, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 149..162, - value: NumberLiteral( + expression: NumberLiteral( ExprNumberLiteral { range: 150..156, value: Float( @@ -633,36 +565,17 @@ expression: parse_ast ), conversion: None, format_spec: Some( - FString( - ExprFString { - range: 158..161, - value: FStringValue { - inner: Single( - FString( - FString { - range: 158..161, - values: [ - StringLiteral( - ExprStringLiteral { - range: 158..161, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 158..161, - value: ".1f", - unicode: false, - }, - ), - }, - }, - ), - ], - }, - ), - ), - }, - }, - ), + FStringFormatSpec { + range: 158..161, + elements: [ + Literal( + FStringLiteralElement { + range: 158..161, + value: ".1f", + }, + ), + ], + }, ), }, ), @@ -676,36 +589,17 @@ expression: parse_ast debug_text: None, conversion: None, format_spec: Some( - FString( - ExprFString { - range: 164..168, - value: FStringValue { - inner: Single( - FString( - FString { - range: 164..168, - values: [ - StringLiteral( - ExprStringLiteral { - range: 164..168, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 164..168, - value: "*^20", - unicode: false, - }, - ), - }, - }, - ), - ], - }, - ), - ), - }, - }, - ), + FStringFormatSpec { + range: 164..168, + elements: [ + Literal( + FStringLiteralElement { + range: 164..168, + value: "*^20", + }, + ), + ], + }, ), }, ), @@ -742,25 +636,17 @@ expression: parse_ast FString( FString { range: 180..195, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 182..186, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 182..186, - value: "bar ", - unicode: false, - }, - ), - }, + value: "bar ", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 186..193, - value: BinOp( + expression: BinOp( ExprBinOp { range: 187..192, left: Name( @@ -785,18 +671,10 @@ expression: parse_ast format_spec: None, }, ), - StringLiteral( - ExprStringLiteral { + Literal( + FStringLiteralElement { range: 193..194, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 193..194, - value: " ", - unicode: false, - }, - ), - }, + value: " ", }, ), ], @@ -925,25 +803,17 @@ expression: parse_ast FString( FString { range: 300..317, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 302..303, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 302..303, - value: "\\", - unicode: false, - }, - ), - }, + value: "\\", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 303..308, - value: Name( + expression: Name( ExprName { range: 304..307, id: "foo", @@ -955,24 +825,16 @@ expression: parse_ast format_spec: None, }, ), - StringLiteral( - ExprStringLiteral { + Literal( + FStringLiteralElement { range: 308..309, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 308..309, - value: "\\", - unicode: false, - }, - ), - }, + value: "\\", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 309..316, - value: Name( + expression: Name( ExprName { range: 310..313, id: "bar", @@ -982,36 +844,17 @@ expression: parse_ast debug_text: None, conversion: None, format_spec: Some( - FString( - ExprFString { - range: 314..315, - value: FStringValue { - inner: Single( - FString( - FString { - range: 314..315, - values: [ - StringLiteral( - ExprStringLiteral { - range: 314..315, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 314..315, - value: "\\", - unicode: false, - }, - ), - }, - }, - ), - ], - }, - ), - ), - }, - }, - ), + FStringFormatSpec { + range: 314..315, + elements: [ + Literal( + FStringLiteralElement { + range: 314..315, + value: "\\", + }, + ), + ], + }, ), }, ), @@ -1035,19 +878,11 @@ expression: parse_ast FString( FString { range: 318..332, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 320..331, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 320..331, - value: "\\{foo\\}", - unicode: false, - }, - ), - }, + value: "\\{foo\\}", }, ), ], @@ -1070,11 +905,11 @@ expression: parse_ast FString( FString { range: 333..373, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 337..370, - value: Name( + expression: Name( ExprName { range: 343..346, id: "foo", @@ -1084,36 +919,17 @@ expression: parse_ast debug_text: None, conversion: None, format_spec: Some( - FString( - ExprFString { - range: 347..369, - value: FStringValue { - inner: Single( - FString( - FString { - range: 347..369, - values: [ - StringLiteral( - ExprStringLiteral { - range: 347..369, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 347..369, - value: "x\n y\n z\n", - unicode: false, - }, - ), - }, - }, - ), - ], - }, - ), - ), - }, - }, - ), + FStringFormatSpec { + range: 347..369, + elements: [ + Literal( + FStringLiteralElement { + range: 347..369, + value: "x\n y\n z\n", + }, + ), + ], + }, ), }, ), diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings_with_unicode.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings_with_unicode.snap index 7373b5c2b69ed..705c6e4d47155 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings_with_unicode.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__fstrings_with_unicode.snap @@ -22,11 +22,11 @@ expression: parse_ast FString( FString { range: 7..15, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 9..14, - value: Name( + expression: Name( ExprName { range: 10..13, id: "bar", @@ -81,11 +81,11 @@ expression: parse_ast FString( FString { range: 36..44, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 38..43, - value: Name( + expression: Name( ExprName { range: 39..42, id: "bar", @@ -140,11 +140,11 @@ expression: parse_ast FString( FString { range: 66..74, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 68..73, - value: Name( + expression: Name( ExprName { range: 69..72, id: "bar", @@ -199,25 +199,17 @@ expression: parse_ast FString( FString { range: 97..116, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 99..103, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 99..103, - value: "bar ", - unicode: false, - }, - ), - }, + value: "bar ", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 103..108, - value: Name( + expression: Name( ExprName { range: 104..107, id: "baz", @@ -229,18 +221,10 @@ expression: parse_ast format_spec: None, }, ), - StringLiteral( - ExprStringLiteral { + Literal( + FStringLiteralElement { range: 108..115, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 108..115, - value: " really", - unicode: false, - }, - ), - }, + value: " really", }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap index d99fa9e549dc1..84364a344ec01 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap @@ -14,19 +14,11 @@ expression: parse_ast FString( FString { range: 0..14, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 2..13, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 2..13, - value: "Hello world", - unicode: false, - }, - ), - }, + value: "Hello world", }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap index a5e05daf58373..f2497947cac46 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap @@ -86,25 +86,17 @@ expression: parse_ast FString( FString { range: 62..81, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 64..71, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 64..71, - value: "caught ", - unicode: false, - }, - ), - }, + value: "caught ", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 71..80, - value: Call( + expression: Call( ExprCall { range: 72..79, func: Name( @@ -194,25 +186,17 @@ expression: parse_ast FString( FString { range: 114..133, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 116..123, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 116..123, - value: "caught ", - unicode: false, - }, - ), - }, + value: "caught ", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 123..132, - value: Call( + expression: Call( ExprCall { range: 124..131, func: Name( diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap index eb9cfeefb9791..220516c86bffd 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap @@ -204,25 +204,17 @@ expression: parse_ast FString( FString { range: 133..179, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 135..142, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 135..142, - value: "caught ", - unicode: false, - }, - ), - }, + value: "caught ", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 142..151, - value: Call( + expression: Call( ExprCall { range: 143..150, func: Name( @@ -252,24 +244,16 @@ expression: parse_ast format_spec: None, }, ), - StringLiteral( - ExprStringLiteral { + Literal( + FStringLiteralElement { range: 151..164, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 151..164, - value: " with nested ", - unicode: false, - }, - ), - }, + value: " with nested ", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 164..178, - value: Attribute( + expression: Attribute( ExprAttribute { range: 165..177, value: Name( @@ -351,25 +335,17 @@ expression: parse_ast FString( FString { range: 213..259, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 215..222, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 215..222, - value: "caught ", - unicode: false, - }, - ), - }, + value: "caught ", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 222..231, - value: Call( + expression: Call( ExprCall { range: 223..230, func: Name( @@ -399,24 +375,16 @@ expression: parse_ast format_spec: None, }, ), - StringLiteral( - ExprStringLiteral { + Literal( + FStringLiteralElement { range: 231..244, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 231..244, - value: " with nested ", - unicode: false, - }, - ), - }, + value: " with nested ", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 244..258, - value: Attribute( + expression: Attribute( ExprAttribute { range: 245..257, value: Name( diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap index 4575aad44eb22..ef91cbf428fdb 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap @@ -14,25 +14,17 @@ expression: parse_ast FString( FString { range: 0..22, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 2..5, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 2..5, - value: "aaa", - unicode: false, - }, - ), - }, + value: "aaa", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 5..10, - value: Name( + expression: Name( ExprName { range: 6..9, id: "bbb", @@ -44,24 +36,16 @@ expression: parse_ast format_spec: None, }, ), - StringLiteral( - ExprStringLiteral { + Literal( + FStringLiteralElement { range: 10..13, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 10..13, - value: "ccc", - unicode: false, - }, - ), - }, + value: "ccc", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 13..18, - value: Name( + expression: Name( ExprName { range: 14..17, id: "ddd", @@ -73,18 +57,10 @@ expression: parse_ast format_spec: None, }, ), - StringLiteral( - ExprStringLiteral { + Literal( + FStringLiteralElement { range: 18..21, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 18..21, - value: "eee", - unicode: false, - }, - ), - }, + value: "eee", }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap index 2ded682ed4633..8353b0e11c1d8 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap @@ -14,25 +14,17 @@ expression: parse_ast FString( FString { range: 0..8, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 2..4, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 2..4, - value: "\\", - unicode: false, - }, - ), - }, + value: "\\", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 4..7, - value: Name( + expression: Name( ExprName { range: 5..6, id: "x", diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap index d7090ab4c0cb9..5394a34336341 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap @@ -14,25 +14,17 @@ expression: parse_ast FString( FString { range: 0..8, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 2..4, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 2..4, - value: "\n", - unicode: false, - }, - ), - }, + value: "\n", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 4..7, - value: Name( + expression: Name( ExprName { range: 5..6, id: "x", diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap index 92ac071ae5ba9..10c759fefa07e 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap @@ -14,25 +14,17 @@ expression: parse_ast FString( FString { range: 0..9, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 3..5, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 3..5, - value: "\\\n", - unicode: false, - }, - ), - }, + value: "\\\n", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 5..8, - value: Name( + expression: Name( ExprName { range: 6..7, id: "x", diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap index 476a5a3f53fd5..f01086439af1a 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap @@ -14,11 +14,11 @@ expression: parse_ast FString( FString { range: 0..10, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..9, - value: Name( + expression: Name( ExprName { range: 3..7, id: "user", diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap index 765076eddb6c2..fe5c4f3497e08 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap @@ -14,25 +14,17 @@ expression: parse_ast FString( FString { range: 0..38, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 2..6, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 2..6, - value: "mix ", - unicode: false, - }, - ), - }, + value: "mix ", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 6..13, - value: Name( + expression: Name( ExprName { range: 7..11, id: "user", @@ -49,24 +41,16 @@ expression: parse_ast format_spec: None, }, ), - StringLiteral( - ExprStringLiteral { + Literal( + FStringLiteralElement { range: 13..28, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 13..28, - value: " with text and ", - unicode: false, - }, - ), - }, + value: " with text and ", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 28..37, - value: Name( + expression: Name( ExprName { range: 29..35, id: "second", diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap index d34b5387ad99c..26d2fb22bef9a 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap @@ -14,11 +14,11 @@ expression: parse_ast FString( FString { range: 0..14, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..13, - value: Name( + expression: Name( ExprName { range: 3..7, id: "user", @@ -33,36 +33,17 @@ expression: parse_ast ), conversion: None, format_spec: Some( - FString( - ExprFString { - range: 9..12, - value: FStringValue { - inner: Single( - FString( - FString { - range: 9..12, - values: [ - StringLiteral( - ExprStringLiteral { - range: 9..12, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 9..12, - value: ">10", - unicode: false, - }, - ), - }, - }, - ), - ], - }, - ), - ), - }, - }, - ), + FStringFormatSpec { + range: 9..12, + elements: [ + Literal( + FStringLiteralElement { + range: 9..12, + value: ">10", + }, + ), + ], + }, ), }, ), diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap index a6079454028a7..55797fae098c7 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap @@ -14,25 +14,17 @@ expression: parse_ast FString( FString { range: 0..11, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 4..5, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 4..5, - value: "\n", - unicode: false, - }, - ), - }, + value: "\n", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 5..8, - value: Name( + expression: Name( ExprName { range: 6..7, id: "x", diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap index a4375d213f044..fccf2a0b9e18c 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap @@ -14,7 +14,7 @@ expression: "parse_suite(r#\"f\"\"\"#, \"\").unwrap()" FString( FString { range: 0..3, - values: [], + elements: [], }, ), ), diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap index 5e831e22e6bc1..3fa34cf133205 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap @@ -22,19 +22,11 @@ expression: parse_ast FString( FString { range: 9..17, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 11..16, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 11..16, - value: "world", - unicode: false, - }, - ), - }, + value: "world", }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap index 5e831e22e6bc1..3fa34cf133205 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap @@ -22,19 +22,11 @@ expression: parse_ast FString( FString { range: 9..17, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 11..16, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 11..16, - value: "world", - unicode: false, - }, - ), - }, + value: "world", }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap index c59b4bc18654d..62c35e88a4483 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap @@ -22,25 +22,17 @@ expression: parse_ast FString( FString { range: 9..22, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 11..16, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 11..16, - value: "world", - unicode: false, - }, - ), - }, + value: "world", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 16..21, - value: StringLiteral( + expression: StringLiteral( ExprStringLiteral { range: 17..20, value: StringLiteralValue { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap index 4d777817d7052..05f12455f3dbb 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap @@ -22,25 +22,17 @@ expression: parse_ast FString( FString { range: 9..22, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 11..16, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 11..16, - value: "world", - unicode: false, - }, - ), - }, + value: "world", }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 16..21, - value: StringLiteral( + expression: StringLiteral( ExprStringLiteral { range: 17..20, value: StringLiteralValue { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap index c3894637985e7..5b24ddca1728e 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap @@ -14,11 +14,11 @@ expression: parse_ast FString( FString { range: 0..18, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..5, - value: Name( + expression: Name( ExprName { range: 3..4, id: "a", @@ -30,10 +30,10 @@ expression: parse_ast format_spec: None, }, ), - FormattedValue( - ExprFormattedValue { + Expression( + FStringExpressionElement { range: 5..10, - value: Name( + expression: Name( ExprName { range: 7..8, id: "b", @@ -45,18 +45,10 @@ expression: parse_ast format_spec: None, }, ), - StringLiteral( - ExprStringLiteral { + Literal( + FStringLiteralElement { range: 10..17, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 10..17, - value: "{foo}", - unicode: false, - }, - ), - }, + value: "{foo}", }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap index fc8338ee70ac7..0972b502da856 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap @@ -14,11 +14,11 @@ expression: parse_ast FString( FString { range: 0..13, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..12, - value: Compare( + expression: Compare( ExprCompare { range: 3..11, left: NumberLiteral( diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap index fdb3a6fc90221..fe1418fc69069 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap @@ -14,11 +14,11 @@ expression: parse_ast FString( FString { range: 0..16, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..15, - value: Name( + expression: Name( ExprName { range: 3..6, id: "foo", @@ -28,54 +28,43 @@ expression: parse_ast debug_text: None, conversion: None, format_spec: Some( - FString( - ExprFString { - range: 7..14, - value: FStringValue { - inner: Single( - FString( - FString { - range: 7..14, - values: [ - FormattedValue( - ExprFormattedValue { - range: 7..14, - value: StringLiteral( - ExprStringLiteral { - range: 8..13, - value: StringLiteralValue { - inner: Concatenated( - ConcatenatedStringLiteral { - strings: [ - StringLiteral { - range: 8..10, - value: "", - unicode: false, - }, - StringLiteral { - range: 11..13, - value: "", - unicode: false, - }, - ], - value: "", - }, - ), - }, + FStringFormatSpec { + range: 7..14, + elements: [ + Expression( + FStringExpressionElement { + range: 7..14, + expression: StringLiteral( + ExprStringLiteral { + range: 8..13, + value: StringLiteralValue { + inner: Concatenated( + ConcatenatedStringLiteral { + strings: [ + StringLiteral { + range: 8..10, + value: "", + unicode: false, }, - ), - debug_text: None, - conversion: None, - format_spec: None, + StringLiteral { + range: 11..13, + value: "", + unicode: false, + }, + ], + value: "", }, ), - ], + }, }, ), - ), - }, - }, - ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, ), }, ), diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap index 3ffcbc7c9edb4..d4e72897e0e04 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap @@ -14,11 +14,11 @@ expression: parse_ast FString( FString { range: 0..15, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..14, - value: Name( + expression: Name( ExprName { range: 3..6, id: "foo", @@ -28,37 +28,26 @@ expression: parse_ast debug_text: None, conversion: None, format_spec: Some( - FString( - ExprFString { - range: 7..13, - value: FStringValue { - inner: Single( - FString( - FString { - range: 7..13, - values: [ - FormattedValue( - ExprFormattedValue { - range: 7..13, - value: Name( - ExprName { - range: 8..12, - id: "spec", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - ], + FStringFormatSpec { + range: 7..13, + elements: [ + Expression( + FStringExpressionElement { + range: 7..13, + expression: Name( + ExprName { + range: 8..12, + id: "spec", + ctx: Load, }, ), - ), - }, - }, - ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, ), }, ), diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap index 06e925c016b72..c00e35f945ff1 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap @@ -14,11 +14,11 @@ expression: parse_ast FString( FString { range: 0..13, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..12, - value: Name( + expression: Name( ExprName { range: 3..6, id: "foo", @@ -28,44 +28,33 @@ expression: parse_ast debug_text: None, conversion: None, format_spec: Some( - FString( - ExprFString { - range: 7..11, - value: FStringValue { - inner: Single( - FString( - FString { - range: 7..11, - values: [ - FormattedValue( - ExprFormattedValue { - range: 7..11, - value: StringLiteral( - ExprStringLiteral { - range: 8..10, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 8..10, - value: "", - unicode: false, - }, - ), - }, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, + FStringFormatSpec { + range: 7..11, + elements: [ + Expression( + FStringExpressionElement { + range: 7..11, + expression: StringLiteral( + ExprStringLiteral { + range: 8..10, + value: StringLiteralValue { + inner: Single( + StringLiteral { + range: 8..10, + value: "", + unicode: false, }, ), - ], + }, }, ), - ), - }, - }, - ), + debug_text: None, + conversion: None, + format_spec: None, + }, + ), + ], + }, ), }, ), diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap index c4aee850245c2..b1284e5cca29c 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap @@ -14,11 +14,11 @@ expression: parse_ast FString( FString { range: 0..11, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..10, - value: Compare( + expression: Compare( ExprCompare { range: 3..9, left: NumberLiteral( diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap index 6b8b11fe88c13..ba4061fddeee7 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap @@ -14,11 +14,11 @@ expression: parse_ast FString( FString { range: 0..13, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..12, - value: Name( + expression: Name( ExprName { range: 3..6, id: "foo", @@ -28,36 +28,17 @@ expression: parse_ast debug_text: None, conversion: None, format_spec: Some( - FString( - ExprFString { - range: 7..11, - value: FStringValue { - inner: Single( - FString( - FString { - range: 7..11, - values: [ - StringLiteral( - ExprStringLiteral { - range: 7..11, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 7..11, - value: "spec", - unicode: false, - }, - ), - }, - }, - ), - ], - }, - ), - ), - }, - }, - ), + FStringFormatSpec { + range: 7..11, + elements: [ + Literal( + FStringLiteralElement { + range: 7..11, + value: "spec", + }, + ), + ], + }, ), }, ), diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap index fd024631ef18b..7c3ec7583dd4e 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap @@ -14,11 +14,11 @@ expression: parse_ast FString( FString { range: 0..10, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..9, - value: Name( + expression: Name( ExprName { range: 3..4, id: "x", diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap index c1f08c3397dd8..47b37caa7f340 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap @@ -14,11 +14,11 @@ expression: parse_ast FString( FString { range: 0..10, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..9, - value: Name( + expression: Name( ExprName { range: 3..4, id: "x", diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap index 20ccfbf7e1379..39219b2044779 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap @@ -14,11 +14,11 @@ expression: parse_ast FString( FString { range: 0..10, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..9, - value: Yield( + expression: Yield( ExprYield { range: 3..8, value: None, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap index c8495e4b318e2..f28bda3133050 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap @@ -22,19 +22,11 @@ expression: parse_ast FString( FString { range: 10..18, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 12..17, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 12..17, - value: "world", - unicode: false, - }, - ), - }, + value: "world", }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap index 9278f809af668..dc6afd4e42494 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap @@ -22,19 +22,11 @@ expression: parse_ast FString( FString { range: 10..18, - values: [ - StringLiteral( - ExprStringLiteral { + elements: [ + Literal( + FStringLiteralElement { range: 12..17, - value: StringLiteralValue { - inner: Single( - StringLiteral { - range: 12..17, - value: "world", - unicode: false, - }, - ), - }, + value: "world", }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap index 100bf1ed55946..05fe49bbf73ad 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap @@ -14,11 +14,11 @@ expression: parse_ast FString( FString { range: 0..7, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 3..6, - value: Name( + expression: Name( ExprName { range: 4..5, id: "x", diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap index 872fe090c8071..c772d6a052128 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap @@ -14,11 +14,11 @@ expression: parse_ast FString( FString { range: 0..11, - values: [ - FormattedValue( - ExprFormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 5..8, - value: Name( + expression: Name( ExprName { range: 6..7, id: "x", diff --git a/crates/ruff_python_parser/src/string.rs b/crates/ruff_python_parser/src/string.rs index 2d4f2c5df926a..ab9106ff31a25 100644 --- a/crates/ruff_python_parser/src/string.rs +++ b/crates/ruff_python_parser/src/string.rs @@ -202,7 +202,7 @@ impl<'a> StringParser<'a> { Ok(()) } - fn parse_fstring_middle(&mut self) -> Result { + fn parse_fstring_middle(&mut self) -> Result { let mut value = String::new(); while let Some(ch) = self.next_char() { match ch { @@ -239,9 +239,8 @@ impl<'a> StringParser<'a> { ch => value.push(ch), } } - Ok(Expr::from(ast::StringLiteral { + Ok(ast::FStringElement::Literal(ast::FStringLiteralElement { value, - unicode: false, range: self.range, })) } @@ -324,11 +323,11 @@ pub(crate) fn parse_string_literal( StringParser::new(source, kind, start_location, range).parse() } -pub(crate) fn parse_fstring_middle( +pub(crate) fn parse_fstring_literal_element( source: &str, is_raw: bool, range: TextRange, -) -> Result { +) -> Result { let kind = if is_raw { StringKind::RawString } else { diff --git a/crates/ruff_python_semantic/src/analyze/type_inference.rs b/crates/ruff_python_semantic/src/analyze/type_inference.rs index f5261cd683664..427bdddca3e22 100644 --- a/crates/ruff_python_semantic/src/analyze/type_inference.rs +++ b/crates/ruff_python_semantic/src/analyze/type_inference.rs @@ -323,7 +323,6 @@ impl From<&Expr> for ResolvedPythonType { | Expr::YieldFrom(_) | Expr::Compare(_) | Expr::Call(_) - | Expr::FormattedValue(_) | Expr::Attribute(_) | Expr::Subscript(_) | Expr::Starred(_) From 96ae9fe6856c3d1d8ed1bd94c73954662d28f2d6 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Thu, 7 Dec 2023 10:39:13 -0600 Subject: [PATCH 137/197] Introduce `StringLike` enum (#9016) ## Summary This PR introduces a new `StringLike` enum which is a narrow type to indicate string-like nodes. These includes the string literals, bytes literals, and the literal parts of f-strings. The main motivation behind this is to avoid repetition of rule calling in the AST checker. We add a new `analyze::string_like` function which takes in the enum and calls all the respective rule functions which expects atleast 2 of the variants of this enum. I'm open to discarding this if others think it's not that useful at this stage as currently only 3 rules require these nodes. As suggested [here](https://github.com/astral-sh/ruff/pull/8835#discussion_r1414746934) and [here](https://github.com/astral-sh/ruff/pull/8835#discussion_r1414750204). ## Test Plan `cargo test` --- .../src/checkers/ast/analyze/expression.rs | 53 +------------------ .../src/checkers/ast/analyze/mod.rs | 2 + .../src/checkers/ast/analyze/string_like.rs | 20 +++++++ crates/ruff_linter/src/checkers/ast/mod.rs | 19 ++++++- .../rules/hardcoded_bind_all_interfaces.rs | 15 ++++-- .../rules/hardcoded_tmp_directory.rs | 14 +++-- .../rules/string_or_bytes_too_long.rs | 19 +++---- crates/ruff_python_ast/src/expression.rs | 38 +++++++++++++ 8 files changed, 108 insertions(+), 72 deletions(-) create mode 100644 crates/ruff_linter/src/checkers/ast/analyze/string_like.rs diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 45cbcea34e8f5..64b2d1a8abcd0 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -4,7 +4,6 @@ use ruff_python_literal::cformat::{CFormatError, CFormatErrorType}; use ruff_diagnostics::Diagnostic; use ruff_python_ast::types::Node; -use ruff_python_ast::AstNode; use ruff_python_semantic::analyze::typing; use ruff_python_semantic::ScopeKind; use ruff_text_size::Ranged; @@ -1007,30 +1006,6 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { pyupgrade::rules::unicode_kind_prefix(checker, string_literal); } } - for literal in value.elements().filter_map(|element| element.as_literal()) { - if checker.enabled(Rule::HardcodedBindAllInterfaces) { - flake8_bandit::rules::hardcoded_bind_all_interfaces( - checker, - &literal.value, - literal.range, - ); - } - if checker.enabled(Rule::HardcodedTempFile) { - flake8_bandit::rules::hardcoded_tmp_directory( - checker, - &literal.value, - literal.range, - ); - } - if checker.source_type.is_stub() { - if checker.enabled(Rule::StringOrBytesTooLong) { - flake8_pyi::rules::string_or_bytes_too_long( - checker, - literal.as_any_node_ref(), - ); - } - } - } } Expr::BinOp(ast::ExprBinOp { left, @@ -1295,38 +1270,12 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { refurb::rules::math_constant(checker, number_literal); } } - Expr::BytesLiteral(bytes_literal) => { - if checker.source_type.is_stub() && checker.enabled(Rule::StringOrBytesTooLong) { - flake8_pyi::rules::string_or_bytes_too_long( - checker, - bytes_literal.as_any_node_ref(), - ); - } - } - Expr::StringLiteral(string_literal @ ast::ExprStringLiteral { value, range }) => { - if checker.enabled(Rule::HardcodedBindAllInterfaces) { - flake8_bandit::rules::hardcoded_bind_all_interfaces( - checker, - value.to_str(), - *range, - ); - } - if checker.enabled(Rule::HardcodedTempFile) { - flake8_bandit::rules::hardcoded_tmp_directory(checker, value.to_str(), *range); - } + Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { if checker.enabled(Rule::UnicodeKindPrefix) { for string_part in value.parts() { pyupgrade::rules::unicode_kind_prefix(checker, string_part); } } - if checker.source_type.is_stub() { - if checker.enabled(Rule::StringOrBytesTooLong) { - flake8_pyi::rules::string_or_bytes_too_long( - checker, - string_literal.as_any_node_ref(), - ); - } - } } Expr::IfExp( if_exp @ ast::ExprIfExp { diff --git a/crates/ruff_linter/src/checkers/ast/analyze/mod.rs b/crates/ruff_linter/src/checkers/ast/analyze/mod.rs index dd9ec2fbfd2ce..deeb55864b569 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/mod.rs @@ -10,6 +10,7 @@ pub(super) use module::module; pub(super) use parameter::parameter; pub(super) use parameters::parameters; pub(super) use statement::statement; +pub(super) use string_like::string_like; pub(super) use suite::suite; pub(super) use unresolved_references::unresolved_references; @@ -25,5 +26,6 @@ mod module; mod parameter; mod parameters; mod statement; +mod string_like; mod suite; mod unresolved_references; diff --git a/crates/ruff_linter/src/checkers/ast/analyze/string_like.rs b/crates/ruff_linter/src/checkers/ast/analyze/string_like.rs new file mode 100644 index 0000000000000..c3c8fb3367eec --- /dev/null +++ b/crates/ruff_linter/src/checkers/ast/analyze/string_like.rs @@ -0,0 +1,20 @@ +use ruff_python_ast::StringLike; + +use crate::checkers::ast::Checker; +use crate::codes::Rule; +use crate::rules::{flake8_bandit, flake8_pyi}; + +/// Run lint rules over a [`StringLike`] syntax nodes. +pub(crate) fn string_like(string_like: StringLike, checker: &mut Checker) { + if checker.enabled(Rule::HardcodedBindAllInterfaces) { + flake8_bandit::rules::hardcoded_bind_all_interfaces(checker, string_like); + } + if checker.enabled(Rule::HardcodedTempFile) { + flake8_bandit::rules::hardcoded_tmp_directory(checker, string_like); + } + if checker.source_type.is_stub() { + if checker.enabled(Rule::StringOrBytesTooLong) { + flake8_pyi::rules::string_or_bytes_too_long(checker, string_like); + } + } +} diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 21a0a944115dd..91b9a96deaa98 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -44,7 +44,7 @@ use ruff_python_ast::helpers::{ }; use ruff_python_ast::identifier::Identifier; use ruff_python_ast::str::trailing_quote; -use ruff_python_ast::visitor::{walk_except_handler, walk_pattern, Visitor}; +use ruff_python_ast::visitor::{walk_except_handler, walk_f_string_element, walk_pattern, Visitor}; use ruff_python_ast::{helpers, str, visitor, PySourceType}; use ruff_python_codegen::{Generator, Quote, Stylist}; use ruff_python_index::Indexer; @@ -1267,6 +1267,13 @@ where // Step 4: Analysis analyze::expression(expr, self); + match expr { + Expr::StringLiteral(string_literal) => { + analyze::string_like(string_literal.into(), self); + } + Expr::BytesLiteral(bytes_literal) => analyze::string_like(bytes_literal.into(), self), + _ => {} + } self.semantic.flags = flags_snapshot; self.semantic.pop_node(); @@ -1431,6 +1438,16 @@ where .push((bound, self.semantic.snapshot())); } } + + fn visit_f_string_element(&mut self, f_string_element: &'b ast::FStringElement) { + // Step 2: Traversal + walk_f_string_element(self, f_string_element); + + // Step 4: Analysis + if let Some(literal) = f_string_element.as_literal() { + analyze::string_like(literal.into(), self); + } + } } impl<'a> Checker<'a> { diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs index d5cf806f868f2..38295b71316a2 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs @@ -1,6 +1,7 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_text_size::TextRange; +use ruff_python_ast::{self as ast, StringLike}; +use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -36,10 +37,16 @@ impl Violation for HardcodedBindAllInterfaces { } /// S104 -pub(crate) fn hardcoded_bind_all_interfaces(checker: &mut Checker, value: &str, range: TextRange) { - if value == "0.0.0.0" { +pub(crate) fn hardcoded_bind_all_interfaces(checker: &mut Checker, string: StringLike) { + let is_bind_all_interface = match string { + StringLike::StringLiteral(ast::ExprStringLiteral { value, .. }) => value == "0.0.0.0", + StringLike::FStringLiteral(ast::FStringLiteralElement { value, .. }) => value == "0.0.0.0", + StringLike::BytesLiteral(_) => return, + }; + + if is_bind_all_interface { checker .diagnostics - .push(Diagnostic::new(HardcodedBindAllInterfaces, range)); + .push(Diagnostic::new(HardcodedBindAllInterfaces, string.range())); } } diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs index 469084ad435fb..e0a66fec19631 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs @@ -1,5 +1,5 @@ -use ruff_python_ast::{self as ast, Expr}; -use ruff_text_size::TextRange; +use ruff_python_ast::{self as ast, Expr, StringLike}; +use ruff_text_size::Ranged; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; @@ -52,7 +52,13 @@ impl Violation for HardcodedTempFile { } /// S108 -pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, value: &str, range: TextRange) { +pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, string: StringLike) { + let value = match string { + StringLike::StringLiteral(ast::ExprStringLiteral { value, .. }) => value.to_str(), + StringLike::FStringLiteral(ast::FStringLiteralElement { value, .. }) => value, + StringLike::BytesLiteral(_) => return, + }; + if !checker .settings .flake8_bandit @@ -79,6 +85,6 @@ pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, value: &str, range: HardcodedTempFile { string: value.to_string(), }, - range, + string.range(), )); } diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/string_or_bytes_too_long.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/string_or_bytes_too_long.rs index 1e6aec11fe05a..df2b034e82513 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/string_or_bytes_too_long.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/string_or_bytes_too_long.rs @@ -1,7 +1,7 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::is_docstring_stmt; -use ruff_python_ast::{self as ast, AnyNodeRef}; +use ruff_python_ast::{self as ast, StringLike}; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -43,30 +43,27 @@ impl AlwaysFixableViolation for StringOrBytesTooLong { } /// PYI053 -pub(crate) fn string_or_bytes_too_long(checker: &mut Checker, node: AnyNodeRef) { +pub(crate) fn string_or_bytes_too_long(checker: &mut Checker, string: StringLike) { // Ignore docstrings. if is_docstring_stmt(checker.semantic().current_statement()) { return; } - let length = match node { - AnyNodeRef::ExprStringLiteral(ast::ExprStringLiteral { value, .. }) => { + let length = match string { + StringLike::StringLiteral(ast::ExprStringLiteral { value, .. }) => value.chars().count(), + StringLike::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => value.len(), + StringLike::FStringLiteral(ast::FStringLiteralElement { value, .. }) => { value.chars().count() } - AnyNodeRef::ExprBytesLiteral(ast::ExprBytesLiteral { value, .. }) => value.len(), - AnyNodeRef::FStringLiteralElement(ast::FStringLiteralElement { value, .. }) => { - value.chars().count() - } - _ => return, }; if length <= 50 { return; } - let mut diagnostic = Diagnostic::new(StringOrBytesTooLong, node.range()); + let mut diagnostic = Diagnostic::new(StringOrBytesTooLong, string.range()); diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( "...".to_string(), - node.range(), + string.range(), ))); checker.diagnostics.push(diagnostic); } diff --git a/crates/ruff_python_ast/src/expression.rs b/crates/ruff_python_ast/src/expression.rs index a8a86a8ec1ef9..56fecca6fc300 100644 --- a/crates/ruff_python_ast/src/expression.rs +++ b/crates/ruff_python_ast/src/expression.rs @@ -393,3 +393,41 @@ impl LiteralExpressionRef<'_> { } } } + +/// An enum that holds a reference to a string-like literal from the AST. +/// This includes string literals, bytes literals, and the literal parts of +/// f-strings. +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum StringLike<'a> { + StringLiteral(&'a ast::ExprStringLiteral), + BytesLiteral(&'a ast::ExprBytesLiteral), + FStringLiteral(&'a ast::FStringLiteralElement), +} + +impl<'a> From<&'a ast::ExprStringLiteral> for StringLike<'a> { + fn from(value: &'a ast::ExprStringLiteral) -> Self { + StringLike::StringLiteral(value) + } +} + +impl<'a> From<&'a ast::ExprBytesLiteral> for StringLike<'a> { + fn from(value: &'a ast::ExprBytesLiteral) -> Self { + StringLike::BytesLiteral(value) + } +} + +impl<'a> From<&'a ast::FStringLiteralElement> for StringLike<'a> { + fn from(value: &'a ast::FStringLiteralElement) -> Self { + StringLike::FStringLiteral(value) + } +} + +impl Ranged for StringLike<'_> { + fn range(&self) -> TextRange { + match self { + StringLike::StringLiteral(literal) => literal.range(), + StringLike::BytesLiteral(literal) => literal.range(), + StringLike::FStringLiteral(literal) => literal.range(), + } + } +} From b021ede481d8a2e693fa6e6adca8dbd70d57d303 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 7 Dec 2023 13:35:55 -0500 Subject: [PATCH 138/197] Allow `sys.path` modifications between imports (#9047) ## Summary It's common to interleave a `sys.path` modification between imports at the top of a file. This is a frequent cause of `# noqa: E402` false positives, as seen in the ecosystem checks. This PR modifies E402 to omit such modifications when determining the "import boundary". (We could consider linting against `sys.path` modifications, but that should be a separate rule.) Closes: https://github.com/astral-sh/ruff/issues/5557. --- .../test/fixtures/pycodestyle/E402.py | 17 ++++++--- crates/ruff_linter/src/checkers/ast/mod.rs | 10 +++-- .../ruff_linter/src/rules/pycodestyle/mod.rs | 1 + .../src/rules/pycodestyle/rules/imports.rs | 4 ++ ...les__pycodestyle__tests__E402_E402.py.snap | 34 +++++++++++------ ...destyle__tests__preview__E402_E402.py.snap | 28 ++++++++++++++ .../src/analyze/imports.rs | 37 +++++++++++++++++++ .../ruff_python_semantic/src/analyze/mod.rs | 1 + 8 files changed, 110 insertions(+), 22 deletions(-) create mode 100644 crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__preview__E402_E402.py.snap create mode 100644 crates/ruff_python_semantic/src/analyze/imports.rs diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E402.py b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E402.py index d5943407852a2..8910ff6007e5f 100644 --- a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E402.py +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E402.py @@ -19,21 +19,26 @@ else: import e -__some__magic = 1 +import sys +sys.path.insert(0, "some/path") import f +__some__magic = 1 + +import g + def foo() -> None: - import e + import h if __name__ == "__main__": - import g + import i -import h; import i +import j; import k if __name__ == "__main__": - import j; \ -import k + import l; \ +import m diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 91b9a96deaa98..6c347af7d1844 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -49,7 +49,7 @@ use ruff_python_ast::{helpers, str, visitor, PySourceType}; use ruff_python_codegen::{Generator, Quote, Stylist}; use ruff_python_index::Indexer; use ruff_python_parser::typing::{parse_type_annotation, AnnotationKind}; -use ruff_python_semantic::analyze::{typing, visibility}; +use ruff_python_semantic::analyze::{imports, typing, visibility}; use ruff_python_semantic::{ BindingFlags, BindingId, BindingKind, Exceptions, Export, FromImport, Globals, Import, Module, ModuleKind, NodeId, ScopeId, ScopeKind, SemanticModel, SemanticModelFlags, Snapshot, @@ -303,9 +303,11 @@ where } _ => { self.semantic.flags |= SemanticModelFlags::FUTURES_BOUNDARY; - if !self.semantic.seen_import_boundary() - && !helpers::is_assignment_to_a_dunder(stmt) - && !helpers::in_nested_block(self.semantic.current_statements()) + if !(self.semantic.seen_import_boundary() + || helpers::is_assignment_to_a_dunder(stmt) + || helpers::in_nested_block(self.semantic.current_statements()) + || self.settings.preview.is_enabled() + && imports::is_sys_path_modification(stmt, self.semantic())) { self.semantic.flags |= SemanticModelFlags::IMPORT_BOUNDARY; } diff --git a/crates/ruff_linter/src/rules/pycodestyle/mod.rs b/crates/ruff_linter/src/rules/pycodestyle/mod.rs index 3f6aa412bf179..008118ceeb48d 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/mod.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/mod.rs @@ -65,6 +65,7 @@ mod tests { } #[test_case(Rule::IsLiteral, Path::new("constant_literals.py"))] + #[test_case(Rule::ModuleImportNotAtTopOfFile, Path::new("E402.py"))] #[test_case(Rule::TypeComparison, Path::new("E721.py"))] fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!( diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/imports.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/imports.rs index 443e044498b75..b85dc9eba8fb5 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/imports.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/imports.rs @@ -41,6 +41,10 @@ impl Violation for MultipleImportsOnOneLine { /// According to [PEP 8], "imports are always put at the top of the file, just after any /// module comments and docstrings, and before module globals and constants." /// +/// In [preview], this rule makes an exception for `sys.path` modifications, +/// allowing for `sys.path.insert`, `sys.path.append`, and similar +/// modifications between import statements. +/// /// ## Example /// ```python /// "One string" diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E402_E402.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E402_E402.py.snap index 8c15438eb55af..44d7f5870ac56 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E402_E402.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E402_E402.py.snap @@ -1,27 +1,37 @@ --- source: crates/ruff_linter/src/rules/pycodestyle/mod.rs --- -E402.py:24:1: E402 Module level import not at top of file +E402.py:25:1: E402 Module level import not at top of file | -22 | __some__magic = 1 -23 | -24 | import f +23 | sys.path.insert(0, "some/path") +24 | +25 | import f | ^^^^^^^^ E402 +26 | +27 | __some__magic = 1 | -E402.py:34:1: E402 Module level import not at top of file +E402.py:29:1: E402 Module level import not at top of file | -32 | import g -33 | -34 | import h; import i +27 | __some__magic = 1 +28 | +29 | import g | ^^^^^^^^ E402 | -E402.py:34:11: E402 Module level import not at top of file +E402.py:39:1: E402 Module level import not at top of file | -32 | import g -33 | -34 | import h; import i +37 | import i +38 | +39 | import j; import k + | ^^^^^^^^ E402 + | + +E402.py:39:11: E402 Module level import not at top of file + | +37 | import i +38 | +39 | import j; import k | ^^^^^^^^ E402 | diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__preview__E402_E402.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__preview__E402_E402.py.snap new file mode 100644 index 0000000000000..cf3a61872dd85 --- /dev/null +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__preview__E402_E402.py.snap @@ -0,0 +1,28 @@ +--- +source: crates/ruff_linter/src/rules/pycodestyle/mod.rs +--- +E402.py:29:1: E402 Module level import not at top of file + | +27 | __some__magic = 1 +28 | +29 | import g + | ^^^^^^^^ E402 + | + +E402.py:39:1: E402 Module level import not at top of file + | +37 | import i +38 | +39 | import j; import k + | ^^^^^^^^ E402 + | + +E402.py:39:11: E402 Module level import not at top of file + | +37 | import i +38 | +39 | import j; import k + | ^^^^^^^^ E402 + | + + diff --git a/crates/ruff_python_semantic/src/analyze/imports.rs b/crates/ruff_python_semantic/src/analyze/imports.rs new file mode 100644 index 0000000000000..cc9d219775b2f --- /dev/null +++ b/crates/ruff_python_semantic/src/analyze/imports.rs @@ -0,0 +1,37 @@ +use ruff_python_ast::{self as ast, Expr, Stmt}; + +use crate::SemanticModel; + +/// Returns `true` if a [`Stmt`] is a `sys.path` modification, as in: +/// ```python +/// import sys +/// +/// sys.path.append("../") +/// ``` +pub fn is_sys_path_modification(stmt: &Stmt, semantic: &SemanticModel) -> bool { + let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt else { + return false; + }; + let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() else { + return false; + }; + semantic + .resolve_call_path(func.as_ref()) + .is_some_and(|call_path| { + matches!( + call_path.as_slice(), + [ + "sys", + "path", + "append" + | "insert" + | "extend" + | "remove" + | "pop" + | "clear" + | "reverse" + | "sort" + ] + ) + }) +} diff --git a/crates/ruff_python_semantic/src/analyze/mod.rs b/crates/ruff_python_semantic/src/analyze/mod.rs index 941309a526c26..f0fb3844e30c6 100644 --- a/crates/ruff_python_semantic/src/analyze/mod.rs +++ b/crates/ruff_python_semantic/src/analyze/mod.rs @@ -1,4 +1,5 @@ pub mod function_type; +pub mod imports; pub mod logging; pub mod type_inference; pub mod typing; From 04ec11a73da4283a09bd949b8797c11290f490d9 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Thu, 7 Dec 2023 14:30:43 -0500 Subject: [PATCH 139/197] ruff_python_formatter: support reformatting Markdown code blocks (#9030) (This is not possible to actually use until https://github.com/astral-sh/ruff/pull/8854 is merged.) This commit slots in support for formatting Markdown fenced code blocks[1]. With the refactoring done for reStructuredText previously, this ended up being pretty easy to add. Markdown code blocks are also quite a bit easier to parse and recognize correctly. One point of contention in #8860 is whether to assume that unlabeled Markdown code fences are Python or not by default. In this PR, we make such an assumption. This follows what `rustdoc` does. The mitigation here is that if an unlabeled code block isn't Python, then it probably won't parse as Python. And we'll end up skipping it. So in the vast majority of cases, the worst thing that can happen is a little bit of wasted work. Closes #8860 [1]: https://spec.commonmark.org/0.30/#fenced-code-blocks --- .../fixtures/ruff/docstring_code_examples.py | 506 + .../src/expression/string/docstring.rs | 254 +- .../ruff_python_formatter/tests/normalizer.rs | 10 + .../format@docstring_code_examples.py.snap | 12668 +++++++++++----- 4 files changed, 9364 insertions(+), 4074 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py index 296da3d816545..68c7a528a6cf8 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py @@ -795,6 +795,19 @@ def rst_literal_skipped_doctest(): pass +def rst_literal_skipped_markdown(): + """ + Do cool stuff:: + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + def rst_directive_skipped_not_indented(): """ .. code-block:: python @@ -828,3 +841,496 @@ def rst_directive_skipped_doctest(): Done. """ pass + + +############################################################################### +# Markdown CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Markdown fenced code blocks. +# +# See: https://spec.commonmark.org/0.30/#fenced-code-blocks +############################################################################### + + +def markdown_simple(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_simple_continued(): + """ + Do cool stuff. + + ```python + def cool_stuff( x ): + print( f"hi {x}" ); + ``` + + Done. + """ + pass + + +# Tests that unlabeled Markdown fenced code blocks are assumed to be Python. +def markdown_unlabeled(): + """ + Do cool stuff. + + ``` + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# Tests that fenced code blocks using tildes work. +def markdown_tildes(): + """ + Do cool stuff. + + ~~~py + cool_stuff( 1 ) + ~~~ + + Done. + """ + pass + + +# Tests that a longer closing fence is just fine and dandy. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + `````` + + Done. + """ + pass + + +# Tests that an invalid closing fence is treated as invalid. +# +# We embed it into a docstring so that the surrounding Python +# remains valid. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ''' + ```invalid + ''' + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +# Tests that one can nest fenced code blocks by using different numbers of +# backticks. +def markdown_nested_fences(): + """ + Do cool stuff. + + `````` + do_something( ''' + ``` + did i trick you? + ``` + ''' ) + `````` + + Done. + """ + pass + + +# Tests that an unclosed block gobbles up everything remaining in the +# docstring. When it's only empty lines, those are passed into the formatter +# and thus stripped. +def markdown_unclosed_empty_lines(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + + + + """ + pass + + +# Tests that we can end the block on the second to last line of the +# docstring. +def markdown_second_to_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + """ + pass + + +# Tests that an unclosed block with one extra line at the end is treated +# correctly. As per the CommonMark spec, an unclosed fenced code block contains +# everything following the opening fences. Since formatting the code snippet +# trims lines, the last empty line is removed here. +def markdown_second_to_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + """ + pass + + +# Tests that we can end the block on the actual last line of the docstring. +def markdown_actually_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ```""" + pass + + +# Tests that an unclosed block that ends on the last line of a docstring +# is handled correctly. +def markdown_unclosed_actually_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 )""" + pass + + +def markdown_with_blank_lines(): + """ + Do cool stuff. + + ```py + def cool_stuff( x ): + print( f"hi {x}" ); + + def other_stuff( y ): + print( y ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_tab_second_line_spaces(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_odd_indentation(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +# Extra blanks should be *not* be preserved (unlike reST) because they are part +# of the code snippet (per CommonMark spec), and thus get trimmed as part of +# code formatting. +def markdown_extra_blanks(): + """ + Do cool stuff. + + ```py + + + cool_stuff( 1 ) + + + ``` + + Done. + """ + pass + + +# A block can contain many empty lines within it. +def markdown_extra_blanks_in_snippet(): + """ + Do cool stuff. + + ```py + + cool_stuff( 1 ) + + + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_weird_closing(): + """ + Code block with weirdly placed closing fences. + + ```python + cool_stuff( 1 ) + + ``` + # The above fences look like it shouldn't close the block, but we + # allow it to. The fences below re-open a block (until the end of + # the docstring), but it's invalid Python and thus doesn't get + # reformatted. + a = 10 + ``` + + Now the code block is closed + """ + pass + + +def markdown_over_indented(): + """ + A docstring + over intended + ```python + print( 5 ) + ``` + """ + pass + + +# Tests that an unclosed block gobbles up everything remaining in the +# docstring, even if it isn't valid Python. Since it isn't valid Python, +# reformatting fails and the entire thing is skipped. +def markdown_skipped_unclosed_non_python(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + + I forgot to close the code block, and this is definitely not + Python. So nothing here gets formatted. + """ + pass + + +# This has a Python snippet with a docstring that contains a closing fence. +# This splits the embedded docstring and makes the overall snippet invalid. +def markdown_skipped_accidental_closure(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ''' + ``` + ''' + ``` + + Done. + """ + pass + + +# When a line is unindented all the way out before the standard indent of the +# docstring, the code reformatting ends up interacting poorly with the standard +# docstring whitespace normalization logic. This is probably a bug, and we +# should probably treat the Markdown block as valid, but for now, we detect +# the unindented line and declare the block as invalid and thus do no code +# reformatting. +# +# FIXME: Fixing this (if we think it's a bug) probably requires refactoring the +# docstring whitespace normalization to be aware of code snippets. Or perhaps +# plausibly, to do normalization *after* code snippets have been formatted. +def markdown_skipped_unindented_completely(): + """ + Do cool stuff. + + ```py +cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# This test is fallout from treating fenced code blocks with unindented lines +# as invalid. We probably should treat this as a valid block. Indeed, if we +# remove the logic that makes the `markdown_skipped_unindented_completely` test +# pass, then this code snippet will get reformatted correctly. +def markdown_skipped_unindented_somewhat(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# This tests that if a Markdown block contains a line that has less of an +# indent than another line. +# +# There is some judgment involved in what the right behavior is here. We +# could "normalize" the indentation so that the minimum is the indent of the +# opening fence line. If we did that here, then the code snippet would become +# valid and format as Python. But at time of writing, we don't, which leads to +# inconsistent indentation and thus invalid Python. +def markdown_skipped_unindented_with_inconsistent_indentation(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_skipped_doctest(): + """ + Do cool stuff. + + ```py + >>> cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_skipped_rst_literal(): + """ + Do cool stuff. + + ```py + And do this:: + + cool_stuff( 1 ) + + ``` + + Done. + """ + pass + + +def markdown_skipped_rst_directive(): + """ + Do cool stuff. + + ```py + .. code-block:: python + + cool_stuff( 1 ) + + ``` + + Done. + """ + pass diff --git a/crates/ruff_python_formatter/src/expression/string/docstring.rs b/crates/ruff_python_formatter/src/expression/string/docstring.rs index 41f350bd4deb2..bb453d20b6518 100644 --- a/crates/ruff_python_formatter/src/expression/string/docstring.rs +++ b/crates/ruff_python_formatter/src/expression/string/docstring.rs @@ -354,6 +354,16 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { )?; } } + CodeExampleKind::Markdown(fenced) => { + // This looks suspicious, but it's consistent with the whitespace + // normalization that will occur anyway. + let indent = " ".repeat(fenced.opening_fence_indent.to_usize()); + for docline in formatted_lines { + self.print_one( + &docline.map(|line| std::format!("{indent}{line}")), + )?; + } + } } } } @@ -648,6 +658,18 @@ impl<'src> CodeExample<'src> { }; self.kind = Some(CodeExampleKind::Rst(litblock)); } + Some(CodeExampleKind::Markdown(fenced)) => { + let Some(fenced) = fenced.add_code_line(original, queue) else { + // For Markdown, the last line in a block should be printed + // as-is. Especially since the last line in many Markdown + // fenced code blocks is identical to the start of a code + // block. So if we try to start a new code block with + // the last line, we risk opening another Markdown block + // inappropriately. + return; + }; + self.kind = Some(CodeExampleKind::Markdown(fenced)); + } } } @@ -681,6 +703,9 @@ impl<'src> CodeExample<'src> { } else if let Some(litblock) = CodeExampleRst::new(original) { self.kind = Some(CodeExampleKind::Rst(litblock)); queue.push_back(CodeExampleAddAction::Print { original }); + } else if let Some(fenced) = CodeExampleMarkdown::new(original) { + self.kind = Some(CodeExampleKind::Markdown(fenced)); + queue.push_back(CodeExampleAddAction::Print { original }); } else { queue.push_back(CodeExampleAddAction::Print { original }); } @@ -707,6 +732,10 @@ enum CodeExampleKind<'src> { /// [literal block]: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks /// [code block directive]: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block Rst(CodeExampleRst<'src>), + /// Code found from a Markdown "[fenced code block]". + /// + /// [fenced code block]: https://spec.commonmark.org/0.30/#fenced-code-blocks + Markdown(CodeExampleMarkdown<'src>), } impl<'src> CodeExampleKind<'src> { @@ -718,6 +747,7 @@ impl<'src> CodeExampleKind<'src> { match *self { CodeExampleKind::Doctest(ref doctest) => &doctest.lines, CodeExampleKind::Rst(ref mut litblock) => litblock.indented_code(), + CodeExampleKind::Markdown(ref fenced) => &fenced.lines, } } @@ -731,6 +761,7 @@ impl<'src> CodeExampleKind<'src> { match self { CodeExampleKind::Doctest(doctest) => doctest.lines, CodeExampleKind::Rst(litblock) => litblock.lines, + CodeExampleKind::Markdown(fenced) => fenced.lines, } } } @@ -1156,6 +1187,227 @@ impl<'src> CodeExampleRst<'src> { } } +/// Represents a code example extracted from a Markdown [fenced code block]. +/// +/// [fenced code block]: https://spec.commonmark.org/0.30/#fenced-code-blocks +#[derive(Debug)] +struct CodeExampleMarkdown<'src> { + /// The lines that have been seen so far that make up the block. + lines: Vec>, + + /// The indent of the line "opening" fence of this block measured via + /// `indentation_length`. + /// + /// This indentation is trimmed from the indentation of every line in the + /// body of the code block, + opening_fence_indent: TextSize, + + /// The kind of fence, backticks or tildes, used for this block. We need to + /// keep track of which kind was used to open the block in order to look + /// for a correct close of the block. + fence_kind: MarkdownFenceKind, + + /// The size of the fence, in codepoints, in the opening line. A correct + /// close of the fence must use *at least* this many characters. In other + /// words, this is the number of backticks or tildes that opened the fenced + /// code block. + fence_len: usize, +} + +impl<'src> CodeExampleMarkdown<'src> { + /// Looks for the start of a Markdown [fenced code block]. + /// + /// If the start of a block is found, then this returns a correctly + /// initialized Markdown code block. Callers should print the line as given + /// as it is not retained as part of the block. + /// + /// [fenced code block]: https://spec.commonmark.org/0.30/#fenced-code-blocks + fn new(original: InputDocstringLine<'src>) -> Option> { + static FENCE_START: Lazy = Lazy::new(|| { + Regex::new( + r"(?xm) + ^ + (?: + # In the backtick case, info strings (following the fence) + # cannot contain backticks themselves, since it would + # introduce ambiguity with parsing inline code. In other + # words, if we didn't specifically exclude matching ` + # in the info string for backtick fences, then we might + # erroneously consider something to be a code fence block + # that is actually inline code. + # + # NOTE: The `ticklang` and `tildlang` capture groups are + # currently unused, but there was some discussion about not + # assuming unlabeled blocks were Python. At the time of + # writing, we do assume unlabeled blocks are Python, but + # one could inspect the `ticklang` and `tildlang` capture + # groups to determine whether the block is labeled or not. + (?```+)(?:\s*(?(?i:python|py|python3|py3))[^`]*)? + | + (?~~~+)(?:\s*(?(?i:python|py|python3|py3))\p{any}*)? + ) + $ + ", + ) + .unwrap() + }); + + let (opening_fence_indent, rest) = indent_with_suffix(original.line); + // Quit quickly in the vast majority of cases. + if !rest.starts_with("```") && !rest.starts_with("~~~") { + return None; + } + + let caps = FENCE_START.captures(rest)?; + let (fence_kind, fence_len) = if let Some(ticks) = caps.name("ticks") { + (MarkdownFenceKind::Backtick, ticks.as_str().chars().count()) + } else { + let tildes = caps + .name("tilds") + .expect("no ticks means it must be tildes"); + (MarkdownFenceKind::Tilde, tildes.as_str().chars().count()) + }; + Some(CodeExampleMarkdown { + lines: vec![], + opening_fence_indent: indentation_length(opening_fence_indent), + fence_kind, + fence_len, + }) + } + + /// Attempts to add the given line from a docstring to the Markdown code + /// snippet being collected. + /// + /// In this case, ownership is only not returned when the end of the block + /// was found, or if the block was determined to be invalid. A formatting + /// action is then pushed onto the queue. + fn add_code_line( + mut self, + original: InputDocstringLine<'src>, + queue: &mut VecDeque>, + ) -> Option> { + if self.is_end(original) { + queue.push_back(self.into_format_action()); + queue.push_back(CodeExampleAddAction::Print { original }); + return None; + } + // When a line in a Markdown fenced closed block is indented *less* + // than the opening indent, we treat the entire block as invalid. + // + // I believe that code blocks of this form are actually valid Markdown + // in some cases, but the interplay between it and our docstring + // whitespace normalization leads to undesirable outcomes. For example, + // if the line here is unindented out beyond the initial indent of the + // docstring itself, then this causes the entire docstring to have + // its indent normalized. And, at the time of writing, a subsequent + // formatting run undoes this indentation, thus violating idempotency. + if !original.line.trim_whitespace().is_empty() + && indentation_length(original.line) < self.opening_fence_indent + { + queue.push_back(self.into_reset_action()); + queue.push_back(CodeExampleAddAction::Print { original }); + return None; + } + self.push(original); + queue.push_back(CodeExampleAddAction::Kept); + Some(self) + } + + /// Returns true when given line ends this fenced code block. + fn is_end(&self, original: InputDocstringLine<'src>) -> bool { + let (_, rest) = indent_with_suffix(original.line); + // We can bail early if we don't have at least three backticks or + // tildes. + if !rest.starts_with("```") && !rest.starts_with("~~~") { + return false; + } + // We do need to check that we have the right number of + // backticks/tildes... + let fence_len = rest + .chars() + .take_while(|&ch| ch == self.fence_kind.to_char()) + .count(); + // A closing fence only needs *at least* the number of ticks/tildes + // that are in the opening fence. + if fence_len < self.fence_len { + return false; + } + // And, also, there can only be trailing whitespace. Nothing else. + assert!( + self.fence_kind.to_char().is_ascii(), + "fence char should be ASCII", + ); + if !rest[fence_len..].chars().all(is_python_whitespace) { + return false; + } + true + } + + /// Pushes the given line as part of this code example. + fn push(&mut self, original: InputDocstringLine<'src>) { + // Unlike reStructuredText blocks, for Markdown fenced code blocks, the + // indentation that we want to strip from each line is known when the + // block is opened. So we can strip it as we collect lines. + let code = indentation_trim(self.opening_fence_indent, original.line); + self.lines.push(CodeExampleLine { original, code }); + } + + /// Consume this block and turn it into a reset action. + /// + /// This occurs when we started collecting a code example from something + /// that looked like a block, but later determined that it wasn't a valid + /// block. + fn into_format_action(self) -> CodeExampleAddAction<'src> { + // Note that unlike in reStructuredText blocks, if a Markdown fenced + // code block is unclosed, then *all* remaining lines should be treated + // as part of the block[1]: + // + // > If the end of the containing block (or document) is reached and no + // > closing code fence has been found, the code block contains all of the + // > lines after the opening code fence until the end of the containing + // > block (or document). + // + // This means that we don't need to try and trim trailing empty lines. + // Those will get fed into the code formatter and ultimately stripped, + // which is what you'd expect if those lines are treated as part of the + // block. + // + // [1]: https://spec.commonmark.org/0.30/#fenced-code-blocks + CodeExampleAddAction::Format { + kind: CodeExampleKind::Markdown(self), + } + } + + /// Consume this block and turn it into a reset action. + /// + /// This occurs when we started collecting a code example from something + /// that looked like a code fence, but later determined that it wasn't a + /// valid. + fn into_reset_action(self) -> CodeExampleAddAction<'src> { + CodeExampleAddAction::Reset { code: self.lines } + } +} + +/// The kind of fence used in a Markdown code block. +/// +/// This indicates that the fence is either surrounded by fences made from +/// backticks, or fences made from tildes. +#[derive(Clone, Copy, Debug)] +enum MarkdownFenceKind { + Backtick, + Tilde, +} + +impl MarkdownFenceKind { + /// Convert the fence kind to the actual character used to build the fence. + fn to_char(self) -> char { + match self { + MarkdownFenceKind::Backtick => '`', + MarkdownFenceKind::Tilde => '~', + } + } +} + /// A single line in a code example found in a docstring. /// /// A code example line exists prior to formatting, and is thus in full @@ -1306,7 +1558,7 @@ fn indentation_trim(indent_len: TextSize, line: &str) -> &str { break; } } - line + trimmed } /// Returns the indentation of the given line and everything following it. diff --git a/crates/ruff_python_formatter/tests/normalizer.rs b/crates/ruff_python_formatter/tests/normalizer.rs index 8f01694468dcb..2bab8915cc054 100644 --- a/crates/ruff_python_formatter/tests/normalizer.rs +++ b/crates/ruff_python_formatter/tests/normalizer.rs @@ -82,6 +82,10 @@ impl Transformer for Normalizer { // everything after it. Talk about a hammer. Regex::new(r#"::(?s:.*)"#).unwrap() }); + static STRIP_MARKDOWN_BLOCKS: Lazy = Lazy::new(|| { + // This covers more than valid Markdown blocks, but that's OK. + Regex::new(r#"(```|~~~)\p{any}*(```|~~~|$)"#).unwrap() + }); // Start by (1) stripping everything that looks like a code // snippet, since code snippets may be completely reformatted if @@ -98,6 +102,12 @@ impl Transformer for Normalizer { "\n", ) .into_owned(); + string_literal.value = STRIP_MARKDOWN_BLOCKS + .replace_all( + &string_literal.value, + "\n", + ) + .into_owned(); // Normalize a string by (2) stripping any leading and trailing space from each // line, and (3) removing any blank lines from the start and end of the string. string_literal.value = string_literal diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap index cae50ad8c6d91..7dc1badfe2b8a 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap @@ -801,6 +801,19 @@ def rst_literal_skipped_doctest(): pass +def rst_literal_skipped_markdown(): + """ + Do cool stuff:: + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + def rst_directive_skipped_not_indented(): """ .. code-block:: python @@ -834,1716 +847,5931 @@ def rst_directive_skipped_doctest(): Done. """ pass -``` -## Outputs -### Output 1 -``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled -``` -```python ############################################################################### -# DOCTEST CODE EXAMPLES +# Markdown CODE EXAMPLES # # This section shows examples of docstrings that contain code snippets in -# Python's "doctest" format. +# Markdown fenced code blocks. # -# See: https://docs.python.org/3/library/doctest.html +# See: https://spec.commonmark.org/0.30/#fenced-code-blocks ############################################################################### -# The simplest doctest to ensure basic formatting works. -def doctest_simple(): + +def markdown_simple(): """ Do cool stuff. - >>> cool_stuff( 1 ) - 2 + ```py + cool_stuff( 1 ) + ``` + + Done. """ pass -# Another simple test, but one where the Python code -# extends over multiple lines. -def doctest_simple_continued(): +def markdown_simple_continued(): """ Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 + ```python + def cool_stuff( x ): + print( f"hi {x}" ); + ``` + + Done. """ pass -# Test that we support multiple directly adjacent -# doctests. -def doctest_adjacent(): +# Tests that unlabeled Markdown fenced code blocks are assumed to be Python. +def markdown_unlabeled(): """ Do cool stuff. - >>> cool_stuff( x ) - >>> cool_stuff( y ) - 2 + ``` + cool_stuff( 1 ) + ``` + + Done. """ pass -# Test that a doctest on the last non-whitespace line of a docstring -# reformats correctly. -def doctest_last_line(): +# Tests that fenced code blocks using tildes work. +def markdown_tildes(): """ Do cool stuff. - >>> cool_stuff( x ) + ~~~py + cool_stuff( 1 ) + ~~~ + + Done. """ pass -# Test that a doctest that continues to the last non-whitespace line of -# a docstring reformats correctly. -def doctest_last_line_continued(): +# Tests that a longer closing fence is just fine and dandy. +def markdown_longer_closing_fence(): """ Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); + ```py + cool_stuff( 1 ) + `````` + + Done. """ pass -# Test that a doctest on the real last line of a docstring reformats -# correctly. -def doctest_really_last_line(): +# Tests that an invalid closing fence is treated as invalid. +# +# We embed it into a docstring so that the surrounding Python +# remains valid. +def markdown_longer_closing_fence(): """ Do cool stuff. - >>> cool_stuff( x )""" + ```py + cool_stuff( 1 ) + ''' + ```invalid + ''' + cool_stuff( 2 ) + ``` + + Done. + """ pass -# Test that a continued doctest on the real last line of a docstring reformats -# correctly. -def doctest_really_last_line_continued(): +# Tests that one can nest fenced code blocks by using different numbers of +# backticks. +def markdown_nested_fences(): """ Do cool stuff. - >>> cool_stuff( x ) - ... more( y )""" + `````` + do_something( ''' + ``` + did i trick you? + ``` + ''' ) + `````` + + Done. + """ pass -# Test that a doctest is correctly identified and formatted with a blank -# continuation line. -def doctest_blank_continued(): +# Tests that an unclosed block gobbles up everything remaining in the +# docstring. When it's only empty lines, those are passed into the formatter +# and thus stripped. +def markdown_unclosed_empty_lines(): """ Do cool stuff. - >>> def cool_stuff ( x ): - ... print( x ) - ... - ... print( x ) + ```py + cool_stuff( 1 ) + + + """ pass -# Tests that a blank PS2 line at the end of a doctest can get dropped. -# It is treated as part of the Python snippet which will trim the -# trailing whitespace. -def doctest_blank_end(): +# Tests that we can end the block on the second to last line of the +# docstring. +def markdown_second_to_last(): """ Do cool stuff. - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... + ```py + cool_stuff( 1 ) + ``` """ pass -# Tests that a blank PS2 line at the end of a doctest can get dropped -# even when there is text following it. -def doctest_blank_end_then_some_text(): +# Tests that an unclosed block with one extra line at the end is treated +# correctly. As per the CommonMark spec, an unclosed fenced code block contains +# everything following the opening fences. Since formatting the code snippet +# trims lines, the last empty line is removed here. +def markdown_second_to_last(): """ Do cool stuff. - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... - - And say something else. + ```py + cool_stuff( 1 ) """ pass -# Test that a doctest containing a triple quoted string gets formatted -# correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): +# Tests that we can end the block on the actual last line of the docstring. +def markdown_actually_last(): """ Do cool stuff. - >>> x = '''tricksy''' - """ + ```py + cool_stuff( 1 ) + ```""" pass -# Test that a doctest containing a triple quoted f-string gets -# formatted correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): +# Tests that an unclosed block that ends on the last line of a docstring +# is handled correctly. +def markdown_unclosed_actually_last(): """ Do cool stuff. - >>> x = f'''tricksy''' - """ + ```py + cool_stuff( 1 )""" pass -# Another nested multi-line string case, but with triple escaped double -# quotes inside a triple single quoted string. -def doctest_with_triple_escaped_double(): +def markdown_with_blank_lines(): """ Do cool stuff. - >>> x = '''\"\"\"''' + ```py + def cool_stuff( x ): + print( f"hi {x}" ); + + def other_stuff( y ): + print( y ) + ``` + + Done. """ pass -# Tests that inverting the triple quoting works as expected. -def doctest_with_triple_inverted(): - ''' +def markdown_first_line_indent_uses_tabs_4spaces(): + """ Do cool stuff. - >>> x = """tricksy""" - ''' + ```py + cool_stuff( 1 ) + ``` + + Done. + """ pass -# Tests that inverting the triple quoting with an f-string works as -# expected. -def doctest_with_triple_inverted_fstring(): - ''' +def markdown_first_line_indent_uses_tabs_4spaces_multiple(): + """ Do cool stuff. - >>> x = f"""tricksy""" - ''' + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ pass -# Tests nested doctests are ignored. That is, we don't format doctests -# recursively. We only recognize "top level" doctests. -# -# This restriction primarily exists to avoid needing to deal with -# nesting quotes. It also seems like a generally sensible restriction, -# although it could be lifted if necessary I believe. -def doctest_nested_doctest_not_formatted(): - ''' - Do cool stuff. +def markdown_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff. - >>> def nested( x ): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass - ''' - pass + ```py + cool_stuff( 1 ) + ``` + Done. + """ + pass -# Tests that the starting column does not matter. -def doctest_varying_start_column(): + +def markdown_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_tab_second_line_spaces(): """ Do cool stuff. - >>> assert ("Easy!") - >>> import math - >>> math.floor( 1.9 ) - 1 + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. """ pass -# Tests that long lines get wrapped... appropriately. -# -# The docstring code formatter uses the same line width settings as for -# formatting other code. This means that a line in the docstring can -# actually extend past the configured line limit. -# -# It's not quite clear whether this is desirable or not. We could in -# theory compute the intendation length of a code snippet and then -# adjust the line-width setting on a recursive call to the formatter. -# But there are assuredly pathological cases to consider. Another path -# would be to expose another formatter option for controlling the -# line-width of code snippets independently. -def doctest_long_lines(): +def markdown_odd_indentation(): """ Do cool stuff. - This won't get wrapped even though it exceeds our configured - line width because it doesn't exceed the line width within this - docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` - But this one is long enough to get wrapped. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) + Done. """ - # This demostrates a normal line that will get wrapped but won't - # get wrapped in the docstring above because of how the line-width - # setting gets reset at the first column in each code snippet. - foo, bar, quux = this_is_a_long_line( - lion, giraffe, hippo, zeba, lemur, penguin, monkey - ) + pass -# Checks that a simple but invalid doctest gets skipped. -def doctest_skipped_simple(): +# Extra blanks should be *not* be preserved (unlike reST) because they are part +# of the code snippet (per CommonMark spec), and thus get trimmed as part of +# code formatting. +def markdown_extra_blanks(): """ Do cool stuff. - >>> cool-stuff( x ): - 2 + ```py + + + cool_stuff( 1 ) + + + ``` + + Done. """ pass -# Checks that a simple doctest that is continued over multiple lines, -# but is invalid, gets skipped. -def doctest_skipped_simple_continued(): +# A block can contain many empty lines within it. +def markdown_extra_blanks_in_snippet(): """ Do cool stuff. - >>> def cool-stuff( x ): - ... print( f"hi {x}" ); - 2 + ```py + + cool_stuff( 1 ) + + + cool_stuff( 2 ) + ``` + + Done. """ pass -# Checks that a doctest with improper indentation gets skipped. -def doctest_skipped_inconsistent_indent(): +def markdown_weird_closing(): """ - Do cool stuff. - - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass + Code block with weirdly placed closing fences. + ```python + cool_stuff( 1 ) -# Checks that a doctest with some proper indentation and some improper -# indentation is "partially" formatted. That is, the part that appears -# before the inconsistent indentation is formatted. This requires that -# the part before it is valid Python. -def doctest_skipped_partial_inconsistent_indent(): - """ - Do cool stuff. + ``` + # The above fences look like it shouldn't close the block, but we + # allow it to. The fences below re-open a block (until the end of + # the docstring), but it's invalid Python and thus doesn't get + # reformatted. + a = 10 + ``` - >>> def cool_stuff( x ): - ... print( x ) - ... print( f"hi {x}" ); - hi 2 + Now the code block is closed """ pass -# Checks that a doctest with improper triple single quoted string gets -# skipped. That is, the code snippet is itself invalid Python, so it is -# left as is. -def doctest_skipped_triple_incorrect(): +def markdown_over_indented(): """ - Do cool stuff. - - >>> foo( x ) - ... '''tri'''cksy''' + A docstring + over intended + ```python + print( 5 ) + ``` """ pass -# Tests that a doctest on a single line is skipped. -def doctest_skipped_one_line(): - ">>> foo( x )" - pass - - -# f-strings are not considered docstrings[1], so any doctests -# inside of them should not be formatted. -# -# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals -def doctest_skipped_fstring(): - f""" +# Tests that an unclosed block gobbles up everything remaining in the +# docstring, even if it isn't valid Python. Since it isn't valid Python, +# reformatting fails and the entire thing is skipped. +def markdown_skipped_unclosed_non_python(): + """ Do cool stuff. - >>> cool_stuff( 1 ) - 2 + ```py + cool_stuff( 1 ) + + I forgot to close the code block, and this is definitely not + Python. So nothing here gets formatted. """ pass -# Test that a doctest containing a triple quoted string at least -# does not result in invalid Python code. Ideally this would format -# correctly, but at time of writing it does not. -def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): +# This has a Python snippet with a docstring that contains a closing fence. +# This splits the embedded docstring and makes the overall snippet invalid. +def markdown_skipped_accidental_closure(): """ Do cool stuff. - >>> x = '\"\"\"' + ```py + cool_stuff( 1 ) + ''' + ``` + ''' + ``` + + Done. """ pass -############################################################################### -# reStructuredText CODE EXAMPLES -# -# This section shows examples of docstrings that contain code snippets in -# reStructuredText formatted code blocks. +# When a line is unindented all the way out before the standard indent of the +# docstring, the code reformatting ends up interacting poorly with the standard +# docstring whitespace normalization logic. This is probably a bug, and we +# should probably treat the Markdown block as valid, but for now, we detect +# the unindented line and declare the block as invalid and thus do no code +# reformatting. # -# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks -# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 -############################################################################### - - -def rst_literal_simple(): +# FIXME: Fixing this (if we think it's a bug) probably requires refactoring the +# docstring whitespace normalization to be aware of code snippets. Or perhaps +# plausibly, to do normalization *after* code snippets have been formatted. +def markdown_skipped_unindented_completely(): """ - Do cool stuff:: + Do cool stuff. - cool_stuff( 1 ) + ```py +cool_stuff( 1 ) + ``` Done. """ pass -def rst_literal_simple_continued(): +# This test is fallout from treating fenced code blocks with unindented lines +# as invalid. We probably should treat this as a valid block. Indeed, if we +# remove the logic that makes the `markdown_skipped_unindented_completely` test +# pass, then this code snippet will get reformatted correctly. +def markdown_skipped_unindented_somewhat(): """ - Do cool stuff:: + Do cool stuff. - def cool_stuff( x ): - print( f"hi {x}" ); + ```py + cool_stuff( 1 ) + ``` Done. """ pass -# Tests that we can end the literal block on the second -# to last line of the docstring. -def rst_literal_second_to_last(): - """ - Do cool stuff:: - - cool_stuff( 1 ) +# This tests that if a Markdown block contains a line that has less of an +# indent than another line. +# +# There is some judgment involved in what the right behavior is here. We +# could "normalize" the indentation so that the minimum is the indent of the +# opening fence line. If we did that here, then the code snippet would become +# valid and format as Python. But at time of writing, we don't, which leads to +# inconsistent indentation and thus invalid Python. +def markdown_skipped_unindented_with_inconsistent_indentation(): """ - pass + Do cool stuff. + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` -# Tests that we can end the literal block on the actual -# last line of the docstring. -def rst_literal_actually_last(): + Done. """ - Do cool stuff:: - - cool_stuff( 1 )""" pass -def rst_literal_with_blank_lines(): +def markdown_skipped_doctest(): """ - Do cool stuff:: - - def cool_stuff( x ): - print( f"hi {x}" ); + Do cool stuff. - def other_stuff( y ): - print( y ) + ```py + >>> cool_stuff( 1 ) + ``` Done. """ pass -# Extra blanks should be preserved. -def rst_literal_extra_blanks(): +def markdown_skipped_rst_literal(): """ - Do cool stuff:: - + Do cool stuff. + ```py + And do this:: cool_stuff( 1 ) - + ``` Done. """ pass -# If a literal block is never properly ended (via a non-empty unindented line), -# then the end of the block should be the last non-empty line. And subsequent -# empty lines should be preserved as-is. -def rst_literal_extra_blanks_at_end(): +def markdown_skipped_rst_directive(): """ - Do cool stuff:: + Do cool stuff. + ```py + .. code-block:: python cool_stuff( 1 ) + ``` - + Done. """ pass +``` +## Outputs +### Output 1 +``` +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +preview = Disabled +``` -# A literal block can contain many empty lines and it should not end the block -# if it continues. -def rst_literal_extra_blanks_in_snippet(): - """ - Do cool stuff:: - - cool_stuff( 1 ) - +```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### - cool_stuff( 2 ) +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. - Done. + >>> cool_stuff( 1 ) + 2 """ pass -# This tests that a unindented line appearing after an indented line (but where -# the indent is still beyond the minimum) gets formatted properly. -def rst_literal_subsequent_line_not_indented(): +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): """ - Do cool stuff:: - - if True: - cool_stuff( ''' - hiya''' ) + Do cool stuff. - Done. + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 """ pass -# This checks that if the first line in a code snippet has been indented with -# tabs, then so long as its "indentation length" is considered bigger than the -# line with `::`, it is reformatted as code. -# -# (If your tabwidth is set to 4, then it looks like the code snippet -# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST -# itself also seems to recognize this as a code block, although it appears -# under-specified.) -def rst_literal_first_line_indent_uses_tabs_4spaces(): +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): """ - Do cool stuff:: - - cool_stuff( 1 ) + Do cool stuff. - Done. + >>> cool_stuff( x ) + >>> cool_stuff( y ) + 2 """ pass -# Like the test above, but with multiple lines. -def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): """ - Do cool stuff:: - - cool_stuff( 1 ) - cool_stuff( 2 ) + Do cool stuff. - Done. + >>> cool_stuff( x ) """ pass -# Another test with tabs, except in this case, if your tabwidth is less than -# 8, than the code snippet actually looks like its indent is *less* than the -# opening line with a `::`. One might presume this means that the code snippet -# is not treated as a literal block and thus not reformatted, but since we -# assume all tabs have tabwidth=8 when computing indentation length, the code -# snippet is actually seen as being more indented than the opening `::` line. -# As with the above example, reST seems to behave the same way here. -def rst_literal_first_line_indent_uses_tabs_8spaces(): +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): """ - Do cool stuff:: - - cool_stuff( 1 ) + Do cool stuff. - Done. + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); """ pass -# Like the test above, but with multiple lines. -def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): """ - Do cool stuff:: - - cool_stuff( 1 ) - cool_stuff( 2 ) + Do cool stuff. - Done. - """ + >>> cool_stuff( x )""" pass -# Tests that if two lines in a literal block are indented to the same level -# but by different means (tabs versus spaces), then we correctly recognize the -# block and format it. -def rst_literal_first_line_tab_second_line_spaces(): +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): """ - Do cool stuff:: - - cool_stuff( 1 ) - cool_stuff( 2 ) + Do cool stuff. - Done. - """ + >>> cool_stuff( x ) + ... more( y )""" pass -# Tests that when two lines in a code snippet have weird and inconsistent -# indentation, the code still gets formatted so long as the indent is greater -# than the indent of the `::` line. -# -# In this case, the minimum indent is 5 spaces (from the second line) where as -# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). -# The minimum indent is stripped from each code line. Since tabs aren't -# divisible, the entire tab is stripped, which means the first and second lines -# wind up with the same level of indentation. -# -# An alternative behavior here would be that the tab is replaced with 3 spaces -# instead of being stripped entirely. The code snippet itself would then have -# inconsistent indentation to the point of being invalid Python, and thus code -# formatting would be skipped. -# -# I decided on the former behavior because it seems a bit easier to implement, -# but we might want to switch to the alternative if cases like this show up in -# the real world. ---AG -def rst_literal_odd_indentation(): +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): """ - Do cool stuff:: - - cool_stuff( 1 ) - cool_stuff( 2 ) + Do cool stuff. - Done. + >>> def cool_stuff ( x ): + ... print( x ) + ... + ... print( x ) """ pass -# Tests that having a line with a lone `::` works as an introduction of a -# literal block. -def rst_literal_lone_colon(): +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): """ Do cool stuff. - :: - - cool_stuff( 1 ) - - Done. + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... """ pass -def rst_directive_simple(): +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): """ - .. code-block:: python + Do cool stuff. - cool_stuff( 1 ) + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... - Done. + And say something else. """ pass -def rst_directive_case_insensitive(): +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): """ - .. cOdE-bLoCk:: python - - cool_stuff( 1 ) + Do cool stuff. - Done. + >>> x = '''tricksy''' """ pass -def rst_directive_sourcecode(): +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): """ - .. sourcecode:: python - - cool_stuff( 1 ) + Do cool stuff. - Done. + >>> x = f'''tricksy''' """ pass -def rst_directive_options(): +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): """ - .. code-block:: python - :linenos: - :emphasize-lines: 2,3 - :name: blah blah - - cool_stuff( 1 ) - cool_stuff( 2 ) - cool_stuff( 3 ) - cool_stuff( 4 ) + Do cool stuff. - Done. + >>> x = '''\"\"\"''' """ pass -# In this case, since `pycon` isn't recognized as a Python code snippet, the -# docstring reformatter ignores it. But it then picks up the doctest and -# reformats it. -def rst_directive_doctest(): - """ - .. code-block:: pycon - - >>> cool_stuff( 1 ) +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. - Done. - """ + >>> x = """tricksy""" + ''' pass -# This checks that if the first non-empty line after the start of a literal -# block is not indented more than the line containing the `::`, then it is not -# treated as a code snippet. -def rst_literal_skipped_first_line_not_indented(): - """ - Do cool stuff:: - - cool_stuff( 1 ) +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. - Done. - """ + >>> x = f"""tricksy""" + ''' pass -# Like the test above, but inserts an indented line after the un-indented one. -# This should not cause the literal block to be resumed. -def rst_literal_skipped_first_line_not_indented_then_indented(): - """ - Do cool stuff:: - - cool_stuff( 1 ) - cool_stuff( 2 ) +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. - Done. - """ + >>> def nested( x ): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' pass -# This also checks that a code snippet is not reformatted when the indentation -# of the first line is not more than the line with `::`, but this uses tabs to -# make it a little more confounding. It relies on the fact that indentation -# length is computed by assuming a tabwidth equal to 8. reST also rejects this -# and doesn't treat it as a literal block. -def rst_literal_skipped_first_line_not_indented_tab(): +# Tests that the starting column does not matter. +def doctest_varying_start_column(): """ - Do cool stuff:: - - cool_stuff( 1 ) + Do cool stuff. - Done. + >>> assert ("Easy!") + >>> import math + >>> math.floor( 1.9 ) + 1 """ pass -# Like the previous test, but adds a second line. -def rst_literal_skipped_first_line_not_indented_tab_multiple(): +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): """ - Do cool stuff:: + Do cool stuff. - cool_stuff( 1 ) - cool_stuff( 2 ) + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) - Done. + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) """ - pass + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) -# Tests that a code block with a second line that is not properly indented gets -# skipped. A valid code block needs to have an empty line separating these. -# -# One trick here is that we need to make sure the Python code in the snippet is -# valid, otherwise it would be skipped because of invalid Python. -def rst_literal_skipped_subsequent_line_not_indented(): +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): """ - Do cool stuff:: - - if True: - cool_stuff( ''' - hiya''' ) + Do cool stuff. - Done. + >>> cool-stuff( x ): + 2 """ pass -# In this test, we write what looks like a code-block, but it should be treated -# as invalid due to the missing `language` argument. -# -# It does still look like it could be a literal block according to the literal -# rules, but we currently consider the `.. ` prefix to indicate that it is not -# a literal block. -def rst_literal_skipped_not_directive(): +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): """ - .. code-block:: - - cool_stuff( 1 ) + Do cool stuff. - Done. + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 """ pass -# In this test, we start a line with `.. `, which makes it look like it might -# be a directive. But instead continue it as if it was just some periods from -# the previous line, and then try to end it by starting a literal block. -# -# But because of the `.. ` in the beginning, we wind up not treating this as a -# code snippet. The reST render I was using to test things does actually treat -# this as a code block, so we may be out of conformance here. -def rst_literal_skipped_possible_false_negative(): +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): """ - This is a test. - .. This is a test:: - - cool_stuff( 1 ) + Do cool stuff. - Done. + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 """ pass -# This tests that a doctest inside of a reST literal block doesn't get -# reformatted. It's plausible this isn't the right behavior, but it also seems -# like it might be the right behavior since it is a literal block. (The doctest -# makes the Python code invalid.) -def rst_literal_skipped_doctest(): +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): """ - Do cool stuff:: - - >>> cool_stuff( 1 ) + Do cool stuff. - Done. + >>> def cool_stuff( x ): + ... print( x ) + ... print( f"hi {x}" ); + hi 2 """ pass -def rst_directive_skipped_not_indented(): +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): """ - .. code-block:: python - - cool_stuff( 1 ) + Do cool stuff. - Done. + >>> foo( x ) + ... '''tri'''cksy''' """ pass -def rst_directive_skipped_wrong_language(): - """ - .. code-block:: rust +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass - cool_stuff( 1 ) - Done. +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 """ pass -# This gets skipped for the same reason that the doctest in a literal block -# gets skipped. -def rst_directive_skipped_doctest(): +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): """ - .. code-block:: python - - >>> cool_stuff( 1 ) + Do cool stuff. - Done. + >>> x = '\"\"\"' """ pass -``` -### Output 2 -``` -indent-style = space -line-width = 88 -indent-width = 2 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled -``` - -```python ############################################################################### -# DOCTEST CODE EXAMPLES +# reStructuredText CODE EXAMPLES # # This section shows examples of docstrings that contain code snippets in -# Python's "doctest" format. +# reStructuredText formatted code blocks. # -# See: https://docs.python.org/3/library/doctest.html +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 ############################################################################### -# The simplest doctest to ensure basic formatting works. -def doctest_simple(): - """ - Do cool stuff. - - >>> cool_stuff( 1 ) - 2 - """ - pass +def rst_literal_simple(): + """ + Do cool stuff:: -# Another simple test, but one where the Python code -# extends over multiple lines. -def doctest_simple_continued(): - """ - Do cool stuff. + cool_stuff( 1 ) - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass + Done. + """ + pass -# Test that we support multiple directly adjacent -# doctests. -def doctest_adjacent(): - """ - Do cool stuff. +def rst_literal_simple_continued(): + """ + Do cool stuff:: - >>> cool_stuff( x ) - >>> cool_stuff( y ) - 2 - """ - pass + def cool_stuff( x ): + print( f"hi {x}" ); + Done. + """ + pass -# Test that a doctest on the last non-whitespace line of a docstring -# reformats correctly. -def doctest_last_line(): - """ - Do cool stuff. - >>> cool_stuff( x ) - """ - pass +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: + cool_stuff( 1 ) + """ + pass -# Test that a doctest that continues to the last non-whitespace line of -# a docstring reformats correctly. -def doctest_last_line_continued(): - """ - Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - """ - pass +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: + cool_stuff( 1 )""" + pass -# Test that a doctest on the real last line of a docstring reformats -# correctly. -def doctest_really_last_line(): - """ - Do cool stuff. - >>> cool_stuff( x )""" - pass +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: + def cool_stuff( x ): + print( f"hi {x}" ); -# Test that a continued doctest on the real last line of a docstring reformats -# correctly. -def doctest_really_last_line_continued(): - """ - Do cool stuff. + def other_stuff( y ): + print( y ) - >>> cool_stuff( x ) - ... more( y )""" - pass + Done. + """ + pass -# Test that a doctest is correctly identified and formatted with a blank -# continuation line. -def doctest_blank_continued(): - """ - Do cool stuff. +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: - >>> def cool_stuff ( x ): - ... print( x ) - ... - ... print( x ) - """ - pass -# Tests that a blank PS2 line at the end of a doctest can get dropped. -# It is treated as part of the Python snippet which will trim the -# trailing whitespace. -def doctest_blank_end(): - """ - Do cool stuff. + cool_stuff( 1 ) - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... - """ - pass -# Tests that a blank PS2 line at the end of a doctest can get dropped -# even when there is text following it. -def doctest_blank_end_then_some_text(): - """ - Do cool stuff. + Done. + """ + pass - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... - And say something else. - """ - pass +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: -# Test that a doctest containing a triple quoted string gets formatted -# correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): - """ - Do cool stuff. + cool_stuff( 1 ) - >>> x = '''tricksy''' - """ - pass -# Test that a doctest containing a triple quoted f-string gets -# formatted correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): - """ - Do cool stuff. + """ + pass - >>> x = f'''tricksy''' - """ - pass +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + + cool_stuff( 2 ) + + Done. + """ + pass + + +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. +# +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ + Do cool stuff. + + :: + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_simple(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_case_insensitive(): + """ + .. cOdE-bLoCk:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_sourcecode(): + """ + .. sourcecode:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + + cool_stuff( 1 ) + cool_stuff( 2 ) + cool_stuff( 3 ) + cool_stuff( 4 ) + + Done. + """ + pass + + +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. +# +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_literal_skipped_markdown(): + """ + Do cool stuff:: + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +############################################################################### +# Markdown CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Markdown fenced code blocks. +# +# See: https://spec.commonmark.org/0.30/#fenced-code-blocks +############################################################################### + + +def markdown_simple(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_simple_continued(): + """ + Do cool stuff. + + ```python + def cool_stuff( x ): + print( f"hi {x}" ); + ``` + + Done. + """ + pass + + +# Tests that unlabeled Markdown fenced code blocks are assumed to be Python. +def markdown_unlabeled(): + """ + Do cool stuff. + + ``` + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# Tests that fenced code blocks using tildes work. +def markdown_tildes(): + """ + Do cool stuff. + + ~~~py + cool_stuff( 1 ) + ~~~ + + Done. + """ + pass + + +# Tests that a longer closing fence is just fine and dandy. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + `````` + + Done. + """ + pass + + +# Tests that an invalid closing fence is treated as invalid. +# +# We embed it into a docstring so that the surrounding Python +# remains valid. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ''' + ```invalid + ''' + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +# Tests that one can nest fenced code blocks by using different numbers of +# backticks. +def markdown_nested_fences(): + """ + Do cool stuff. + + `````` + do_something( ''' + ``` + did i trick you? + ``` + ''' ) + `````` + + Done. + """ + pass + + +# Tests that an unclosed block gobbles up everything remaining in the +# docstring. When it's only empty lines, those are passed into the formatter +# and thus stripped. +def markdown_unclosed_empty_lines(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + + + + """ + pass + + +# Tests that we can end the block on the second to last line of the +# docstring. +def markdown_second_to_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + """ + pass + + +# Tests that an unclosed block with one extra line at the end is treated +# correctly. As per the CommonMark spec, an unclosed fenced code block contains +# everything following the opening fences. Since formatting the code snippet +# trims lines, the last empty line is removed here. +def markdown_second_to_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + """ + pass + + +# Tests that we can end the block on the actual last line of the docstring. +def markdown_actually_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ```""" + pass + + +# Tests that an unclosed block that ends on the last line of a docstring +# is handled correctly. +def markdown_unclosed_actually_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 )""" + pass + + +def markdown_with_blank_lines(): + """ + Do cool stuff. + + ```py + def cool_stuff( x ): + print( f"hi {x}" ); + + def other_stuff( y ): + print( y ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_tab_second_line_spaces(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_odd_indentation(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +# Extra blanks should be *not* be preserved (unlike reST) because they are part +# of the code snippet (per CommonMark spec), and thus get trimmed as part of +# code formatting. +def markdown_extra_blanks(): + """ + Do cool stuff. + + ```py + + + cool_stuff( 1 ) + + + ``` + + Done. + """ + pass + + +# A block can contain many empty lines within it. +def markdown_extra_blanks_in_snippet(): + """ + Do cool stuff. + + ```py + + cool_stuff( 1 ) + + + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_weird_closing(): + """ + Code block with weirdly placed closing fences. + + ```python + cool_stuff( 1 ) + + ``` + # The above fences look like it shouldn't close the block, but we + # allow it to. The fences below re-open a block (until the end of + # the docstring), but it's invalid Python and thus doesn't get + # reformatted. + a = 10 + ``` + + Now the code block is closed + """ + pass + + +def markdown_over_indented(): + """ + A docstring + over intended + ```python + print( 5 ) + ``` + """ + pass + + +# Tests that an unclosed block gobbles up everything remaining in the +# docstring, even if it isn't valid Python. Since it isn't valid Python, +# reformatting fails and the entire thing is skipped. +def markdown_skipped_unclosed_non_python(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + + I forgot to close the code block, and this is definitely not + Python. So nothing here gets formatted. + """ + pass + + +# This has a Python snippet with a docstring that contains a closing fence. +# This splits the embedded docstring and makes the overall snippet invalid. +def markdown_skipped_accidental_closure(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ''' + ``` + ''' + ``` + + Done. + """ + pass + + +# When a line is unindented all the way out before the standard indent of the +# docstring, the code reformatting ends up interacting poorly with the standard +# docstring whitespace normalization logic. This is probably a bug, and we +# should probably treat the Markdown block as valid, but for now, we detect +# the unindented line and declare the block as invalid and thus do no code +# reformatting. +# +# FIXME: Fixing this (if we think it's a bug) probably requires refactoring the +# docstring whitespace normalization to be aware of code snippets. Or perhaps +# plausibly, to do normalization *after* code snippets have been formatted. +def markdown_skipped_unindented_completely(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# This test is fallout from treating fenced code blocks with unindented lines +# as invalid. We probably should treat this as a valid block. Indeed, if we +# remove the logic that makes the `markdown_skipped_unindented_completely` test +# pass, then this code snippet will get reformatted correctly. +def markdown_skipped_unindented_somewhat(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# This tests that if a Markdown block contains a line that has less of an +# indent than another line. +# +# There is some judgment involved in what the right behavior is here. We +# could "normalize" the indentation so that the minimum is the indent of the +# opening fence line. If we did that here, then the code snippet would become +# valid and format as Python. But at time of writing, we don't, which leads to +# inconsistent indentation and thus invalid Python. +def markdown_skipped_unindented_with_inconsistent_indentation(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_skipped_doctest(): + """ + Do cool stuff. + + ```py + >>> cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_skipped_rst_literal(): + """ + Do cool stuff. + + ```py + And do this:: + + cool_stuff( 1 ) + + ``` + + Done. + """ + pass + + +def markdown_skipped_rst_directive(): + """ + Do cool stuff. + + ```py + .. code-block:: python + + cool_stuff( 1 ) + + ``` + + Done. + """ + pass +``` + + +### Output 2 +``` +indent-style = space +line-width = 88 +indent-width = 2 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +preview = Disabled +``` + +```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + >>> cool_stuff( y ) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + """ + pass + + +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x )""" + pass + + +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + ... more( y )""" + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... + ... print( x ) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested( x ): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert ("Easy!") + >>> import math + >>> math.floor( 1.9 ) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( x ) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass + + +############################################################################### +# reStructuredText CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# reStructuredText formatted code blocks. +# +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +############################################################################### + + +def rst_literal_simple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_literal_simple_continued(): + """ + Do cool stuff:: + + def cool_stuff( x ): + print( f"hi {x}" ); + + Done. + """ + pass + + +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + """ + pass + + +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: + + cool_stuff( 1 )""" + pass + + +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: + + def cool_stuff( x ): + print( f"hi {x}" ); + + def other_stuff( y ): + print( y ) + + Done. + """ + pass + + +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: + + + + cool_stuff( 1 ) + + + + Done. + """ + pass + + +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: + + + cool_stuff( 1 ) + + + + """ + pass + + +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + + cool_stuff( 2 ) + + Done. + """ + pass + + +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. +# +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ + Do cool stuff. + + :: + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_simple(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_case_insensitive(): + """ + .. cOdE-bLoCk:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_sourcecode(): + """ + .. sourcecode:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + + cool_stuff( 1 ) + cool_stuff( 2 ) + cool_stuff( 3 ) + cool_stuff( 4 ) + + Done. + """ + pass + + +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. +# +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_literal_skipped_markdown(): + """ + Do cool stuff:: + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +############################################################################### +# Markdown CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Markdown fenced code blocks. +# +# See: https://spec.commonmark.org/0.30/#fenced-code-blocks +############################################################################### + + +def markdown_simple(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_simple_continued(): + """ + Do cool stuff. + + ```python + def cool_stuff( x ): + print( f"hi {x}" ); + ``` + + Done. + """ + pass + + +# Tests that unlabeled Markdown fenced code blocks are assumed to be Python. +def markdown_unlabeled(): + """ + Do cool stuff. + + ``` + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# Tests that fenced code blocks using tildes work. +def markdown_tildes(): + """ + Do cool stuff. + + ~~~py + cool_stuff( 1 ) + ~~~ + + Done. + """ + pass + + +# Tests that a longer closing fence is just fine and dandy. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + `````` + + Done. + """ + pass + + +# Tests that an invalid closing fence is treated as invalid. +# +# We embed it into a docstring so that the surrounding Python +# remains valid. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ''' + ```invalid + ''' + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +# Tests that one can nest fenced code blocks by using different numbers of +# backticks. +def markdown_nested_fences(): + """ + Do cool stuff. + + `````` + do_something( ''' + ``` + did i trick you? + ``` + ''' ) + `````` + + Done. + """ + pass + + +# Tests that an unclosed block gobbles up everything remaining in the +# docstring. When it's only empty lines, those are passed into the formatter +# and thus stripped. +def markdown_unclosed_empty_lines(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + + + + """ + pass + + +# Tests that we can end the block on the second to last line of the +# docstring. +def markdown_second_to_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + """ + pass + + +# Tests that an unclosed block with one extra line at the end is treated +# correctly. As per the CommonMark spec, an unclosed fenced code block contains +# everything following the opening fences. Since formatting the code snippet +# trims lines, the last empty line is removed here. +def markdown_second_to_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + """ + pass + + +# Tests that we can end the block on the actual last line of the docstring. +def markdown_actually_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ```""" + pass + + +# Tests that an unclosed block that ends on the last line of a docstring +# is handled correctly. +def markdown_unclosed_actually_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 )""" + pass + + +def markdown_with_blank_lines(): + """ + Do cool stuff. + + ```py + def cool_stuff( x ): + print( f"hi {x}" ); + + def other_stuff( y ): + print( y ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_tab_second_line_spaces(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_odd_indentation(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +# Extra blanks should be *not* be preserved (unlike reST) because they are part +# of the code snippet (per CommonMark spec), and thus get trimmed as part of +# code formatting. +def markdown_extra_blanks(): + """ + Do cool stuff. + + ```py + + + cool_stuff( 1 ) + + + ``` + + Done. + """ + pass + + +# A block can contain many empty lines within it. +def markdown_extra_blanks_in_snippet(): + """ + Do cool stuff. + + ```py + + cool_stuff( 1 ) + + + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_weird_closing(): + """ + Code block with weirdly placed closing fences. + + ```python + cool_stuff( 1 ) + + ``` + # The above fences look like it shouldn't close the block, but we + # allow it to. The fences below re-open a block (until the end of + # the docstring), but it's invalid Python and thus doesn't get + # reformatted. + a = 10 + ``` + + Now the code block is closed + """ + pass + + +def markdown_over_indented(): + """ + A docstring + over intended + ```python + print( 5 ) + ``` + """ + pass + + +# Tests that an unclosed block gobbles up everything remaining in the +# docstring, even if it isn't valid Python. Since it isn't valid Python, +# reformatting fails and the entire thing is skipped. +def markdown_skipped_unclosed_non_python(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + + I forgot to close the code block, and this is definitely not + Python. So nothing here gets formatted. + """ + pass + + +# This has a Python snippet with a docstring that contains a closing fence. +# This splits the embedded docstring and makes the overall snippet invalid. +def markdown_skipped_accidental_closure(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ''' + ``` + ''' + ``` + + Done. + """ + pass + + +# When a line is unindented all the way out before the standard indent of the +# docstring, the code reformatting ends up interacting poorly with the standard +# docstring whitespace normalization logic. This is probably a bug, and we +# should probably treat the Markdown block as valid, but for now, we detect +# the unindented line and declare the block as invalid and thus do no code +# reformatting. +# +# FIXME: Fixing this (if we think it's a bug) probably requires refactoring the +# docstring whitespace normalization to be aware of code snippets. Or perhaps +# plausibly, to do normalization *after* code snippets have been formatted. +def markdown_skipped_unindented_completely(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# This test is fallout from treating fenced code blocks with unindented lines +# as invalid. We probably should treat this as a valid block. Indeed, if we +# remove the logic that makes the `markdown_skipped_unindented_completely` test +# pass, then this code snippet will get reformatted correctly. +def markdown_skipped_unindented_somewhat(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# This tests that if a Markdown block contains a line that has less of an +# indent than another line. +# +# There is some judgment involved in what the right behavior is here. We +# could "normalize" the indentation so that the minimum is the indent of the +# opening fence line. If we did that here, then the code snippet would become +# valid and format as Python. But at time of writing, we don't, which leads to +# inconsistent indentation and thus invalid Python. +def markdown_skipped_unindented_with_inconsistent_indentation(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_skipped_doctest(): + """ + Do cool stuff. + + ```py + >>> cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_skipped_rst_literal(): + """ + Do cool stuff. + + ```py + And do this:: + + cool_stuff( 1 ) + + ``` + + Done. + """ + pass + + +def markdown_skipped_rst_directive(): + """ + Do cool stuff. + + ```py + .. code-block:: python + + cool_stuff( 1 ) + + ``` + + Done. + """ + pass +``` + + +### Output 3 +``` +indent-style = tab +line-width = 88 +indent-width = 8 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +preview = Disabled +``` + +```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + >>> cool_stuff( y ) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + """ + pass + + +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x )""" + pass + + +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + ... more( y )""" + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... + ... print( x ) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested( x ): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert ("Easy!") + >>> import math + >>> math.floor( 1.9 ) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( x ) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass + + +############################################################################### +# reStructuredText CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# reStructuredText formatted code blocks. +# +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +############################################################################### + + +def rst_literal_simple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_literal_simple_continued(): + """ + Do cool stuff:: + + def cool_stuff( x ): + print( f"hi {x}" ); + + Done. + """ + pass + + +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + """ + pass + + +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: + + cool_stuff( 1 )""" + pass + + +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: + + def cool_stuff( x ): + print( f"hi {x}" ); + + def other_stuff( y ): + print( y ) + + Done. + """ + pass + + +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: + + + + cool_stuff( 1 ) + + + + Done. + """ + pass + + +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: + + + cool_stuff( 1 ) + + + + """ + pass + + +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + + cool_stuff( 2 ) + + Done. + """ + pass + + +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. +# +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ + Do cool stuff. + + :: + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_simple(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_case_insensitive(): + """ + .. cOdE-bLoCk:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_sourcecode(): + """ + .. sourcecode:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + + cool_stuff( 1 ) + cool_stuff( 2 ) + cool_stuff( 3 ) + cool_stuff( 4 ) + + Done. + """ + pass + + +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. +# +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_literal_skipped_markdown(): + """ + Do cool stuff:: + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +############################################################################### +# Markdown CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Markdown fenced code blocks. +# +# See: https://spec.commonmark.org/0.30/#fenced-code-blocks +############################################################################### + + +def markdown_simple(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_simple_continued(): + """ + Do cool stuff. + + ```python + def cool_stuff( x ): + print( f"hi {x}" ); + ``` + + Done. + """ + pass + + +# Tests that unlabeled Markdown fenced code blocks are assumed to be Python. +def markdown_unlabeled(): + """ + Do cool stuff. + + ``` + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# Tests that fenced code blocks using tildes work. +def markdown_tildes(): + """ + Do cool stuff. + + ~~~py + cool_stuff( 1 ) + ~~~ + + Done. + """ + pass + + +# Tests that a longer closing fence is just fine and dandy. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + `````` + + Done. + """ + pass + + +# Tests that an invalid closing fence is treated as invalid. +# +# We embed it into a docstring so that the surrounding Python +# remains valid. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ''' + ```invalid + ''' + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +# Tests that one can nest fenced code blocks by using different numbers of +# backticks. +def markdown_nested_fences(): + """ + Do cool stuff. + + `````` + do_something( ''' + ``` + did i trick you? + ``` + ''' ) + `````` + + Done. + """ + pass + + +# Tests that an unclosed block gobbles up everything remaining in the +# docstring. When it's only empty lines, those are passed into the formatter +# and thus stripped. +def markdown_unclosed_empty_lines(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + + + + """ + pass + + +# Tests that we can end the block on the second to last line of the +# docstring. +def markdown_second_to_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + """ + pass + + +# Tests that an unclosed block with one extra line at the end is treated +# correctly. As per the CommonMark spec, an unclosed fenced code block contains +# everything following the opening fences. Since formatting the code snippet +# trims lines, the last empty line is removed here. +def markdown_second_to_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + """ + pass + + +# Tests that we can end the block on the actual last line of the docstring. +def markdown_actually_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ```""" + pass + + +# Tests that an unclosed block that ends on the last line of a docstring +# is handled correctly. +def markdown_unclosed_actually_last(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 )""" + pass + + +def markdown_with_blank_lines(): + """ + Do cool stuff. + + ```py + def cool_stuff( x ): + print( f"hi {x}" ); + + def other_stuff( y ): + print( y ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_first_line_tab_second_line_spaces(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_odd_indentation(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +# Extra blanks should be *not* be preserved (unlike reST) because they are part +# of the code snippet (per CommonMark spec), and thus get trimmed as part of +# code formatting. +def markdown_extra_blanks(): + """ + Do cool stuff. + + ```py + + + cool_stuff( 1 ) + + + ``` + + Done. + """ + pass + + +# A block can contain many empty lines within it. +def markdown_extra_blanks_in_snippet(): + """ + Do cool stuff. + + ```py + + cool_stuff( 1 ) + + + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_weird_closing(): + """ + Code block with weirdly placed closing fences. + + ```python + cool_stuff( 1 ) + + ``` + # The above fences look like it shouldn't close the block, but we + # allow it to. The fences below re-open a block (until the end of + # the docstring), but it's invalid Python and thus doesn't get + # reformatted. + a = 10 + ``` + + Now the code block is closed + """ + pass + + +def markdown_over_indented(): + """ + A docstring + over intended + ```python + print( 5 ) + ``` + """ + pass + + +# Tests that an unclosed block gobbles up everything remaining in the +# docstring, even if it isn't valid Python. Since it isn't valid Python, +# reformatting fails and the entire thing is skipped. +def markdown_skipped_unclosed_non_python(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + + I forgot to close the code block, and this is definitely not + Python. So nothing here gets formatted. + """ + pass + + +# This has a Python snippet with a docstring that contains a closing fence. +# This splits the embedded docstring and makes the overall snippet invalid. +def markdown_skipped_accidental_closure(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ''' + ``` + ''' + ``` + + Done. + """ + pass + + +# When a line is unindented all the way out before the standard indent of the +# docstring, the code reformatting ends up interacting poorly with the standard +# docstring whitespace normalization logic. This is probably a bug, and we +# should probably treat the Markdown block as valid, but for now, we detect +# the unindented line and declare the block as invalid and thus do no code +# reformatting. +# +# FIXME: Fixing this (if we think it's a bug) probably requires refactoring the +# docstring whitespace normalization to be aware of code snippets. Or perhaps +# plausibly, to do normalization *after* code snippets have been formatted. +def markdown_skipped_unindented_completely(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# This test is fallout from treating fenced code blocks with unindented lines +# as invalid. We probably should treat this as a valid block. Indeed, if we +# remove the logic that makes the `markdown_skipped_unindented_completely` test +# pass, then this code snippet will get reformatted correctly. +def markdown_skipped_unindented_somewhat(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# This tests that if a Markdown block contains a line that has less of an +# indent than another line. +# +# There is some judgment involved in what the right behavior is here. We +# could "normalize" the indentation so that the minimum is the indent of the +# opening fence line. If we did that here, then the code snippet would become +# valid and format as Python. But at time of writing, we don't, which leads to +# inconsistent indentation and thus invalid Python. +def markdown_skipped_unindented_with_inconsistent_indentation(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_skipped_doctest(): + """ + Do cool stuff. + + ```py + >>> cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_skipped_rst_literal(): + """ + Do cool stuff. + + ```py + And do this:: + + cool_stuff( 1 ) + + ``` + + Done. + """ + pass + + +def markdown_skipped_rst_directive(): + """ + Do cool stuff. + + ```py + .. code-block:: python + + cool_stuff( 1 ) + + ``` + + Done. + """ + pass +``` + + +### Output 4 +``` +indent-style = tab +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +preview = Disabled +``` + +```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + >>> cool_stuff( y ) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + """ + pass + + +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. + + >>> cool_stuff( x )""" + pass + + +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. + + >>> cool_stuff( x ) + ... more( y )""" + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... + ... print( x ) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff ( x ): + ... print( x ) + ... print( x ) + ... + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested( x ): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert ("Easy!") + >>> import math + >>> math.floor( 1.9 ) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( x ) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass + + +############################################################################### +# reStructuredText CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# reStructuredText formatted code blocks. +# +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +############################################################################### + + +def rst_literal_simple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_literal_simple_continued(): + """ + Do cool stuff:: + + def cool_stuff( x ): + print( f"hi {x}" ); + + Done. + """ + pass + + +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + """ + pass + + +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: + + cool_stuff( 1 )""" + pass + + +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: + + def cool_stuff( x ): + print( f"hi {x}" ); + + def other_stuff( y ): + print( y ) + + Done. + """ + pass + + +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: + + + + cool_stuff( 1 ) + + + + Done. + """ + pass + + +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: + + + cool_stuff( 1 ) + + + + """ + pass + + +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + + cool_stuff( 2 ) + + Done. + """ + pass + + +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + + cool_stuff( 1 ) -# Another nested multi-line string case, but with triple escaped double -# quotes inside a triple single quoted string. -def doctest_with_triple_escaped_double(): - """ - Do cool stuff. + Done. + """ + pass - >>> x = '''\"\"\"''' - """ - pass +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: -# Tests that inverting the triple quoting works as expected. -def doctest_with_triple_inverted(): - ''' - Do cool stuff. + cool_stuff( 1 ) + cool_stuff( 2 ) - >>> x = """tricksy""" - ''' - pass + Done. + """ + pass -# Tests that inverting the triple quoting with an f-string works as -# expected. -def doctest_with_triple_inverted_fstring(): - ''' - Do cool stuff. +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): + """ + Do cool stuff:: - >>> x = f"""tricksy""" - ''' - pass + cool_stuff( 1 ) + cool_stuff( 2 ) + Done. + """ + pass -# Tests nested doctests are ignored. That is, we don't format doctests -# recursively. We only recognize "top level" doctests. + +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. # -# This restriction primarily exists to avoid needing to deal with -# nesting quotes. It also seems like a generally sensible restriction, -# although it could be lifted if necessary I believe. -def doctest_nested_doctest_not_formatted(): - ''' - Do cool stuff. +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: - >>> def nested( x ): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass - ''' - pass + cool_stuff( 1 ) + cool_stuff( 2 ) + Done. + """ + pass -# Tests that the starting column does not matter. -def doctest_varying_start_column(): - """ - Do cool stuff. - >>> assert ("Easy!") - >>> import math - >>> math.floor( 1.9 ) - 1 - """ - pass +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ + Do cool stuff. + :: -# Tests that long lines get wrapped... appropriately. + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_simple(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_case_insensitive(): + """ + .. cOdE-bLoCk:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_sourcecode(): + """ + .. sourcecode:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + + cool_stuff( 1 ) + cool_stuff( 2 ) + cool_stuff( 3 ) + cool_stuff( 4 ) + + Done. + """ + pass + + +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. # -# The docstring code formatter uses the same line width settings as for -# formatting other code. This means that a line in the docstring can -# actually extend past the configured line limit. +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. # -# It's not quite clear whether this is desirable or not. We could in -# theory compute the intendation length of a code snippet and then -# adjust the line-width setting on a recursive call to the formatter. -# But there are assuredly pathological cases to consider. Another path -# would be to expose another formatter option for controlling the -# line-width of code snippets independently. -def doctest_long_lines(): - """ - Do cool stuff. +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: - This won't get wrapped even though it exceeds our configured - line width because it doesn't exceed the line width within this - docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + cool_stuff( 1 ) - But this one is long enough to get wrapped. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) - """ - # This demostrates a normal line that will get wrapped but won't - # get wrapped in the docstring above because of how the line-width - # setting gets reset at the first column in each code snippet. - foo, bar, quux = this_is_a_long_line( - lion, giraffe, hippo, zeba, lemur, penguin, monkey - ) + Done. + """ + pass -# Checks that a simple but invalid doctest gets skipped. -def doctest_skipped_simple(): - """ - Do cool stuff. +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: - >>> cool-stuff( x ): - 2 - """ - pass + cool_stuff( 1 ) + Done. + """ + pass -# Checks that a simple doctest that is continued over multiple lines, -# but is invalid, gets skipped. -def doctest_skipped_simple_continued(): - """ - Do cool stuff. - >>> def cool-stuff( x ): - ... print( f"hi {x}" ); - 2 - """ - pass +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: + >>> cool_stuff( 1 ) -# Checks that a doctest with improper indentation gets skipped. -def doctest_skipped_inconsistent_indent(): - """ - Do cool stuff. + Done. + """ + pass - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass +def rst_literal_skipped_markdown(): + """ + Do cool stuff:: -# Checks that a doctest with some proper indentation and some improper -# indentation is "partially" formatted. That is, the part that appears -# before the inconsistent indentation is formatted. This requires that -# the part before it is valid Python. -def doctest_skipped_partial_inconsistent_indent(): - """ - Do cool stuff. + ```py + cool_stuff( 1 ) + ``` - >>> def cool_stuff( x ): - ... print( x ) - ... print( f"hi {x}" ); - hi 2 - """ - pass + Done. + """ + pass -# Checks that a doctest with improper triple single quoted string gets -# skipped. That is, the code snippet is itself invalid Python, so it is -# left as is. -def doctest_skipped_triple_incorrect(): - """ - Do cool stuff. +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python - >>> foo( x ) - ... '''tri'''cksy''' - """ - pass + cool_stuff( 1 ) + + Done. + """ + pass -# Tests that a doctest on a single line is skipped. -def doctest_skipped_one_line(): - ">>> foo( x )" - pass +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust + cool_stuff( 1 ) -# f-strings are not considered docstrings[1], so any doctests -# inside of them should not be formatted. -# -# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals -def doctest_skipped_fstring(): - f""" - Do cool stuff. + Done. + """ + pass - >>> cool_stuff( 1 ) - 2 - """ - pass +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python -# Test that a doctest containing a triple quoted string at least -# does not result in invalid Python code. Ideally this would format -# correctly, but at time of writing it does not. -def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): - """ - Do cool stuff. + >>> cool_stuff( 1 ) - >>> x = '\"\"\"' - """ - pass + Done. + """ + pass ############################################################################### -# reStructuredText CODE EXAMPLES +# Markdown CODE EXAMPLES # # This section shows examples of docstrings that contain code snippets in -# reStructuredText formatted code blocks. +# Markdown fenced code blocks. # -# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks -# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +# See: https://spec.commonmark.org/0.30/#fenced-code-blocks ############################################################################### -def rst_literal_simple(): - """ - Do cool stuff:: - - cool_stuff( 1 ) - - Done. - """ - pass - - -def rst_literal_simple_continued(): - """ - Do cool stuff:: +def markdown_simple(): + """ + Do cool stuff. - def cool_stuff( x ): - print( f"hi {x}" ); + ```py + cool_stuff( 1 ) + ``` - Done. - """ - pass + Done. + """ + pass -# Tests that we can end the literal block on the second -# to last line of the docstring. -def rst_literal_second_to_last(): - """ - Do cool stuff:: +def markdown_simple_continued(): + """ + Do cool stuff. - cool_stuff( 1 ) - """ - pass + ```python + def cool_stuff( x ): + print( f"hi {x}" ); + ``` + Done. + """ + pass -# Tests that we can end the literal block on the actual -# last line of the docstring. -def rst_literal_actually_last(): - """ - Do cool stuff:: - cool_stuff( 1 )""" - pass +# Tests that unlabeled Markdown fenced code blocks are assumed to be Python. +def markdown_unlabeled(): + """ + Do cool stuff. + ``` + cool_stuff( 1 ) + ``` -def rst_literal_with_blank_lines(): - """ - Do cool stuff:: + Done. + """ + pass - def cool_stuff( x ): - print( f"hi {x}" ); - def other_stuff( y ): - print( y ) +# Tests that fenced code blocks using tildes work. +def markdown_tildes(): + """ + Do cool stuff. - Done. - """ - pass + ~~~py + cool_stuff( 1 ) + ~~~ + Done. + """ + pass -# Extra blanks should be preserved. -def rst_literal_extra_blanks(): - """ - Do cool stuff:: +# Tests that a longer closing fence is just fine and dandy. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + ```py + cool_stuff( 1 ) + `````` - cool_stuff( 1 ) + Done. + """ + pass +# Tests that an invalid closing fence is treated as invalid. +# +# We embed it into a docstring so that the surrounding Python +# remains valid. +def markdown_longer_closing_fence(): + """ + Do cool stuff. - Done. - """ - pass + ```py + cool_stuff( 1 ) + ''' + ```invalid + ''' + cool_stuff( 2 ) + ``` + Done. + """ + pass -# If a literal block is never properly ended (via a non-empty unindented line), -# then the end of the block should be the last non-empty line. And subsequent -# empty lines should be preserved as-is. -def rst_literal_extra_blanks_at_end(): - """ - Do cool stuff:: +# Tests that one can nest fenced code blocks by using different numbers of +# backticks. +def markdown_nested_fences(): + """ + Do cool stuff. - cool_stuff( 1 ) + `````` + do_something( ''' + ``` + did i trick you? + ``` + ''' ) + `````` + Done. + """ + pass - """ - pass +# Tests that an unclosed block gobbles up everything remaining in the +# docstring. When it's only empty lines, those are passed into the formatter +# and thus stripped. +def markdown_unclosed_empty_lines(): + """ + Do cool stuff. + ```py + cool_stuff( 1 ) -# A literal block can contain many empty lines and it should not end the block -# if it continues. -def rst_literal_extra_blanks_in_snippet(): - """ - Do cool stuff:: - cool_stuff( 1 ) + """ + pass - cool_stuff( 2 ) - Done. - """ - pass +# Tests that we can end the block on the second to last line of the +# docstring. +def markdown_second_to_last(): + """ + Do cool stuff. + ```py + cool_stuff( 1 ) + ``` + """ + pass -# This tests that a unindented line appearing after an indented line (but where -# the indent is still beyond the minimum) gets formatted properly. -def rst_literal_subsequent_line_not_indented(): - """ - Do cool stuff:: - if True: - cool_stuff( ''' - hiya''' ) +# Tests that an unclosed block with one extra line at the end is treated +# correctly. As per the CommonMark spec, an unclosed fenced code block contains +# everything following the opening fences. Since formatting the code snippet +# trims lines, the last empty line is removed here. +def markdown_second_to_last(): + """ + Do cool stuff. - Done. - """ - pass + ```py + cool_stuff( 1 ) + """ + pass -# This checks that if the first line in a code snippet has been indented with -# tabs, then so long as its "indentation length" is considered bigger than the -# line with `::`, it is reformatted as code. -# -# (If your tabwidth is set to 4, then it looks like the code snippet -# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST -# itself also seems to recognize this as a code block, although it appears -# under-specified.) -def rst_literal_first_line_indent_uses_tabs_4spaces(): - """ - Do cool stuff:: +# Tests that we can end the block on the actual last line of the docstring. +def markdown_actually_last(): + """ + Do cool stuff. - cool_stuff( 1 ) + ```py + cool_stuff( 1 ) + ```""" + pass - Done. - """ - pass +# Tests that an unclosed block that ends on the last line of a docstring +# is handled correctly. +def markdown_unclosed_actually_last(): + """ + Do cool stuff. -# Like the test above, but with multiple lines. -def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): - """ - Do cool stuff:: + ```py + cool_stuff( 1 )""" + pass - cool_stuff( 1 ) - cool_stuff( 2 ) - Done. - """ - pass +def markdown_with_blank_lines(): + """ + Do cool stuff. + ```py + def cool_stuff( x ): + print( f"hi {x}" ); -# Another test with tabs, except in this case, if your tabwidth is less than -# 8, than the code snippet actually looks like its indent is *less* than the -# opening line with a `::`. One might presume this means that the code snippet -# is not treated as a literal block and thus not reformatted, but since we -# assume all tabs have tabwidth=8 when computing indentation length, the code -# snippet is actually seen as being more indented than the opening `::` line. -# As with the above example, reST seems to behave the same way here. -def rst_literal_first_line_indent_uses_tabs_8spaces(): - """ - Do cool stuff:: + def other_stuff( y ): + print( y ) + ``` - cool_stuff( 1 ) + Done. + """ + pass - Done. - """ - pass +def markdown_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff. -# Like the test above, but with multiple lines. -def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): - """ - Do cool stuff:: + ```py + cool_stuff( 1 ) + ``` - cool_stuff( 1 ) - cool_stuff( 2 ) + Done. + """ + pass - Done. - """ - pass +def markdown_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff. -# Tests that if two lines in a literal block are indented to the same level -# but by different means (tabs versus spaces), then we correctly recognize the -# block and format it. -def rst_literal_first_line_tab_second_line_spaces(): - """ - Do cool stuff:: + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` - cool_stuff( 1 ) - cool_stuff( 2 ) + Done. + """ + pass - Done. - """ - pass +def markdown_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff. -# Tests that when two lines in a code snippet have weird and inconsistent -# indentation, the code still gets formatted so long as the indent is greater -# than the indent of the `::` line. -# -# In this case, the minimum indent is 5 spaces (from the second line) where as -# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). -# The minimum indent is stripped from each code line. Since tabs aren't -# divisible, the entire tab is stripped, which means the first and second lines -# wind up with the same level of indentation. -# -# An alternative behavior here would be that the tab is replaced with 3 spaces -# instead of being stripped entirely. The code snippet itself would then have -# inconsistent indentation to the point of being invalid Python, and thus code -# formatting would be skipped. -# -# I decided on the former behavior because it seems a bit easier to implement, -# but we might want to switch to the alternative if cases like this show up in -# the real world. ---AG -def rst_literal_odd_indentation(): - """ - Do cool stuff:: + ```py + cool_stuff( 1 ) + ``` - cool_stuff( 1 ) - cool_stuff( 2 ) + Done. + """ + pass - Done. - """ - pass +def markdown_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff. -# Tests that having a line with a lone `::` works as an introduction of a -# literal block. -def rst_literal_lone_colon(): - """ - Do cool stuff. + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` - :: + Done. + """ + pass - cool_stuff( 1 ) - Done. - """ - pass +def markdown_first_line_tab_second_line_spaces(): + """ + Do cool stuff. + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` -def rst_directive_simple(): - """ - .. code-block:: python + Done. + """ + pass - cool_stuff( 1 ) - Done. - """ - pass +def markdown_odd_indentation(): + """ + Do cool stuff. + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` -def rst_directive_case_insensitive(): - """ - .. cOdE-bLoCk:: python + Done. + """ + pass - cool_stuff( 1 ) - Done. - """ - pass +# Extra blanks should be *not* be preserved (unlike reST) because they are part +# of the code snippet (per CommonMark spec), and thus get trimmed as part of +# code formatting. +def markdown_extra_blanks(): + """ + Do cool stuff. + ```py -def rst_directive_sourcecode(): - """ - .. sourcecode:: python - cool_stuff( 1 ) + cool_stuff( 1 ) - Done. - """ - pass + ``` -def rst_directive_options(): - """ - .. code-block:: python - :linenos: - :emphasize-lines: 2,3 - :name: blah blah + Done. + """ + pass - cool_stuff( 1 ) - cool_stuff( 2 ) - cool_stuff( 3 ) - cool_stuff( 4 ) - Done. - """ - pass +# A block can contain many empty lines within it. +def markdown_extra_blanks_in_snippet(): + """ + Do cool stuff. + ```py -# In this case, since `pycon` isn't recognized as a Python code snippet, the -# docstring reformatter ignores it. But it then picks up the doctest and -# reformats it. -def rst_directive_doctest(): - """ - .. code-block:: pycon + cool_stuff( 1 ) - >>> cool_stuff( 1 ) - Done. - """ - pass + cool_stuff( 2 ) + ``` + Done. + """ + pass -# This checks that if the first non-empty line after the start of a literal -# block is not indented more than the line containing the `::`, then it is not -# treated as a code snippet. -def rst_literal_skipped_first_line_not_indented(): - """ - Do cool stuff:: - cool_stuff( 1 ) +def markdown_weird_closing(): + """ + Code block with weirdly placed closing fences. - Done. - """ - pass + ```python + cool_stuff( 1 ) + ``` + # The above fences look like it shouldn't close the block, but we + # allow it to. The fences below re-open a block (until the end of + # the docstring), but it's invalid Python and thus doesn't get + # reformatted. + a = 10 + ``` -# Like the test above, but inserts an indented line after the un-indented one. -# This should not cause the literal block to be resumed. -def rst_literal_skipped_first_line_not_indented_then_indented(): - """ - Do cool stuff:: + Now the code block is closed + """ + pass - cool_stuff( 1 ) - cool_stuff( 2 ) - Done. - """ - pass +def markdown_over_indented(): + """ + A docstring + over intended + ```python + print( 5 ) + ``` + """ + pass -# This also checks that a code snippet is not reformatted when the indentation -# of the first line is not more than the line with `::`, but this uses tabs to -# make it a little more confounding. It relies on the fact that indentation -# length is computed by assuming a tabwidth equal to 8. reST also rejects this -# and doesn't treat it as a literal block. -def rst_literal_skipped_first_line_not_indented_tab(): - """ - Do cool stuff:: +# Tests that an unclosed block gobbles up everything remaining in the +# docstring, even if it isn't valid Python. Since it isn't valid Python, +# reformatting fails and the entire thing is skipped. +def markdown_skipped_unclosed_non_python(): + """ + Do cool stuff. - cool_stuff( 1 ) + ```py + cool_stuff( 1 ) - Done. - """ - pass + I forgot to close the code block, and this is definitely not + Python. So nothing here gets formatted. + """ + pass -# Like the previous test, but adds a second line. -def rst_literal_skipped_first_line_not_indented_tab_multiple(): - """ - Do cool stuff:: +# This has a Python snippet with a docstring that contains a closing fence. +# This splits the embedded docstring and makes the overall snippet invalid. +def markdown_skipped_accidental_closure(): + """ + Do cool stuff. - cool_stuff( 1 ) - cool_stuff( 2 ) + ```py + cool_stuff( 1 ) + ''' + ``` + ''' + ``` - Done. - """ - pass + Done. + """ + pass -# Tests that a code block with a second line that is not properly indented gets -# skipped. A valid code block needs to have an empty line separating these. +# When a line is unindented all the way out before the standard indent of the +# docstring, the code reformatting ends up interacting poorly with the standard +# docstring whitespace normalization logic. This is probably a bug, and we +# should probably treat the Markdown block as valid, but for now, we detect +# the unindented line and declare the block as invalid and thus do no code +# reformatting. # -# One trick here is that we need to make sure the Python code in the snippet is -# valid, otherwise it would be skipped because of invalid Python. -def rst_literal_skipped_subsequent_line_not_indented(): - """ - Do cool stuff:: +# FIXME: Fixing this (if we think it's a bug) probably requires refactoring the +# docstring whitespace normalization to be aware of code snippets. Or perhaps +# plausibly, to do normalization *after* code snippets have been formatted. +def markdown_skipped_unindented_completely(): + """ + Do cool stuff. - if True: - cool_stuff( ''' - hiya''' ) + ```py + cool_stuff( 1 ) + ``` - Done. - """ - pass + Done. + """ + pass -# In this test, we write what looks like a code-block, but it should be treated -# as invalid due to the missing `language` argument. -# -# It does still look like it could be a literal block according to the literal -# rules, but we currently consider the `.. ` prefix to indicate that it is not -# a literal block. -def rst_literal_skipped_not_directive(): - """ - .. code-block:: +# This test is fallout from treating fenced code blocks with unindented lines +# as invalid. We probably should treat this as a valid block. Indeed, if we +# remove the logic that makes the `markdown_skipped_unindented_completely` test +# pass, then this code snippet will get reformatted correctly. +def markdown_skipped_unindented_somewhat(): + """ + Do cool stuff. - cool_stuff( 1 ) + ```py + cool_stuff( 1 ) + ``` - Done. - """ - pass + Done. + """ + pass -# In this test, we start a line with `.. `, which makes it look like it might -# be a directive. But instead continue it as if it was just some periods from -# the previous line, and then try to end it by starting a literal block. +# This tests that if a Markdown block contains a line that has less of an +# indent than another line. # -# But because of the `.. ` in the beginning, we wind up not treating this as a -# code snippet. The reST render I was using to test things does actually treat -# this as a code block, so we may be out of conformance here. -def rst_literal_skipped_possible_false_negative(): - """ - This is a test. - .. This is a test:: +# There is some judgment involved in what the right behavior is here. We +# could "normalize" the indentation so that the minimum is the indent of the +# opening fence line. If we did that here, then the code snippet would become +# valid and format as Python. But at time of writing, we don't, which leads to +# inconsistent indentation and thus invalid Python. +def markdown_skipped_unindented_with_inconsistent_indentation(): + """ + Do cool stuff. - cool_stuff( 1 ) + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` - Done. - """ - pass + Done. + """ + pass -# This tests that a doctest inside of a reST literal block doesn't get -# reformatted. It's plausible this isn't the right behavior, but it also seems -# like it might be the right behavior since it is a literal block. (The doctest -# makes the Python code invalid.) -def rst_literal_skipped_doctest(): - """ - Do cool stuff:: +def markdown_skipped_doctest(): + """ + Do cool stuff. - >>> cool_stuff( 1 ) + ```py + >>> cool_stuff( 1 ) + ``` - Done. - """ - pass + Done. + """ + pass -def rst_directive_skipped_not_indented(): - """ - .. code-block:: python +def markdown_skipped_rst_literal(): + """ + Do cool stuff. - cool_stuff( 1 ) + ```py + And do this:: - Done. - """ - pass + cool_stuff( 1 ) + ``` -def rst_directive_skipped_wrong_language(): - """ - .. code-block:: rust + Done. + """ + pass - cool_stuff( 1 ) - Done. - """ - pass +def markdown_skipped_rst_directive(): + """ + Do cool stuff. + ```py + .. code-block:: python -# This gets skipped for the same reason that the doctest in a literal block -# gets skipped. -def rst_directive_skipped_doctest(): - """ - .. code-block:: python + cool_stuff( 1 ) - >>> cool_stuff( 1 ) + ``` - Done. - """ - pass + Done. + """ + pass ``` -### Output 3 +### Output 5 ``` -indent-style = tab +indent-style = space line-width = 88 -indent-width = 8 +indent-width = 4 quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect -docstring-code = Disabled +docstring-code = Enabled preview = Disabled ``` @@ -2559,182 +6787,180 @@ preview = Disabled # The simplest doctest to ensure basic formatting works. def doctest_simple(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff( 1 ) - 2 - """ - pass + >>> cool_stuff(1) + 2 + """ + pass # Another simple test, but one where the Python code # extends over multiple lines. def doctest_simple_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass + >>> def cool_stuff(x): + ... print(f"hi {x}") + hi 2 + """ + pass # Test that we support multiple directly adjacent # doctests. def doctest_adjacent(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff( x ) - >>> cool_stuff( y ) - 2 - """ - pass + >>> cool_stuff(x) + >>> cool_stuff(y) + 2 + """ + pass # Test that a doctest on the last non-whitespace line of a docstring # reformats correctly. def doctest_last_line(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff( x ) - """ - pass + >>> cool_stuff(x) + """ + pass # Test that a doctest that continues to the last non-whitespace line of # a docstring reformats correctly. def doctest_last_line_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - """ - pass + >>> def cool_stuff(x): + ... print(f"hi {x}") + """ + pass # Test that a doctest on the real last line of a docstring reformats # correctly. def doctest_really_last_line(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff( x )""" - pass + >>> cool_stuff(x)""" + pass # Test that a continued doctest on the real last line of a docstring reformats # correctly. def doctest_really_last_line_continued(): - """ - Do cool stuff. - - >>> cool_stuff( x ) - ... more( y )""" - pass + """ + Do cool stuff. + + >>> cool_stuff(x) + ... more(y)""" + pass # Test that a doctest is correctly identified and formatted with a blank # continuation line. def doctest_blank_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff ( x ): - ... print( x ) - ... - ... print( x ) - """ - pass + >>> def cool_stuff(x): + ... print(x) + ... + ... print(x) + """ + pass # Tests that a blank PS2 line at the end of a doctest can get dropped. # It is treated as part of the Python snippet which will trim the # trailing whitespace. def doctest_blank_end(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... - """ - pass + >>> def cool_stuff(x): + ... print(x) + ... print(x) + """ + pass # Tests that a blank PS2 line at the end of a doctest can get dropped # even when there is text following it. def doctest_blank_end_then_some_text(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... + >>> def cool_stuff(x): + ... print(x) + ... print(x) - And say something else. - """ - pass + And say something else. + """ + pass # Test that a doctest containing a triple quoted string gets formatted # correctly and doesn't result in invalid syntax. def doctest_with_triple_single(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = '''tricksy''' - """ - pass + >>> x = '''tricksy''' + """ + pass # Test that a doctest containing a triple quoted f-string gets # formatted correctly and doesn't result in invalid syntax. def doctest_with_triple_single(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = f'''tricksy''' - """ - pass + >>> x = f'''tricksy''' + """ + pass # Another nested multi-line string case, but with triple escaped double # quotes inside a triple single quoted string. def doctest_with_triple_escaped_double(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = '''\"\"\"''' - """ - pass + >>> x = '''\"\"\"''' + """ + pass # Tests that inverting the triple quoting works as expected. def doctest_with_triple_inverted(): - ''' - Do cool stuff. + ''' + Do cool stuff. - >>> x = """tricksy""" - ''' - pass + >>> x = """tricksy""" + ''' + pass # Tests that inverting the triple quoting with an f-string works as # expected. def doctest_with_triple_inverted_fstring(): - ''' - Do cool stuff. + ''' + Do cool stuff. - >>> x = f"""tricksy""" - ''' - pass + >>> x = f"""tricksy""" + ''' + pass # Tests nested doctests are ignored. That is, we don't format doctests @@ -2744,30 +6970,30 @@ def doctest_with_triple_inverted_fstring(): # nesting quotes. It also seems like a generally sensible restriction, # although it could be lifted if necessary I believe. def doctest_nested_doctest_not_formatted(): - ''' - Do cool stuff. + ''' + Do cool stuff. - >>> def nested( x ): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass - ''' - pass + >>> def nested(x): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass # Tests that the starting column does not matter. def doctest_varying_start_column(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> assert ("Easy!") - >>> import math - >>> math.floor( 1.9 ) - 1 - """ - pass + >>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1 + """ + pass # Tests that long lines get wrapped... appropriately. @@ -2783,59 +7009,61 @@ def doctest_varying_start_column(): # would be to expose another formatter option for controlling the # line-width of code snippets independently. def doctest_long_lines(): - """ - Do cool stuff. + """ + Do cool stuff. - This won't get wrapped even though it exceeds our configured - line width because it doesn't exceed the line width within this - docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) - But this one is long enough to get wrapped. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) - """ - # This demostrates a normal line that will get wrapped but won't - # get wrapped in the docstring above because of how the line-width - # setting gets reset at the first column in each code snippet. - foo, bar, quux = this_is_a_long_line( - lion, giraffe, hippo, zeba, lemur, penguin, monkey - ) + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard + ... ) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) # Checks that a simple but invalid doctest gets skipped. def doctest_skipped_simple(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool-stuff( x ): - 2 - """ - pass + >>> cool-stuff( x ): + 2 + """ + pass # Checks that a simple doctest that is continued over multiple lines, # but is invalid, gets skipped. def doctest_skipped_simple_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool-stuff( x ): - ... print( f"hi {x}" ); - 2 - """ - pass + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass # Checks that a doctest with improper indentation gets skipped. def doctest_skipped_inconsistent_indent(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass # Checks that a doctest with some proper indentation and some improper @@ -2843,34 +7071,34 @@ def doctest_skipped_inconsistent_indent(): # before the inconsistent indentation is formatted. This requires that # the part before it is valid Python. def doctest_skipped_partial_inconsistent_indent(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( x ) - ... print( f"hi {x}" ); - hi 2 - """ - pass + >>> def cool_stuff(x): + ... print(x) + ... print( f"hi {x}" ); + hi 2 + """ + pass # Checks that a doctest with improper triple single quoted string gets # skipped. That is, the code snippet is itself invalid Python, so it is # left as is. def doctest_skipped_triple_incorrect(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> foo( x ) - ... '''tri'''cksy''' - """ - pass + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass # Tests that a doctest on a single line is skipped. def doctest_skipped_one_line(): - ">>> foo( x )" - pass + ">>> foo( x )" + pass # f-strings are not considered docstrings[1], so any doctests @@ -2878,25 +7106,25 @@ def doctest_skipped_one_line(): # # [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals def doctest_skipped_fstring(): - f""" + f""" Do cool stuff. >>> cool_stuff( 1 ) 2 """ - pass + pass # Test that a doctest containing a triple quoted string at least # does not result in invalid Python code. Ideally this would format # correctly, but at time of writing it does not. def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = '\"\"\"' - """ - pass + >>> x = '\"\"\"' + """ + pass ############################################################################### @@ -2914,125 +7142,128 @@ def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): def rst_literal_simple(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) + cool_stuff(1) - Done. - """ - pass + Done. + """ + pass def rst_literal_simple_continued(): - """ - Do cool stuff:: + """ + Do cool stuff:: - def cool_stuff( x ): - print( f"hi {x}" ); + def cool_stuff(x): + print(f"hi {x}") - Done. - """ - pass + Done. + """ + pass # Tests that we can end the literal block on the second # to last line of the docstring. def rst_literal_second_to_last(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) - """ - pass + cool_stuff(1) + """ + pass # Tests that we can end the literal block on the actual # last line of the docstring. def rst_literal_actually_last(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 )""" - pass + cool_stuff(1)""" + pass def rst_literal_with_blank_lines(): - """ - Do cool stuff:: + """ + Do cool stuff:: - def cool_stuff( x ): - print( f"hi {x}" ); + def cool_stuff(x): + print(f"hi {x}") - def other_stuff( y ): - print( y ) - Done. - """ - pass + def other_stuff(y): + print(y) + + Done. + """ + pass # Extra blanks should be preserved. def rst_literal_extra_blanks(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) + cool_stuff(1) - Done. - """ - pass + Done. + """ + pass # If a literal block is never properly ended (via a non-empty unindented line), # then the end of the block should be the last non-empty line. And subsequent # empty lines should be preserved as-is. def rst_literal_extra_blanks_at_end(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) + cool_stuff(1) - """ - pass + """ + pass # A literal block can contain many empty lines and it should not end the block # if it continues. def rst_literal_extra_blanks_in_snippet(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) + cool_stuff(1) - cool_stuff( 2 ) + cool_stuff(2) - Done. - """ - pass + Done. + """ + pass # This tests that a unindented line appearing after an indented line (but where # the indent is still beyond the minimum) gets formatted properly. def rst_literal_subsequent_line_not_indented(): - """ - Do cool stuff:: + """ + Do cool stuff:: - if True: - cool_stuff( ''' - hiya''' ) + if True: + cool_stuff( + ''' + hiya''' + ) - Done. - """ - pass + Done. + """ + pass # This checks that if the first line in a code snippet has been indented with @@ -3044,27 +7275,27 @@ def rst_literal_subsequent_line_not_indented(): # itself also seems to recognize this as a code block, although it appears # under-specified.) def rst_literal_first_line_indent_uses_tabs_4spaces(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) + cool_stuff(1) - Done. - """ - pass + Done. + """ + pass # Like the test above, but with multiple lines. def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) - cool_stuff( 2 ) + cool_stuff(1) + cool_stuff(2) - Done. - """ - pass + Done. + """ + pass # Another test with tabs, except in this case, if your tabwidth is less than @@ -3075,42 +7306,42 @@ def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): # snippet is actually seen as being more indented than the opening `::` line. # As with the above example, reST seems to behave the same way here. def rst_literal_first_line_indent_uses_tabs_8spaces(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) + cool_stuff(1) - Done. - """ - pass + Done. + """ + pass # Like the test above, but with multiple lines. def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) - cool_stuff( 2 ) + cool_stuff(1) + cool_stuff(2) - Done. - """ - pass + Done. + """ + pass # Tests that if two lines in a literal block are indented to the same level # but by different means (tabs versus spaces), then we correctly recognize the # block and format it. def rst_literal_first_line_tab_second_line_spaces(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) - cool_stuff( 2 ) + cool_stuff(1) + cool_stuff(2) - Done. - """ - pass + Done. + """ + pass # Tests that when two lines in a code snippet have weird and inconsistent @@ -3132,122 +7363,122 @@ def rst_literal_first_line_tab_second_line_spaces(): # but we might want to switch to the alternative if cases like this show up in # the real world. ---AG def rst_literal_odd_indentation(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) - cool_stuff( 2 ) + cool_stuff(1) + cool_stuff(2) - Done. - """ - pass + Done. + """ + pass # Tests that having a line with a lone `::` works as an introduction of a # literal block. def rst_literal_lone_colon(): - """ - Do cool stuff. + """ + Do cool stuff. - :: + :: - cool_stuff( 1 ) + cool_stuff(1) - Done. - """ - pass + Done. + """ + pass def rst_directive_simple(): - """ - .. code-block:: python + """ + .. code-block:: python - cool_stuff( 1 ) + cool_stuff(1) - Done. - """ - pass + Done. + """ + pass def rst_directive_case_insensitive(): - """ - .. cOdE-bLoCk:: python + """ + .. cOdE-bLoCk:: python - cool_stuff( 1 ) + cool_stuff(1) - Done. - """ - pass + Done. + """ + pass def rst_directive_sourcecode(): - """ - .. sourcecode:: python - - cool_stuff( 1 ) - - Done. - """ - pass + """ + .. sourcecode:: python + cool_stuff(1) -def rst_directive_options(): - """ - .. code-block:: python - :linenos: - :emphasize-lines: 2,3 - :name: blah blah + Done. + """ + pass - cool_stuff( 1 ) - cool_stuff( 2 ) - cool_stuff( 3 ) - cool_stuff( 4 ) - Done. - """ - pass +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + + cool_stuff(1) + cool_stuff(2) + cool_stuff(3) + cool_stuff(4) + + Done. + """ + pass # In this case, since `pycon` isn't recognized as a Python code snippet, the # docstring reformatter ignores it. But it then picks up the doctest and # reformats it. def rst_directive_doctest(): - """ - .. code-block:: pycon + """ + .. code-block:: pycon - >>> cool_stuff( 1 ) + >>> cool_stuff(1) - Done. - """ - pass + Done. + """ + pass # This checks that if the first non-empty line after the start of a literal # block is not indented more than the line containing the `::`, then it is not # treated as a code snippet. def rst_literal_skipped_first_line_not_indented(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) + cool_stuff( 1 ) - Done. - """ - pass + Done. + """ + pass # Like the test above, but inserts an indented line after the un-indented one. # This should not cause the literal block to be resumed. def rst_literal_skipped_first_line_not_indented_then_indented(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) - cool_stuff( 2 ) + cool_stuff( 1 ) + cool_stuff( 2 ) - Done. - """ - pass + Done. + """ + pass # This also checks that a code snippet is not reformatted when the indentation @@ -3256,27 +7487,27 @@ def rst_literal_skipped_first_line_not_indented_then_indented(): # length is computed by assuming a tabwidth equal to 8. reST also rejects this # and doesn't treat it as a literal block. def rst_literal_skipped_first_line_not_indented_tab(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) + cool_stuff( 1 ) - Done. - """ - pass + Done. + """ + pass # Like the previous test, but adds a second line. def rst_literal_skipped_first_line_not_indented_tab_multiple(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) - cool_stuff( 2 ) + cool_stuff( 1 ) + cool_stuff( 2 ) - Done. - """ - pass + Done. + """ + pass # Tests that a code block with a second line that is not properly indented gets @@ -3285,16 +7516,16 @@ def rst_literal_skipped_first_line_not_indented_tab_multiple(): # One trick here is that we need to make sure the Python code in the snippet is # valid, otherwise it would be skipped because of invalid Python. def rst_literal_skipped_subsequent_line_not_indented(): - """ - Do cool stuff:: + """ + Do cool stuff:: - if True: - cool_stuff( ''' - hiya''' ) + if True: + cool_stuff( ''' + hiya''' ) - Done. - """ - pass + Done. + """ + pass # In this test, we write what looks like a code-block, but it should be treated @@ -3304,14 +7535,14 @@ def rst_literal_skipped_subsequent_line_not_indented(): # rules, but we currently consider the `.. ` prefix to indicate that it is not # a literal block. def rst_literal_skipped_not_directive(): - """ - .. code-block:: + """ + .. code-block:: - cool_stuff( 1 ) + cool_stuff( 1 ) - Done. - """ - pass + Done. + """ + pass # In this test, we start a line with `.. `, which makes it look like it might @@ -3322,15 +7553,15 @@ def rst_literal_skipped_not_directive(): # code snippet. The reST render I was using to test things does actually treat # this as a code block, so we may be out of conformance here. def rst_literal_skipped_possible_false_negative(): - """ - This is a test. - .. This is a test:: + """ + This is a test. + .. This is a test:: - cool_stuff( 1 ) + cool_stuff( 1 ) - Done. - """ - pass + Done. + """ + pass # This tests that a doctest inside of a reST literal block doesn't get @@ -3338,1758 +7569,1905 @@ def rst_literal_skipped_possible_false_negative(): # like it might be the right behavior since it is a literal block. (The doctest # makes the Python code invalid.) def rst_literal_skipped_doctest(): - """ - Do cool stuff:: + """ + Do cool stuff:: - >>> cool_stuff( 1 ) + >>> cool_stuff( 1 ) - Done. - """ - pass + Done. + """ + pass + + +def rst_literal_skipped_markdown(): + """ + Do cool stuff:: + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass def rst_directive_skipped_not_indented(): - """ - .. code-block:: python + """ + .. code-block:: python - cool_stuff( 1 ) + cool_stuff( 1 ) - Done. - """ - pass + Done. + """ + pass def rst_directive_skipped_wrong_language(): - """ - .. code-block:: rust + """ + .. code-block:: rust - cool_stuff( 1 ) + cool_stuff( 1 ) - Done. - """ - pass + Done. + """ + pass # This gets skipped for the same reason that the doctest in a literal block # gets skipped. def rst_directive_skipped_doctest(): - """ - .. code-block:: python + """ + .. code-block:: python + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +############################################################################### +# Markdown CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Markdown fenced code blocks. +# +# See: https://spec.commonmark.org/0.30/#fenced-code-blocks +############################################################################### + + +def markdown_simple(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ``` + + Done. + """ + pass + + +def markdown_simple_continued(): + """ + Do cool stuff. + + ```python + def cool_stuff(x): + print(f"hi {x}") + ``` + + Done. + """ + pass + + +# Tests that unlabeled Markdown fenced code blocks are assumed to be Python. +def markdown_unlabeled(): + """ + Do cool stuff. + + ``` + cool_stuff(1) + ``` + + Done. + """ + pass + + +# Tests that fenced code blocks using tildes work. +def markdown_tildes(): + """ + Do cool stuff. + + ~~~py + cool_stuff(1) + ~~~ + + Done. + """ + pass + + +# Tests that a longer closing fence is just fine and dandy. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + `````` + + Done. + """ + pass + + +# Tests that an invalid closing fence is treated as invalid. +# +# We embed it into a docstring so that the surrounding Python +# remains valid. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ''' + ```invalid + ''' + cool_stuff(2) + ``` + + Done. + """ + pass + + +# Tests that one can nest fenced code blocks by using different numbers of +# backticks. +def markdown_nested_fences(): + """ + Do cool stuff. + + `````` + do_something( + ''' + ``` + did i trick you? + ``` + ''' + ) + `````` - >>> cool_stuff( 1 ) + Done. + """ + pass - Done. - """ - pass -``` +# Tests that an unclosed block gobbles up everything remaining in the +# docstring. When it's only empty lines, those are passed into the formatter +# and thus stripped. +def markdown_unclosed_empty_lines(): + """ + Do cool stuff. -### Output 4 -``` -indent-style = tab -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled -``` + ```py + cool_stuff(1)""" + pass -```python -############################################################################### -# DOCTEST CODE EXAMPLES -# -# This section shows examples of docstrings that contain code snippets in -# Python's "doctest" format. -# -# See: https://docs.python.org/3/library/doctest.html -############################################################################### -# The simplest doctest to ensure basic formatting works. -def doctest_simple(): - """ - Do cool stuff. +# Tests that we can end the block on the second to last line of the +# docstring. +def markdown_second_to_last(): + """ + Do cool stuff. - >>> cool_stuff( 1 ) - 2 - """ - pass + ```py + cool_stuff(1) + ``` + """ + pass -# Another simple test, but one where the Python code -# extends over multiple lines. -def doctest_simple_continued(): - """ - Do cool stuff. +# Tests that an unclosed block with one extra line at the end is treated +# correctly. As per the CommonMark spec, an unclosed fenced code block contains +# everything following the opening fences. Since formatting the code snippet +# trims lines, the last empty line is removed here. +def markdown_second_to_last(): + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass + ```py + cool_stuff(1)""" + pass -# Test that we support multiple directly adjacent -# doctests. -def doctest_adjacent(): - """ - Do cool stuff. +# Tests that we can end the block on the actual last line of the docstring. +def markdown_actually_last(): + """ + Do cool stuff. - >>> cool_stuff( x ) - >>> cool_stuff( y ) - 2 - """ - pass + ```py + cool_stuff(1) + ```""" + pass -# Test that a doctest on the last non-whitespace line of a docstring -# reformats correctly. -def doctest_last_line(): - """ - Do cool stuff. +# Tests that an unclosed block that ends on the last line of a docstring +# is handled correctly. +def markdown_unclosed_actually_last(): + """ + Do cool stuff. - >>> cool_stuff( x ) - """ - pass + ```py + cool_stuff(1)""" + pass -# Test that a doctest that continues to the last non-whitespace line of -# a docstring reformats correctly. -def doctest_last_line_continued(): - """ - Do cool stuff. +def markdown_with_blank_lines(): + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - """ - pass + ```py + def cool_stuff(x): + print(f"hi {x}") -# Test that a doctest on the real last line of a docstring reformats -# correctly. -def doctest_really_last_line(): - """ - Do cool stuff. + def other_stuff(y): + print(y) + ``` - >>> cool_stuff( x )""" - pass + Done. + """ + pass -# Test that a continued doctest on the real last line of a docstring reformats -# correctly. -def doctest_really_last_line_continued(): - """ - Do cool stuff. +def markdown_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff. - >>> cool_stuff( x ) - ... more( y )""" - pass + ```py + cool_stuff(1) + ``` + Done. + """ + pass -# Test that a doctest is correctly identified and formatted with a blank -# continuation line. -def doctest_blank_continued(): - """ - Do cool stuff. - >>> def cool_stuff ( x ): - ... print( x ) - ... - ... print( x ) - """ - pass +def markdown_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff. + ```py + cool_stuff(1) + cool_stuff(2) + ``` -# Tests that a blank PS2 line at the end of a doctest can get dropped. -# It is treated as part of the Python snippet which will trim the -# trailing whitespace. -def doctest_blank_end(): - """ - Do cool stuff. + Done. + """ + pass - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... - """ - pass +def markdown_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff. -# Tests that a blank PS2 line at the end of a doctest can get dropped -# even when there is text following it. -def doctest_blank_end_then_some_text(): - """ - Do cool stuff. + ```py + cool_stuff(1) + ``` - >>> def cool_stuff ( x ): - ... print( x ) - ... print( x ) - ... + Done. + """ + pass - And say something else. - """ - pass +def markdown_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff. -# Test that a doctest containing a triple quoted string gets formatted -# correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): - """ - Do cool stuff. + ```py + cool_stuff(1) + cool_stuff(2) + ``` - >>> x = '''tricksy''' - """ - pass + Done. + """ + pass -# Test that a doctest containing a triple quoted f-string gets -# formatted correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): - """ - Do cool stuff. +def markdown_first_line_tab_second_line_spaces(): + """ + Do cool stuff. - >>> x = f'''tricksy''' - """ - pass + ```py + cool_stuff(1) + cool_stuff(2) + ``` + Done. + """ + pass -# Another nested multi-line string case, but with triple escaped double -# quotes inside a triple single quoted string. -def doctest_with_triple_escaped_double(): - """ - Do cool stuff. - >>> x = '''\"\"\"''' - """ - pass +def markdown_odd_indentation(): + """ + Do cool stuff. + ```py + cool_stuff(1) + cool_stuff(2) + ``` -# Tests that inverting the triple quoting works as expected. -def doctest_with_triple_inverted(): - ''' - Do cool stuff. + Done. + """ + pass - >>> x = """tricksy""" - ''' - pass +# Extra blanks should be *not* be preserved (unlike reST) because they are part +# of the code snippet (per CommonMark spec), and thus get trimmed as part of +# code formatting. +def markdown_extra_blanks(): + """ + Do cool stuff. -# Tests that inverting the triple quoting with an f-string works as -# expected. -def doctest_with_triple_inverted_fstring(): - ''' - Do cool stuff. + ```py + cool_stuff(1) + ``` - >>> x = f"""tricksy""" - ''' - pass + Done. + """ + pass -# Tests nested doctests are ignored. That is, we don't format doctests -# recursively. We only recognize "top level" doctests. -# -# This restriction primarily exists to avoid needing to deal with -# nesting quotes. It also seems like a generally sensible restriction, -# although it could be lifted if necessary I believe. -def doctest_nested_doctest_not_formatted(): - ''' - Do cool stuff. +# A block can contain many empty lines within it. +def markdown_extra_blanks_in_snippet(): + """ + Do cool stuff. - >>> def nested( x ): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass - ''' - pass + ```py + cool_stuff(1) -# Tests that the starting column does not matter. -def doctest_varying_start_column(): - """ - Do cool stuff. + cool_stuff(2) + ``` - >>> assert ("Easy!") - >>> import math - >>> math.floor( 1.9 ) - 1 - """ - pass + Done. + """ + pass -# Tests that long lines get wrapped... appropriately. -# -# The docstring code formatter uses the same line width settings as for -# formatting other code. This means that a line in the docstring can -# actually extend past the configured line limit. -# -# It's not quite clear whether this is desirable or not. We could in -# theory compute the intendation length of a code snippet and then -# adjust the line-width setting on a recursive call to the formatter. -# But there are assuredly pathological cases to consider. Another path -# would be to expose another formatter option for controlling the -# line-width of code snippets independently. -def doctest_long_lines(): - """ - Do cool stuff. +def markdown_weird_closing(): + """ + Code block with weirdly placed closing fences. - This won't get wrapped even though it exceeds our configured - line width because it doesn't exceed the line width within this - docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + ```python + cool_stuff(1) + ``` + # The above fences look like it shouldn't close the block, but we + # allow it to. The fences below re-open a block (until the end of + # the docstring), but it's invalid Python and thus doesn't get + # reformatted. + a = 10 + ``` - But this one is long enough to get wrapped. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard) - """ - # This demostrates a normal line that will get wrapped but won't - # get wrapped in the docstring above because of how the line-width - # setting gets reset at the first column in each code snippet. - foo, bar, quux = this_is_a_long_line( - lion, giraffe, hippo, zeba, lemur, penguin, monkey - ) + Now the code block is closed + """ + pass -# Checks that a simple but invalid doctest gets skipped. -def doctest_skipped_simple(): - """ - Do cool stuff. +def markdown_over_indented(): + """ + A docstring + over intended + ```python + print(5) + ``` + """ + pass - >>> cool-stuff( x ): - 2 - """ - pass +# Tests that an unclosed block gobbles up everything remaining in the +# docstring, even if it isn't valid Python. Since it isn't valid Python, +# reformatting fails and the entire thing is skipped. +def markdown_skipped_unclosed_non_python(): + """ + Do cool stuff. -# Checks that a simple doctest that is continued over multiple lines, -# but is invalid, gets skipped. -def doctest_skipped_simple_continued(): - """ - Do cool stuff. + ```py + cool_stuff( 1 ) - >>> def cool-stuff( x ): - ... print( f"hi {x}" ); - 2 - """ - pass + I forgot to close the code block, and this is definitely not + Python. So nothing here gets formatted. + """ + pass -# Checks that a doctest with improper indentation gets skipped. -def doctest_skipped_inconsistent_indent(): - """ - Do cool stuff. +# This has a Python snippet with a docstring that contains a closing fence. +# This splits the embedded docstring and makes the overall snippet invalid. +def markdown_skipped_accidental_closure(): + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass + ```py + cool_stuff( 1 ) + ''' + ``` + ''' + ``` + Done. + """ + pass -# Checks that a doctest with some proper indentation and some improper -# indentation is "partially" formatted. That is, the part that appears -# before the inconsistent indentation is formatted. This requires that -# the part before it is valid Python. -def doctest_skipped_partial_inconsistent_indent(): - """ - Do cool stuff. - >>> def cool_stuff( x ): - ... print( x ) - ... print( f"hi {x}" ); - hi 2 - """ - pass +# When a line is unindented all the way out before the standard indent of the +# docstring, the code reformatting ends up interacting poorly with the standard +# docstring whitespace normalization logic. This is probably a bug, and we +# should probably treat the Markdown block as valid, but for now, we detect +# the unindented line and declare the block as invalid and thus do no code +# reformatting. +# +# FIXME: Fixing this (if we think it's a bug) probably requires refactoring the +# docstring whitespace normalization to be aware of code snippets. Or perhaps +# plausibly, to do normalization *after* code snippets have been formatted. +def markdown_skipped_unindented_completely(): + """ + Do cool stuff. + ```py + cool_stuff( 1 ) + ``` -# Checks that a doctest with improper triple single quoted string gets -# skipped. That is, the code snippet is itself invalid Python, so it is -# left as is. -def doctest_skipped_triple_incorrect(): - """ - Do cool stuff. + Done. + """ + pass - >>> foo( x ) - ... '''tri'''cksy''' - """ - pass +# This test is fallout from treating fenced code blocks with unindented lines +# as invalid. We probably should treat this as a valid block. Indeed, if we +# remove the logic that makes the `markdown_skipped_unindented_completely` test +# pass, then this code snippet will get reformatted correctly. +def markdown_skipped_unindented_somewhat(): + """ + Do cool stuff. -# Tests that a doctest on a single line is skipped. -def doctest_skipped_one_line(): - ">>> foo( x )" - pass + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass -# f-strings are not considered docstrings[1], so any doctests -# inside of them should not be formatted. +# This tests that if a Markdown block contains a line that has less of an +# indent than another line. # -# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals -def doctest_skipped_fstring(): - f""" +# There is some judgment involved in what the right behavior is here. We +# could "normalize" the indentation so that the minimum is the indent of the +# opening fence line. If we did that here, then the code snippet would become +# valid and format as Python. But at time of writing, we don't, which leads to +# inconsistent indentation and thus invalid Python. +def markdown_skipped_unindented_with_inconsistent_indentation(): + """ Do cool stuff. - >>> cool_stuff( 1 ) - 2 + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. """ - pass + pass -# Test that a doctest containing a triple quoted string at least -# does not result in invalid Python code. Ideally this would format -# correctly, but at time of writing it does not. -def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): - """ - Do cool stuff. +def markdown_skipped_doctest(): + """ + Do cool stuff. - >>> x = '\"\"\"' - """ - pass + ```py + >>> cool_stuff( 1 ) + ``` + Done. + """ + pass -############################################################################### -# reStructuredText CODE EXAMPLES -# -# This section shows examples of docstrings that contain code snippets in -# reStructuredText formatted code blocks. -# -# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks -# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 -############################################################################### +def markdown_skipped_rst_literal(): + """ + Do cool stuff. -def rst_literal_simple(): - """ - Do cool stuff:: + ```py + And do this:: - cool_stuff( 1 ) + cool_stuff( 1 ) - Done. - """ - pass + ``` + Done. + """ + pass -def rst_literal_simple_continued(): - """ - Do cool stuff:: - def cool_stuff( x ): - print( f"hi {x}" ); +def markdown_skipped_rst_directive(): + """ + Do cool stuff. - Done. - """ - pass + ```py + .. code-block:: python + cool_stuff( 1 ) -# Tests that we can end the literal block on the second -# to last line of the docstring. -def rst_literal_second_to_last(): - """ - Do cool stuff:: + ``` - cool_stuff( 1 ) - """ - pass + Done. + """ + pass +``` -# Tests that we can end the literal block on the actual -# last line of the docstring. -def rst_literal_actually_last(): - """ - Do cool stuff:: +### Output 6 +``` +indent-style = space +line-width = 88 +indent-width = 2 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +preview = Disabled +``` - cool_stuff( 1 )""" - pass +```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. -def rst_literal_with_blank_lines(): - """ - Do cool stuff:: + >>> cool_stuff(1) + 2 + """ + pass - def cool_stuff( x ): - print( f"hi {x}" ); - def other_stuff( y ): - print( y ) +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. - Done. - """ - pass + >>> def cool_stuff(x): + ... print(f"hi {x}") + hi 2 + """ + pass -# Extra blanks should be preserved. -def rst_literal_extra_blanks(): - """ - Do cool stuff:: +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + >>> cool_stuff(x) + >>> cool_stuff(y) + 2 + """ + pass - cool_stuff( 1 ) +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + >>> cool_stuff(x) + """ + pass - Done. - """ - pass +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + >>> def cool_stuff(x): + ... print(f"hi {x}") + """ + pass -# If a literal block is never properly ended (via a non-empty unindented line), -# then the end of the block should be the last non-empty line. And subsequent -# empty lines should be preserved as-is. -def rst_literal_extra_blanks_at_end(): - """ - Do cool stuff:: +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. - cool_stuff( 1 ) + >>> cool_stuff(x)""" + pass +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. - """ - pass + >>> cool_stuff(x) + ... more(y)""" + pass -# A literal block can contain many empty lines and it should not end the block -# if it continues. -def rst_literal_extra_blanks_in_snippet(): - """ - Do cool stuff:: +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. - cool_stuff( 1 ) + >>> def cool_stuff(x): + ... print(x) + ... + ... print(x) + """ + pass - cool_stuff( 2 ) +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. - Done. - """ - pass + >>> def cool_stuff(x): + ... print(x) + ... print(x) + """ + pass -# This tests that a unindented line appearing after an indented line (but where -# the indent is still beyond the minimum) gets formatted properly. -def rst_literal_subsequent_line_not_indented(): - """ - Do cool stuff:: +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. - if True: - cool_stuff( ''' - hiya''' ) + >>> def cool_stuff(x): + ... print(x) + ... print(x) - Done. - """ - pass + And say something else. + """ + pass -# This checks that if the first line in a code snippet has been indented with -# tabs, then so long as its "indentation length" is considered bigger than the -# line with `::`, it is reformatted as code. -# -# (If your tabwidth is set to 4, then it looks like the code snippet -# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST -# itself also seems to recognize this as a code block, although it appears -# under-specified.) -def rst_literal_first_line_indent_uses_tabs_4spaces(): - """ - Do cool stuff:: +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. - cool_stuff( 1 ) + >>> x = '''tricksy''' + """ + pass - Done. - """ - pass +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. -# Like the test above, but with multiple lines. -def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): - """ - Do cool stuff:: + >>> x = f'''tricksy''' + """ + pass - cool_stuff( 1 ) - cool_stuff( 2 ) - Done. - """ - pass +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + >>> x = '''\"\"\"''' + """ + pass -# Another test with tabs, except in this case, if your tabwidth is less than -# 8, than the code snippet actually looks like its indent is *less* than the -# opening line with a `::`. One might presume this means that the code snippet -# is not treated as a literal block and thus not reformatted, but since we -# assume all tabs have tabwidth=8 when computing indentation length, the code -# snippet is actually seen as being more indented than the opening `::` line. -# As with the above example, reST seems to behave the same way here. -def rst_literal_first_line_indent_uses_tabs_8spaces(): - """ - Do cool stuff:: - cool_stuff( 1 ) +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. - Done. - """ - pass + >>> x = """tricksy""" + ''' + pass -# Like the test above, but with multiple lines. -def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): - """ - Do cool stuff:: +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. - cool_stuff( 1 ) - cool_stuff( 2 ) + >>> x = f"""tricksy""" + ''' + pass - Done. - """ - pass +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. -# Tests that if two lines in a literal block are indented to the same level -# but by different means (tabs versus spaces), then we correctly recognize the -# block and format it. -def rst_literal_first_line_tab_second_line_spaces(): - """ - Do cool stuff:: + >>> def nested(x): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass - cool_stuff( 1 ) - cool_stuff( 2 ) - Done. - """ - pass +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + >>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1 + """ + pass -# Tests that when two lines in a code snippet have weird and inconsistent -# indentation, the code still gets formatted so long as the indent is greater -# than the indent of the `::` line. -# -# In this case, the minimum indent is 5 spaces (from the second line) where as -# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). -# The minimum indent is stripped from each code line. Since tabs aren't -# divisible, the entire tab is stripped, which means the first and second lines -# wind up with the same level of indentation. -# -# An alternative behavior here would be that the tab is replaced with 3 spaces -# instead of being stripped entirely. The code snippet itself would then have -# inconsistent indentation to the point of being invalid Python, and thus code -# formatting would be skipped. -# -# I decided on the former behavior because it seems a bit easier to implement, -# but we might want to switch to the alternative if cases like this show up in -# the real world. ---AG -def rst_literal_odd_indentation(): - """ - Do cool stuff:: - cool_stuff( 1 ) - cool_stuff( 2 ) +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. - Done. - """ - pass + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard + ... ) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) -# Tests that having a line with a lone `::` works as an introduction of a -# literal block. -def rst_literal_lone_colon(): - """ - Do cool stuff. - :: +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. - cool_stuff( 1 ) + >>> cool-stuff( x ): + 2 + """ + pass - Done. - """ - pass +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. -def rst_directive_simple(): - """ - .. code-block:: python + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass - cool_stuff( 1 ) - Done. - """ - pass +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass -def rst_directive_case_insensitive(): - """ - .. cOdE-bLoCk:: python - cool_stuff( 1 ) +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. - Done. - """ - pass + >>> def cool_stuff(x): + ... print(x) + ... print( f"hi {x}" ); + hi 2 + """ + pass -def rst_directive_sourcecode(): - """ - .. sourcecode:: python +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. - cool_stuff( 1 ) + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass - Done. - """ - pass +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass -def rst_directive_options(): - """ - .. code-block:: python - :linenos: - :emphasize-lines: 2,3 - :name: blah blah - cool_stuff( 1 ) - cool_stuff( 2 ) - cool_stuff( 3 ) - cool_stuff( 4 ) +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. - Done. - """ - pass + >>> cool_stuff( 1 ) + 2 + """ + pass -# In this case, since `pycon` isn't recognized as a Python code snippet, the -# docstring reformatter ignores it. But it then picks up the doctest and -# reformats it. -def rst_directive_doctest(): - """ - .. code-block:: pycon +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. - >>> cool_stuff( 1 ) + >>> x = '\"\"\"' + """ + pass - Done. - """ - pass +############################################################################### +# reStructuredText CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# reStructuredText formatted code blocks. +# +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +############################################################################### -# This checks that if the first non-empty line after the start of a literal -# block is not indented more than the line containing the `::`, then it is not -# treated as a code snippet. -def rst_literal_skipped_first_line_not_indented(): - """ - Do cool stuff:: - cool_stuff( 1 ) +def rst_literal_simple(): + """ + Do cool stuff:: - Done. - """ - pass + cool_stuff(1) + Done. + """ + pass -# Like the test above, but inserts an indented line after the un-indented one. -# This should not cause the literal block to be resumed. -def rst_literal_skipped_first_line_not_indented_then_indented(): - """ - Do cool stuff:: - cool_stuff( 1 ) - cool_stuff( 2 ) +def rst_literal_simple_continued(): + """ + Do cool stuff:: - Done. - """ - pass + def cool_stuff(x): + print(f"hi {x}") + Done. + """ + pass -# This also checks that a code snippet is not reformatted when the indentation -# of the first line is not more than the line with `::`, but this uses tabs to -# make it a little more confounding. It relies on the fact that indentation -# length is computed by assuming a tabwidth equal to 8. reST also rejects this -# and doesn't treat it as a literal block. -def rst_literal_skipped_first_line_not_indented_tab(): - """ - Do cool stuff:: - cool_stuff( 1 ) +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: - Done. - """ - pass + cool_stuff(1) + """ + pass -# Like the previous test, but adds a second line. -def rst_literal_skipped_first_line_not_indented_tab_multiple(): - """ - Do cool stuff:: +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: - cool_stuff( 1 ) - cool_stuff( 2 ) + cool_stuff(1)""" + pass - Done. - """ - pass +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: -# Tests that a code block with a second line that is not properly indented gets -# skipped. A valid code block needs to have an empty line separating these. -# -# One trick here is that we need to make sure the Python code in the snippet is -# valid, otherwise it would be skipped because of invalid Python. -def rst_literal_skipped_subsequent_line_not_indented(): - """ - Do cool stuff:: + def cool_stuff(x): + print(f"hi {x}") - if True: - cool_stuff( ''' - hiya''' ) - Done. - """ - pass + def other_stuff(y): + print(y) + Done. + """ + pass -# In this test, we write what looks like a code-block, but it should be treated -# as invalid due to the missing `language` argument. -# -# It does still look like it could be a literal block according to the literal -# rules, but we currently consider the `.. ` prefix to indicate that it is not -# a literal block. -def rst_literal_skipped_not_directive(): - """ - .. code-block:: - cool_stuff( 1 ) +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: - Done. - """ - pass -# In this test, we start a line with `.. `, which makes it look like it might -# be a directive. But instead continue it as if it was just some periods from -# the previous line, and then try to end it by starting a literal block. -# -# But because of the `.. ` in the beginning, we wind up not treating this as a -# code snippet. The reST render I was using to test things does actually treat -# this as a code block, so we may be out of conformance here. -def rst_literal_skipped_possible_false_negative(): - """ - This is a test. - .. This is a test:: + cool_stuff(1) - cool_stuff( 1 ) - Done. - """ - pass + Done. + """ + pass -# This tests that a doctest inside of a reST literal block doesn't get -# reformatted. It's plausible this isn't the right behavior, but it also seems -# like it might be the right behavior since it is a literal block. (The doctest -# makes the Python code invalid.) -def rst_literal_skipped_doctest(): - """ - Do cool stuff:: - >>> cool_stuff( 1 ) +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: - Done. - """ - pass + cool_stuff(1) -def rst_directive_skipped_not_indented(): - """ - .. code-block:: python - cool_stuff( 1 ) - Done. - """ - pass + """ + pass -def rst_directive_skipped_wrong_language(): - """ - .. code-block:: rust +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: - cool_stuff( 1 ) + cool_stuff(1) - Done. - """ - pass + cool_stuff(2) -# This gets skipped for the same reason that the doctest in a literal block -# gets skipped. -def rst_directive_skipped_doctest(): - """ - .. code-block:: python + Done. + """ + pass - >>> cool_stuff( 1 ) - Done. - """ - pass -``` +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + if True: + cool_stuff( + ''' + hiya''' + ) -### Output 5 -``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Enabled -preview = Disabled -``` + Done. + """ + pass -```python -############################################################################### -# DOCTEST CODE EXAMPLES -# -# This section shows examples of docstrings that contain code snippets in -# Python's "doctest" format. + +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. # -# See: https://docs.python.org/3/library/doctest.html -############################################################################### +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff:: -# The simplest doctest to ensure basic formatting works. -def doctest_simple(): - """ - Do cool stuff. + cool_stuff(1) - >>> cool_stuff(1) - 2 - """ - pass + Done. + """ + pass -# Another simple test, but one where the Python code -# extends over multiple lines. -def doctest_simple_continued(): - """ - Do cool stuff. +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff:: - >>> def cool_stuff(x): - ... print(f"hi {x}") - hi 2 - """ - pass + cool_stuff(1) + cool_stuff(2) + Done. + """ + pass -# Test that we support multiple directly adjacent -# doctests. -def doctest_adjacent(): - """ - Do cool stuff. - >>> cool_stuff(x) - >>> cool_stuff(y) - 2 - """ - pass +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + cool_stuff(1) -# Test that a doctest on the last non-whitespace line of a docstring -# reformats correctly. -def doctest_last_line(): - """ - Do cool stuff. + Done. + """ + pass - >>> cool_stuff(x) - """ - pass +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: -# Test that a doctest that continues to the last non-whitespace line of -# a docstring reformats correctly. -def doctest_last_line_continued(): - """ - Do cool stuff. + cool_stuff(1) + cool_stuff(2) - >>> def cool_stuff(x): - ... print(f"hi {x}") - """ - pass + Done. + """ + pass -# Test that a doctest on the real last line of a docstring reformats -# correctly. -def doctest_really_last_line(): - """ - Do cool stuff. +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): + """ + Do cool stuff:: - >>> cool_stuff(x)""" - pass + cool_stuff(1) + cool_stuff(2) + Done. + """ + pass + + +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. +# +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: -# Test that a continued doctest on the real last line of a docstring reformats -# correctly. -def doctest_really_last_line_continued(): - """ - Do cool stuff. + cool_stuff(1) + cool_stuff(2) - >>> cool_stuff(x) - ... more(y)""" - pass + Done. + """ + pass -# Test that a doctest is correctly identified and formatted with a blank -# continuation line. -def doctest_blank_continued(): - """ - Do cool stuff. +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ + Do cool stuff. - >>> def cool_stuff(x): - ... print(x) - ... - ... print(x) - """ - pass + :: + cool_stuff(1) -# Tests that a blank PS2 line at the end of a doctest can get dropped. -# It is treated as part of the Python snippet which will trim the -# trailing whitespace. -def doctest_blank_end(): - """ - Do cool stuff. + Done. + """ + pass - >>> def cool_stuff(x): - ... print(x) - ... print(x) - """ - pass +def rst_directive_simple(): + """ + .. code-block:: python -# Tests that a blank PS2 line at the end of a doctest can get dropped -# even when there is text following it. -def doctest_blank_end_then_some_text(): - """ - Do cool stuff. + cool_stuff(1) - >>> def cool_stuff(x): - ... print(x) - ... print(x) + Done. + """ + pass - And say something else. - """ - pass +def rst_directive_case_insensitive(): + """ + .. cOdE-bLoCk:: python -# Test that a doctest containing a triple quoted string gets formatted -# correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): - """ - Do cool stuff. + cool_stuff(1) - >>> x = '''tricksy''' - """ - pass + Done. + """ + pass -# Test that a doctest containing a triple quoted f-string gets -# formatted correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): - """ - Do cool stuff. +def rst_directive_sourcecode(): + """ + .. sourcecode:: python - >>> x = f'''tricksy''' - """ - pass + cool_stuff(1) + Done. + """ + pass -# Another nested multi-line string case, but with triple escaped double -# quotes inside a triple single quoted string. -def doctest_with_triple_escaped_double(): - """ - Do cool stuff. - >>> x = '''\"\"\"''' - """ - pass +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + cool_stuff(1) + cool_stuff(2) + cool_stuff(3) + cool_stuff(4) -# Tests that inverting the triple quoting works as expected. -def doctest_with_triple_inverted(): - ''' - Do cool stuff. + Done. + """ + pass - >>> x = """tricksy""" - ''' - pass +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon -# Tests that inverting the triple quoting with an f-string works as -# expected. -def doctest_with_triple_inverted_fstring(): - ''' - Do cool stuff. + >>> cool_stuff(1) - >>> x = f"""tricksy""" - ''' - pass + Done. + """ + pass -# Tests nested doctests are ignored. That is, we don't format doctests -# recursively. We only recognize "top level" doctests. -# -# This restriction primarily exists to avoid needing to deal with -# nesting quotes. It also seems like a generally sensible restriction, -# although it could be lifted if necessary I believe. -def doctest_nested_doctest_not_formatted(): - ''' - Do cool stuff. +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: - >>> def nested(x): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass - ''' - pass + cool_stuff( 1 ) + Done. + """ + pass -# Tests that the starting column does not matter. -def doctest_varying_start_column(): - """ - Do cool stuff. - >>> assert "Easy!" - >>> import math - >>> math.floor(1.9) - 1 - """ - pass +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): + """ + Do cool stuff:: + cool_stuff( 1 ) + cool_stuff( 2 ) -# Tests that long lines get wrapped... appropriately. -# -# The docstring code formatter uses the same line width settings as for -# formatting other code. This means that a line in the docstring can -# actually extend past the configured line limit. -# -# It's not quite clear whether this is desirable or not. We could in -# theory compute the intendation length of a code snippet and then -# adjust the line-width setting on a recursive call to the formatter. -# But there are assuredly pathological cases to consider. Another path -# would be to expose another formatter option for controlling the -# line-width of code snippets independently. -def doctest_long_lines(): - """ - Do cool stuff. + Done. + """ + pass - This won't get wrapped even though it exceeds our configured - line width because it doesn't exceed the line width within this - docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) - But this one is long enough to get wrapped. - >>> foo, bar, quux = this_is_a_long_line( - ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard - ... ) - """ - # This demostrates a normal line that will get wrapped but won't - # get wrapped in the docstring above because of how the line-width - # setting gets reset at the first column in each code snippet. - foo, bar, quux = this_is_a_long_line( - lion, giraffe, hippo, zeba, lemur, penguin, monkey - ) +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: + cool_stuff( 1 ) -# Checks that a simple but invalid doctest gets skipped. -def doctest_skipped_simple(): - """ - Do cool stuff. + Done. + """ + pass - >>> cool-stuff( x ): - 2 - """ - pass +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: -# Checks that a simple doctest that is continued over multiple lines, -# but is invalid, gets skipped. -def doctest_skipped_simple_continued(): - """ - Do cool stuff. + cool_stuff( 1 ) + cool_stuff( 2 ) - >>> def cool-stuff( x ): - ... print( f"hi {x}" ); - 2 - """ - pass + Done. + """ + pass -# Checks that a doctest with improper indentation gets skipped. -def doctest_skipped_inconsistent_indent(): - """ - Do cool stuff. +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. +# +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass + if True: + cool_stuff( ''' + hiya''' ) + Done. + """ + pass -# Checks that a doctest with some proper indentation and some improper -# indentation is "partially" formatted. That is, the part that appears -# before the inconsistent indentation is formatted. This requires that -# the part before it is valid Python. -def doctest_skipped_partial_inconsistent_indent(): - """ - Do cool stuff. - >>> def cool_stuff(x): - ... print(x) - ... print( f"hi {x}" ); - hi 2 - """ - pass +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: + cool_stuff( 1 ) -# Checks that a doctest with improper triple single quoted string gets -# skipped. That is, the code snippet is itself invalid Python, so it is -# left as is. -def doctest_skipped_triple_incorrect(): - """ - Do cool stuff. + Done. + """ + pass - >>> foo( x ) - ... '''tri'''cksy''' - """ - pass +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: -# Tests that a doctest on a single line is skipped. -def doctest_skipped_one_line(): - ">>> foo( x )" - pass + cool_stuff( 1 ) + Done. + """ + pass -# f-strings are not considered docstrings[1], so any doctests -# inside of them should not be formatted. -# -# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals -def doctest_skipped_fstring(): - f""" - Do cool stuff. - >>> cool_stuff( 1 ) - 2 - """ - pass +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: + >>> cool_stuff( 1 ) -# Test that a doctest containing a triple quoted string at least -# does not result in invalid Python code. Ideally this would format -# correctly, but at time of writing it does not. -def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): - """ - Do cool stuff. + Done. + """ + pass - >>> x = '\"\"\"' - """ - pass +def rst_literal_skipped_markdown(): + """ + Do cool stuff:: -############################################################################### -# reStructuredText CODE EXAMPLES -# -# This section shows examples of docstrings that contain code snippets in -# reStructuredText formatted code blocks. -# -# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks -# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 -############################################################################### + ```py + cool_stuff( 1 ) + ``` + Done. + """ + pass -def rst_literal_simple(): - """ - Do cool stuff:: - cool_stuff(1) +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python - Done. - """ - pass + cool_stuff( 1 ) + Done. + """ + pass -def rst_literal_simple_continued(): - """ - Do cool stuff:: - def cool_stuff(x): - print(f"hi {x}") +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust - Done. - """ - pass + cool_stuff( 1 ) + Done. + """ + pass -# Tests that we can end the literal block on the second -# to last line of the docstring. -def rst_literal_second_to_last(): - """ - Do cool stuff:: - cool_stuff(1) - """ - pass +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python + >>> cool_stuff( 1 ) -# Tests that we can end the literal block on the actual -# last line of the docstring. -def rst_literal_actually_last(): - """ - Do cool stuff:: + Done. + """ + pass - cool_stuff(1)""" - pass + +############################################################################### +# Markdown CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Markdown fenced code blocks. +# +# See: https://spec.commonmark.org/0.30/#fenced-code-blocks +############################################################################### -def rst_literal_with_blank_lines(): - """ - Do cool stuff:: +def markdown_simple(): + """ + Do cool stuff. - def cool_stuff(x): - print(f"hi {x}") + ```py + cool_stuff(1) + ``` + Done. + """ + pass - def other_stuff(y): - print(y) - Done. - """ - pass +def markdown_simple_continued(): + """ + Do cool stuff. + ```python + def cool_stuff(x): + print(f"hi {x}") + ``` -# Extra blanks should be preserved. -def rst_literal_extra_blanks(): - """ - Do cool stuff:: + Done. + """ + pass +# Tests that unlabeled Markdown fenced code blocks are assumed to be Python. +def markdown_unlabeled(): + """ + Do cool stuff. - cool_stuff(1) + ``` + cool_stuff(1) + ``` + Done. + """ + pass - Done. - """ - pass +# Tests that fenced code blocks using tildes work. +def markdown_tildes(): + """ + Do cool stuff. + ~~~py + cool_stuff(1) + ~~~ -# If a literal block is never properly ended (via a non-empty unindented line), -# then the end of the block should be the last non-empty line. And subsequent -# empty lines should be preserved as-is. -def rst_literal_extra_blanks_at_end(): - """ - Do cool stuff:: + Done. + """ + pass - cool_stuff(1) +# Tests that a longer closing fence is just fine and dandy. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + ```py + cool_stuff(1) + `````` + Done. + """ + pass - """ - pass +# Tests that an invalid closing fence is treated as invalid. +# +# We embed it into a docstring so that the surrounding Python +# remains valid. +def markdown_longer_closing_fence(): + """ + Do cool stuff. -# A literal block can contain many empty lines and it should not end the block -# if it continues. -def rst_literal_extra_blanks_in_snippet(): - """ - Do cool stuff:: + ```py + cool_stuff(1) + ''' + ```invalid + ''' + cool_stuff(2) + ``` - cool_stuff(1) + Done. + """ + pass - cool_stuff(2) +# Tests that one can nest fenced code blocks by using different numbers of +# backticks. +def markdown_nested_fences(): + """ + Do cool stuff. - Done. - """ - pass + `````` + do_something( + ''' + ``` + did i trick you? + ``` + ''' + ) + `````` + Done. + """ + pass -# This tests that a unindented line appearing after an indented line (but where -# the indent is still beyond the minimum) gets formatted properly. -def rst_literal_subsequent_line_not_indented(): - """ - Do cool stuff:: - if True: - cool_stuff( - ''' - hiya''' - ) +# Tests that an unclosed block gobbles up everything remaining in the +# docstring. When it's only empty lines, those are passed into the formatter +# and thus stripped. +def markdown_unclosed_empty_lines(): + """ + Do cool stuff. - Done. - """ - pass + ```py + cool_stuff(1)""" + pass -# This checks that if the first line in a code snippet has been indented with -# tabs, then so long as its "indentation length" is considered bigger than the -# line with `::`, it is reformatted as code. -# -# (If your tabwidth is set to 4, then it looks like the code snippet -# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST -# itself also seems to recognize this as a code block, although it appears -# under-specified.) -def rst_literal_first_line_indent_uses_tabs_4spaces(): - """ - Do cool stuff:: +# Tests that we can end the block on the second to last line of the +# docstring. +def markdown_second_to_last(): + """ + Do cool stuff. - cool_stuff(1) + ```py + cool_stuff(1) + ``` + """ + pass - Done. - """ - pass +# Tests that an unclosed block with one extra line at the end is treated +# correctly. As per the CommonMark spec, an unclosed fenced code block contains +# everything following the opening fences. Since formatting the code snippet +# trims lines, the last empty line is removed here. +def markdown_second_to_last(): + """ + Do cool stuff. -# Like the test above, but with multiple lines. -def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): - """ - Do cool stuff:: + ```py + cool_stuff(1)""" + pass - cool_stuff(1) - cool_stuff(2) - Done. - """ - pass +# Tests that we can end the block on the actual last line of the docstring. +def markdown_actually_last(): + """ + Do cool stuff. + ```py + cool_stuff(1) + ```""" + pass -# Another test with tabs, except in this case, if your tabwidth is less than -# 8, than the code snippet actually looks like its indent is *less* than the -# opening line with a `::`. One might presume this means that the code snippet -# is not treated as a literal block and thus not reformatted, but since we -# assume all tabs have tabwidth=8 when computing indentation length, the code -# snippet is actually seen as being more indented than the opening `::` line. -# As with the above example, reST seems to behave the same way here. -def rst_literal_first_line_indent_uses_tabs_8spaces(): - """ - Do cool stuff:: - cool_stuff(1) +# Tests that an unclosed block that ends on the last line of a docstring +# is handled correctly. +def markdown_unclosed_actually_last(): + """ + Do cool stuff. - Done. - """ - pass + ```py + cool_stuff(1)""" + pass -# Like the test above, but with multiple lines. -def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): - """ - Do cool stuff:: +def markdown_with_blank_lines(): + """ + Do cool stuff. - cool_stuff(1) - cool_stuff(2) + ```py + def cool_stuff(x): + print(f"hi {x}") - Done. - """ - pass + def other_stuff(y): + print(y) + ``` -# Tests that if two lines in a literal block are indented to the same level -# but by different means (tabs versus spaces), then we correctly recognize the -# block and format it. -def rst_literal_first_line_tab_second_line_spaces(): - """ - Do cool stuff:: + Done. + """ + pass - cool_stuff(1) - cool_stuff(2) - Done. - """ - pass +def markdown_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff. + ```py + cool_stuff(1) + ``` -# Tests that when two lines in a code snippet have weird and inconsistent -# indentation, the code still gets formatted so long as the indent is greater -# than the indent of the `::` line. -# -# In this case, the minimum indent is 5 spaces (from the second line) where as -# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). -# The minimum indent is stripped from each code line. Since tabs aren't -# divisible, the entire tab is stripped, which means the first and second lines -# wind up with the same level of indentation. -# -# An alternative behavior here would be that the tab is replaced with 3 spaces -# instead of being stripped entirely. The code snippet itself would then have -# inconsistent indentation to the point of being invalid Python, and thus code -# formatting would be skipped. -# -# I decided on the former behavior because it seems a bit easier to implement, -# but we might want to switch to the alternative if cases like this show up in -# the real world. ---AG -def rst_literal_odd_indentation(): - """ - Do cool stuff:: + Done. + """ + pass - cool_stuff(1) - cool_stuff(2) - Done. - """ - pass +def markdown_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff. + ```py + cool_stuff(1) + cool_stuff(2) + ``` -# Tests that having a line with a lone `::` works as an introduction of a -# literal block. -def rst_literal_lone_colon(): - """ - Do cool stuff. + Done. + """ + pass - :: - cool_stuff(1) +def markdown_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff. - Done. - """ - pass + ```py + cool_stuff(1) + ``` + Done. + """ + pass -def rst_directive_simple(): - """ - .. code-block:: python - cool_stuff(1) +def markdown_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff. - Done. - """ - pass + ```py + cool_stuff(1) + cool_stuff(2) + ``` + Done. + """ + pass -def rst_directive_case_insensitive(): - """ - .. cOdE-bLoCk:: python - cool_stuff(1) +def markdown_first_line_tab_second_line_spaces(): + """ + Do cool stuff. - Done. - """ - pass + ```py + cool_stuff(1) + cool_stuff(2) + ``` + Done. + """ + pass -def rst_directive_sourcecode(): - """ - .. sourcecode:: python - cool_stuff(1) +def markdown_odd_indentation(): + """ + Do cool stuff. - Done. - """ - pass + ```py + cool_stuff(1) + cool_stuff(2) + ``` + Done. + """ + pass -def rst_directive_options(): - """ - .. code-block:: python - :linenos: - :emphasize-lines: 2,3 - :name: blah blah - cool_stuff(1) - cool_stuff(2) - cool_stuff(3) - cool_stuff(4) +# Extra blanks should be *not* be preserved (unlike reST) because they are part +# of the code snippet (per CommonMark spec), and thus get trimmed as part of +# code formatting. +def markdown_extra_blanks(): + """ + Do cool stuff. - Done. - """ - pass + ```py + cool_stuff(1) + ``` + Done. + """ + pass -# In this case, since `pycon` isn't recognized as a Python code snippet, the -# docstring reformatter ignores it. But it then picks up the doctest and -# reformats it. -def rst_directive_doctest(): - """ - .. code-block:: pycon - >>> cool_stuff(1) +# A block can contain many empty lines within it. +def markdown_extra_blanks_in_snippet(): + """ + Do cool stuff. - Done. - """ - pass + ```py + cool_stuff(1) -# This checks that if the first non-empty line after the start of a literal -# block is not indented more than the line containing the `::`, then it is not -# treated as a code snippet. -def rst_literal_skipped_first_line_not_indented(): - """ - Do cool stuff:: + cool_stuff(2) + ``` - cool_stuff( 1 ) + Done. + """ + pass - Done. - """ - pass +def markdown_weird_closing(): + """ + Code block with weirdly placed closing fences. -# Like the test above, but inserts an indented line after the un-indented one. -# This should not cause the literal block to be resumed. -def rst_literal_skipped_first_line_not_indented_then_indented(): - """ - Do cool stuff:: + ```python + cool_stuff(1) + ``` + # The above fences look like it shouldn't close the block, but we + # allow it to. The fences below re-open a block (until the end of + # the docstring), but it's invalid Python and thus doesn't get + # reformatted. + a = 10 + ``` - cool_stuff( 1 ) - cool_stuff( 2 ) + Now the code block is closed + """ + pass - Done. - """ - pass +def markdown_over_indented(): + """ + A docstring + over intended + ```python + print(5) + ``` + """ + pass -# This also checks that a code snippet is not reformatted when the indentation -# of the first line is not more than the line with `::`, but this uses tabs to -# make it a little more confounding. It relies on the fact that indentation -# length is computed by assuming a tabwidth equal to 8. reST also rejects this -# and doesn't treat it as a literal block. -def rst_literal_skipped_first_line_not_indented_tab(): - """ - Do cool stuff:: - cool_stuff( 1 ) +# Tests that an unclosed block gobbles up everything remaining in the +# docstring, even if it isn't valid Python. Since it isn't valid Python, +# reformatting fails and the entire thing is skipped. +def markdown_skipped_unclosed_non_python(): + """ + Do cool stuff. - Done. - """ - pass + ```py + cool_stuff( 1 ) + I forgot to close the code block, and this is definitely not + Python. So nothing here gets formatted. + """ + pass -# Like the previous test, but adds a second line. -def rst_literal_skipped_first_line_not_indented_tab_multiple(): - """ - Do cool stuff:: - cool_stuff( 1 ) - cool_stuff( 2 ) +# This has a Python snippet with a docstring that contains a closing fence. +# This splits the embedded docstring and makes the overall snippet invalid. +def markdown_skipped_accidental_closure(): + """ + Do cool stuff. - Done. - """ - pass + ```py + cool_stuff( 1 ) + ''' + ``` + ''' + ``` + + Done. + """ + pass -# Tests that a code block with a second line that is not properly indented gets -# skipped. A valid code block needs to have an empty line separating these. +# When a line is unindented all the way out before the standard indent of the +# docstring, the code reformatting ends up interacting poorly with the standard +# docstring whitespace normalization logic. This is probably a bug, and we +# should probably treat the Markdown block as valid, but for now, we detect +# the unindented line and declare the block as invalid and thus do no code +# reformatting. # -# One trick here is that we need to make sure the Python code in the snippet is -# valid, otherwise it would be skipped because of invalid Python. -def rst_literal_skipped_subsequent_line_not_indented(): - """ - Do cool stuff:: +# FIXME: Fixing this (if we think it's a bug) probably requires refactoring the +# docstring whitespace normalization to be aware of code snippets. Or perhaps +# plausibly, to do normalization *after* code snippets have been formatted. +def markdown_skipped_unindented_completely(): + """ + Do cool stuff. - if True: - cool_stuff( ''' - hiya''' ) + ```py + cool_stuff( 1 ) + ``` - Done. - """ - pass + Done. + """ + pass -# In this test, we write what looks like a code-block, but it should be treated -# as invalid due to the missing `language` argument. -# -# It does still look like it could be a literal block according to the literal -# rules, but we currently consider the `.. ` prefix to indicate that it is not -# a literal block. -def rst_literal_skipped_not_directive(): - """ - .. code-block:: +# This test is fallout from treating fenced code blocks with unindented lines +# as invalid. We probably should treat this as a valid block. Indeed, if we +# remove the logic that makes the `markdown_skipped_unindented_completely` test +# pass, then this code snippet will get reformatted correctly. +def markdown_skipped_unindented_somewhat(): + """ + Do cool stuff. - cool_stuff( 1 ) + ```py + cool_stuff( 1 ) + ``` - Done. - """ - pass + Done. + """ + pass -# In this test, we start a line with `.. `, which makes it look like it might -# be a directive. But instead continue it as if it was just some periods from -# the previous line, and then try to end it by starting a literal block. +# This tests that if a Markdown block contains a line that has less of an +# indent than another line. # -# But because of the `.. ` in the beginning, we wind up not treating this as a -# code snippet. The reST render I was using to test things does actually treat -# this as a code block, so we may be out of conformance here. -def rst_literal_skipped_possible_false_negative(): - """ - This is a test. - .. This is a test:: +# There is some judgment involved in what the right behavior is here. We +# could "normalize" the indentation so that the minimum is the indent of the +# opening fence line. If we did that here, then the code snippet would become +# valid and format as Python. But at time of writing, we don't, which leads to +# inconsistent indentation and thus invalid Python. +def markdown_skipped_unindented_with_inconsistent_indentation(): + """ + Do cool stuff. - cool_stuff( 1 ) + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` - Done. - """ - pass + Done. + """ + pass -# This tests that a doctest inside of a reST literal block doesn't get -# reformatted. It's plausible this isn't the right behavior, but it also seems -# like it might be the right behavior since it is a literal block. (The doctest -# makes the Python code invalid.) -def rst_literal_skipped_doctest(): - """ - Do cool stuff:: +def markdown_skipped_doctest(): + """ + Do cool stuff. - >>> cool_stuff( 1 ) + ```py + >>> cool_stuff( 1 ) + ``` - Done. - """ - pass + Done. + """ + pass -def rst_directive_skipped_not_indented(): - """ - .. code-block:: python +def markdown_skipped_rst_literal(): + """ + Do cool stuff. - cool_stuff( 1 ) + ```py + And do this:: - Done. - """ - pass + cool_stuff( 1 ) + ``` -def rst_directive_skipped_wrong_language(): - """ - .. code-block:: rust + Done. + """ + pass - cool_stuff( 1 ) - Done. - """ - pass +def markdown_skipped_rst_directive(): + """ + Do cool stuff. + ```py + .. code-block:: python -# This gets skipped for the same reason that the doctest in a literal block -# gets skipped. -def rst_directive_skipped_doctest(): - """ - .. code-block:: python + cool_stuff( 1 ) - >>> cool_stuff( 1 ) + ``` - Done. - """ - pass + Done. + """ + pass ``` -### Output 6 +### Output 7 ``` -indent-style = space +indent-style = tab line-width = 88 -indent-width = 2 +indent-width = 8 quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect @@ -5109,180 +9487,180 @@ preview = Disabled # The simplest doctest to ensure basic formatting works. def doctest_simple(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff(1) - 2 - """ - pass + >>> cool_stuff(1) + 2 + """ + pass # Another simple test, but one where the Python code # extends over multiple lines. def doctest_simple_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff(x): - ... print(f"hi {x}") - hi 2 - """ - pass + >>> def cool_stuff(x): + ... print(f"hi {x}") + hi 2 + """ + pass # Test that we support multiple directly adjacent # doctests. def doctest_adjacent(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff(x) - >>> cool_stuff(y) - 2 - """ - pass + >>> cool_stuff(x) + >>> cool_stuff(y) + 2 + """ + pass # Test that a doctest on the last non-whitespace line of a docstring # reformats correctly. def doctest_last_line(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff(x) - """ - pass + >>> cool_stuff(x) + """ + pass # Test that a doctest that continues to the last non-whitespace line of # a docstring reformats correctly. def doctest_last_line_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff(x): - ... print(f"hi {x}") - """ - pass + >>> def cool_stuff(x): + ... print(f"hi {x}") + """ + pass # Test that a doctest on the real last line of a docstring reformats # correctly. def doctest_really_last_line(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff(x)""" - pass + >>> cool_stuff(x)""" + pass # Test that a continued doctest on the real last line of a docstring reformats # correctly. def doctest_really_last_line_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool_stuff(x) - ... more(y)""" - pass + >>> cool_stuff(x) + ... more(y)""" + pass # Test that a doctest is correctly identified and formatted with a blank # continuation line. def doctest_blank_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff(x): - ... print(x) - ... - ... print(x) - """ - pass + >>> def cool_stuff(x): + ... print(x) + ... + ... print(x) + """ + pass # Tests that a blank PS2 line at the end of a doctest can get dropped. # It is treated as part of the Python snippet which will trim the # trailing whitespace. def doctest_blank_end(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff(x): - ... print(x) - ... print(x) - """ - pass + >>> def cool_stuff(x): + ... print(x) + ... print(x) + """ + pass # Tests that a blank PS2 line at the end of a doctest can get dropped # even when there is text following it. def doctest_blank_end_then_some_text(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff(x): - ... print(x) - ... print(x) + >>> def cool_stuff(x): + ... print(x) + ... print(x) - And say something else. - """ - pass + And say something else. + """ + pass # Test that a doctest containing a triple quoted string gets formatted # correctly and doesn't result in invalid syntax. def doctest_with_triple_single(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = '''tricksy''' - """ - pass + >>> x = '''tricksy''' + """ + pass # Test that a doctest containing a triple quoted f-string gets # formatted correctly and doesn't result in invalid syntax. def doctest_with_triple_single(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = f'''tricksy''' - """ - pass + >>> x = f'''tricksy''' + """ + pass # Another nested multi-line string case, but with triple escaped double # quotes inside a triple single quoted string. def doctest_with_triple_escaped_double(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = '''\"\"\"''' - """ - pass + >>> x = '''\"\"\"''' + """ + pass # Tests that inverting the triple quoting works as expected. def doctest_with_triple_inverted(): - ''' - Do cool stuff. + ''' + Do cool stuff. - >>> x = """tricksy""" - ''' - pass + >>> x = """tricksy""" + ''' + pass # Tests that inverting the triple quoting with an f-string works as # expected. def doctest_with_triple_inverted_fstring(): - ''' - Do cool stuff. + ''' + Do cool stuff. - >>> x = f"""tricksy""" - ''' - pass + >>> x = f"""tricksy""" + ''' + pass # Tests nested doctests are ignored. That is, we don't format doctests @@ -5292,30 +9670,30 @@ def doctest_with_triple_inverted_fstring(): # nesting quotes. It also seems like a generally sensible restriction, # although it could be lifted if necessary I believe. def doctest_nested_doctest_not_formatted(): - ''' - Do cool stuff. + ''' + Do cool stuff. - >>> def nested(x): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass - ''' - pass + >>> def nested(x): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass # Tests that the starting column does not matter. def doctest_varying_start_column(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> assert "Easy!" - >>> import math - >>> math.floor(1.9) - 1 - """ - pass + >>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1 + """ + pass # Tests that long lines get wrapped... appropriately. @@ -5331,61 +9709,61 @@ def doctest_varying_start_column(): # would be to expose another formatter option for controlling the # line-width of code snippets independently. def doctest_long_lines(): - """ - Do cool stuff. + """ + Do cool stuff. - This won't get wrapped even though it exceeds our configured - line width because it doesn't exceed the line width within this - docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) - But this one is long enough to get wrapped. - >>> foo, bar, quux = this_is_a_long_line( - ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard - ... ) - """ - # This demostrates a normal line that will get wrapped but won't - # get wrapped in the docstring above because of how the line-width - # setting gets reset at the first column in each code snippet. - foo, bar, quux = this_is_a_long_line( - lion, giraffe, hippo, zeba, lemur, penguin, monkey - ) + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard + ... ) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) # Checks that a simple but invalid doctest gets skipped. def doctest_skipped_simple(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> cool-stuff( x ): - 2 - """ - pass + >>> cool-stuff( x ): + 2 + """ + pass # Checks that a simple doctest that is continued over multiple lines, # but is invalid, gets skipped. def doctest_skipped_simple_continued(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool-stuff( x ): - ... print( f"hi {x}" ); - 2 - """ - pass + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass # Checks that a doctest with improper indentation gets skipped. def doctest_skipped_inconsistent_indent(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 - """ - pass + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass # Checks that a doctest with some proper indentation and some improper @@ -5393,34 +9771,34 @@ def doctest_skipped_inconsistent_indent(): # before the inconsistent indentation is formatted. This requires that # the part before it is valid Python. def doctest_skipped_partial_inconsistent_indent(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> def cool_stuff(x): - ... print(x) - ... print( f"hi {x}" ); - hi 2 - """ - pass + >>> def cool_stuff(x): + ... print(x) + ... print( f"hi {x}" ); + hi 2 + """ + pass # Checks that a doctest with improper triple single quoted string gets # skipped. That is, the code snippet is itself invalid Python, so it is # left as is. def doctest_skipped_triple_incorrect(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> foo( x ) - ... '''tri'''cksy''' - """ - pass + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass # Tests that a doctest on a single line is skipped. def doctest_skipped_one_line(): - ">>> foo( x )" - pass + ">>> foo( x )" + pass # f-strings are not considered docstrings[1], so any doctests @@ -5428,25 +9806,25 @@ def doctest_skipped_one_line(): # # [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals def doctest_skipped_fstring(): - f""" + f""" Do cool stuff. >>> cool_stuff( 1 ) 2 """ - pass + pass # Test that a doctest containing a triple quoted string at least # does not result in invalid Python code. Ideally this would format # correctly, but at time of writing it does not. def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): - """ - Do cool stuff. + """ + Do cool stuff. - >>> x = '\"\"\"' - """ - pass + >>> x = '\"\"\"' + """ + pass ############################################################################### @@ -5464,128 +9842,128 @@ def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): def rst_literal_simple(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff(1) + cool_stuff(1) - Done. - """ - pass + Done. + """ + pass def rst_literal_simple_continued(): - """ - Do cool stuff:: - - def cool_stuff(x): - print(f"hi {x}") + """ + Do cool stuff:: - Done. - """ - pass + def cool_stuff(x): + print(f"hi {x}") + + Done. + """ + pass # Tests that we can end the literal block on the second # to last line of the docstring. def rst_literal_second_to_last(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff(1) - """ - pass + cool_stuff(1) + """ + pass # Tests that we can end the literal block on the actual # last line of the docstring. def rst_literal_actually_last(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff(1)""" - pass + cool_stuff(1)""" + pass def rst_literal_with_blank_lines(): - """ - Do cool stuff:: + """ + Do cool stuff:: - def cool_stuff(x): - print(f"hi {x}") + def cool_stuff(x): + print(f"hi {x}") - def other_stuff(y): - print(y) + def other_stuff(y): + print(y) - Done. - """ - pass + Done. + """ + pass # Extra blanks should be preserved. def rst_literal_extra_blanks(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff(1) + cool_stuff(1) - Done. - """ - pass + Done. + """ + pass # If a literal block is never properly ended (via a non-empty unindented line), # then the end of the block should be the last non-empty line. And subsequent # empty lines should be preserved as-is. def rst_literal_extra_blanks_at_end(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff(1) + cool_stuff(1) - """ - pass + """ + pass # A literal block can contain many empty lines and it should not end the block # if it continues. def rst_literal_extra_blanks_in_snippet(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff(1) + cool_stuff(1) - cool_stuff(2) + cool_stuff(2) - Done. - """ - pass + Done. + """ + pass # This tests that a unindented line appearing after an indented line (but where # the indent is still beyond the minimum) gets formatted properly. def rst_literal_subsequent_line_not_indented(): - """ - Do cool stuff:: + """ + Do cool stuff:: - if True: - cool_stuff( - ''' - hiya''' - ) + if True: + cool_stuff( + ''' + hiya''' + ) - Done. - """ - pass + Done. + """ + pass # This checks that if the first line in a code snippet has been indented with @@ -5597,27 +9975,27 @@ def rst_literal_subsequent_line_not_indented(): # itself also seems to recognize this as a code block, although it appears # under-specified.) def rst_literal_first_line_indent_uses_tabs_4spaces(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff(1) + cool_stuff(1) - Done. - """ - pass + Done. + """ + pass # Like the test above, but with multiple lines. def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff(1) - cool_stuff(2) + cool_stuff(1) + cool_stuff(2) - Done. - """ - pass + Done. + """ + pass # Another test with tabs, except in this case, if your tabwidth is less than @@ -5628,42 +10006,42 @@ def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): # snippet is actually seen as being more indented than the opening `::` line. # As with the above example, reST seems to behave the same way here. def rst_literal_first_line_indent_uses_tabs_8spaces(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff(1) + cool_stuff(1) - Done. - """ - pass + Done. + """ + pass # Like the test above, but with multiple lines. def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff(1) - cool_stuff(2) + cool_stuff(1) + cool_stuff(2) - Done. - """ - pass + Done. + """ + pass # Tests that if two lines in a literal block are indented to the same level # but by different means (tabs versus spaces), then we correctly recognize the # block and format it. def rst_literal_first_line_tab_second_line_spaces(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff(1) - cool_stuff(2) + cool_stuff(1) + cool_stuff(2) - Done. - """ - pass + Done. + """ + pass # Tests that when two lines in a code snippet have weird and inconsistent @@ -5685,122 +10063,122 @@ def rst_literal_first_line_tab_second_line_spaces(): # but we might want to switch to the alternative if cases like this show up in # the real world. ---AG def rst_literal_odd_indentation(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff(1) - cool_stuff(2) + cool_stuff(1) + cool_stuff(2) - Done. - """ - pass + Done. + """ + pass # Tests that having a line with a lone `::` works as an introduction of a # literal block. def rst_literal_lone_colon(): - """ - Do cool stuff. + """ + Do cool stuff. - :: + :: - cool_stuff(1) + cool_stuff(1) - Done. - """ - pass + Done. + """ + pass def rst_directive_simple(): - """ - .. code-block:: python + """ + .. code-block:: python - cool_stuff(1) + cool_stuff(1) - Done. - """ - pass + Done. + """ + pass def rst_directive_case_insensitive(): - """ - .. cOdE-bLoCk:: python + """ + .. cOdE-bLoCk:: python - cool_stuff(1) + cool_stuff(1) - Done. - """ - pass + Done. + """ + pass def rst_directive_sourcecode(): - """ - .. sourcecode:: python + """ + .. sourcecode:: python - cool_stuff(1) + cool_stuff(1) - Done. - """ - pass + Done. + """ + pass def rst_directive_options(): - """ - .. code-block:: python - :linenos: - :emphasize-lines: 2,3 - :name: blah blah + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah - cool_stuff(1) - cool_stuff(2) - cool_stuff(3) - cool_stuff(4) + cool_stuff(1) + cool_stuff(2) + cool_stuff(3) + cool_stuff(4) - Done. - """ - pass + Done. + """ + pass # In this case, since `pycon` isn't recognized as a Python code snippet, the # docstring reformatter ignores it. But it then picks up the doctest and # reformats it. def rst_directive_doctest(): - """ - .. code-block:: pycon + """ + .. code-block:: pycon - >>> cool_stuff(1) + >>> cool_stuff(1) - Done. - """ - pass + Done. + """ + pass # This checks that if the first non-empty line after the start of a literal # block is not indented more than the line containing the `::`, then it is not # treated as a code snippet. def rst_literal_skipped_first_line_not_indented(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) + cool_stuff( 1 ) - Done. - """ - pass + Done. + """ + pass # Like the test above, but inserts an indented line after the un-indented one. # This should not cause the literal block to be resumed. def rst_literal_skipped_first_line_not_indented_then_indented(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) - cool_stuff( 2 ) + cool_stuff( 1 ) + cool_stuff( 2 ) - Done. - """ - pass + Done. + """ + pass # This also checks that a code snippet is not reformatted when the indentation @@ -5809,27 +10187,27 @@ def rst_literal_skipped_first_line_not_indented_then_indented(): # length is computed by assuming a tabwidth equal to 8. reST also rejects this # and doesn't treat it as a literal block. def rst_literal_skipped_first_line_not_indented_tab(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) + cool_stuff( 1 ) - Done. - """ - pass + Done. + """ + pass # Like the previous test, but adds a second line. def rst_literal_skipped_first_line_not_indented_tab_multiple(): - """ - Do cool stuff:: + """ + Do cool stuff:: - cool_stuff( 1 ) - cool_stuff( 2 ) + cool_stuff( 1 ) + cool_stuff( 2 ) - Done. - """ - pass + Done. + """ + pass # Tests that a code block with a second line that is not properly indented gets @@ -5838,16 +10216,16 @@ def rst_literal_skipped_first_line_not_indented_tab_multiple(): # One trick here is that we need to make sure the Python code in the snippet is # valid, otherwise it would be skipped because of invalid Python. def rst_literal_skipped_subsequent_line_not_indented(): - """ - Do cool stuff:: + """ + Do cool stuff:: - if True: - cool_stuff( ''' - hiya''' ) + if True: + cool_stuff( ''' + hiya''' ) - Done. - """ - pass + Done. + """ + pass # In this test, we write what looks like a code-block, but it should be treated @@ -5857,14 +10235,14 @@ def rst_literal_skipped_subsequent_line_not_indented(): # rules, but we currently consider the `.. ` prefix to indicate that it is not # a literal block. def rst_literal_skipped_not_directive(): - """ - .. code-block:: + """ + .. code-block:: - cool_stuff( 1 ) + cool_stuff( 1 ) - Done. - """ - pass + Done. + """ + pass # In this test, we start a line with `.. `, which makes it look like it might @@ -5875,15 +10253,15 @@ def rst_literal_skipped_not_directive(): # code snippet. The reST render I was using to test things does actually treat # this as a code block, so we may be out of conformance here. def rst_literal_skipped_possible_false_negative(): - """ - This is a test. - .. This is a test:: + """ + This is a test. + .. This is a test:: - cool_stuff( 1 ) + cool_stuff( 1 ) - Done. - """ - pass + Done. + """ + pass # This tests that a doctest inside of a reST literal block doesn't get @@ -5891,1749 +10269,1893 @@ def rst_literal_skipped_possible_false_negative(): # like it might be the right behavior since it is a literal block. (The doctest # makes the Python code invalid.) def rst_literal_skipped_doctest(): - """ - Do cool stuff:: + """ + Do cool stuff:: - >>> cool_stuff( 1 ) + >>> cool_stuff( 1 ) - Done. - """ - pass + Done. + """ + pass + + +def rst_literal_skipped_markdown(): + """ + Do cool stuff:: + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass def rst_directive_skipped_not_indented(): - """ - .. code-block:: python + """ + .. code-block:: python - cool_stuff( 1 ) + cool_stuff( 1 ) - Done. - """ - pass + Done. + """ + pass def rst_directive_skipped_wrong_language(): - """ - .. code-block:: rust + """ + .. code-block:: rust - cool_stuff( 1 ) + cool_stuff( 1 ) - Done. - """ - pass + Done. + """ + pass # This gets skipped for the same reason that the doctest in a literal block # gets skipped. def rst_directive_skipped_doctest(): - """ - .. code-block:: python - - >>> cool_stuff( 1 ) + """ + .. code-block:: python - Done. - """ - pass -``` + >>> cool_stuff( 1 ) + Done. + """ + pass -### Output 7 -``` -indent-style = tab -line-width = 88 -indent-width = 8 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Enabled -preview = Disabled -``` -```python ############################################################################### -# DOCTEST CODE EXAMPLES +# Markdown CODE EXAMPLES # # This section shows examples of docstrings that contain code snippets in -# Python's "doctest" format. +# Markdown fenced code blocks. # -# See: https://docs.python.org/3/library/doctest.html +# See: https://spec.commonmark.org/0.30/#fenced-code-blocks ############################################################################### -# The simplest doctest to ensure basic formatting works. -def doctest_simple(): + +def markdown_simple(): """ Do cool stuff. - >>> cool_stuff(1) - 2 + ```py + cool_stuff(1) + ``` + + Done. """ pass -# Another simple test, but one where the Python code -# extends over multiple lines. -def doctest_simple_continued(): +def markdown_simple_continued(): """ Do cool stuff. - >>> def cool_stuff(x): - ... print(f"hi {x}") - hi 2 + ```python + def cool_stuff(x): + print(f"hi {x}") + ``` + + Done. """ pass -# Test that we support multiple directly adjacent -# doctests. -def doctest_adjacent(): +# Tests that unlabeled Markdown fenced code blocks are assumed to be Python. +def markdown_unlabeled(): """ Do cool stuff. - >>> cool_stuff(x) - >>> cool_stuff(y) - 2 + ``` + cool_stuff(1) + ``` + + Done. """ pass -# Test that a doctest on the last non-whitespace line of a docstring -# reformats correctly. -def doctest_last_line(): +# Tests that fenced code blocks using tildes work. +def markdown_tildes(): """ Do cool stuff. - >>> cool_stuff(x) + ~~~py + cool_stuff(1) + ~~~ + + Done. """ pass -# Test that a doctest that continues to the last non-whitespace line of -# a docstring reformats correctly. -def doctest_last_line_continued(): +# Tests that a longer closing fence is just fine and dandy. +def markdown_longer_closing_fence(): """ Do cool stuff. - >>> def cool_stuff(x): - ... print(f"hi {x}") + ```py + cool_stuff(1) + `````` + + Done. """ pass -# Test that a doctest on the real last line of a docstring reformats -# correctly. -def doctest_really_last_line(): +# Tests that an invalid closing fence is treated as invalid. +# +# We embed it into a docstring so that the surrounding Python +# remains valid. +def markdown_longer_closing_fence(): """ Do cool stuff. - >>> cool_stuff(x)""" + ```py + cool_stuff(1) + ''' + ```invalid + ''' + cool_stuff(2) + ``` + + Done. + """ pass -# Test that a continued doctest on the real last line of a docstring reformats -# correctly. -def doctest_really_last_line_continued(): +# Tests that one can nest fenced code blocks by using different numbers of +# backticks. +def markdown_nested_fences(): """ Do cool stuff. - >>> cool_stuff(x) - ... more(y)""" + `````` + do_something( + ''' + ``` + did i trick you? + ``` + ''' + ) + `````` + + Done. + """ pass -# Test that a doctest is correctly identified and formatted with a blank -# continuation line. -def doctest_blank_continued(): +# Tests that an unclosed block gobbles up everything remaining in the +# docstring. When it's only empty lines, those are passed into the formatter +# and thus stripped. +def markdown_unclosed_empty_lines(): """ Do cool stuff. - >>> def cool_stuff(x): - ... print(x) - ... - ... print(x) - """ + ```py + cool_stuff(1)""" pass -# Tests that a blank PS2 line at the end of a doctest can get dropped. -# It is treated as part of the Python snippet which will trim the -# trailing whitespace. -def doctest_blank_end(): +# Tests that we can end the block on the second to last line of the +# docstring. +def markdown_second_to_last(): """ Do cool stuff. - >>> def cool_stuff(x): - ... print(x) - ... print(x) + ```py + cool_stuff(1) + ``` """ pass -# Tests that a blank PS2 line at the end of a doctest can get dropped -# even when there is text following it. -def doctest_blank_end_then_some_text(): +# Tests that an unclosed block with one extra line at the end is treated +# correctly. As per the CommonMark spec, an unclosed fenced code block contains +# everything following the opening fences. Since formatting the code snippet +# trims lines, the last empty line is removed here. +def markdown_second_to_last(): """ Do cool stuff. - >>> def cool_stuff(x): - ... print(x) - ... print(x) + ```py + cool_stuff(1)""" + pass + - And say something else. +# Tests that we can end the block on the actual last line of the docstring. +def markdown_actually_last(): """ + Do cool stuff. + + ```py + cool_stuff(1) + ```""" pass -# Test that a doctest containing a triple quoted string gets formatted -# correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): +# Tests that an unclosed block that ends on the last line of a docstring +# is handled correctly. +def markdown_unclosed_actually_last(): """ Do cool stuff. - >>> x = '''tricksy''' - """ + ```py + cool_stuff(1)""" pass -# Test that a doctest containing a triple quoted f-string gets -# formatted correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): +def markdown_with_blank_lines(): """ Do cool stuff. - >>> x = f'''tricksy''' + ```py + def cool_stuff(x): + print(f"hi {x}") + + + def other_stuff(y): + print(y) + ``` + + Done. """ pass -# Another nested multi-line string case, but with triple escaped double -# quotes inside a triple single quoted string. -def doctest_with_triple_escaped_double(): +def markdown_first_line_indent_uses_tabs_4spaces(): """ Do cool stuff. - >>> x = '''\"\"\"''' + ```py + cool_stuff(1) + ``` + + Done. """ pass -# Tests that inverting the triple quoting works as expected. -def doctest_with_triple_inverted(): - ''' +def markdown_first_line_indent_uses_tabs_4spaces_multiple(): + """ Do cool stuff. - >>> x = """tricksy""" - ''' + ```py + cool_stuff(1) + cool_stuff(2) + ``` + + Done. + """ pass -# Tests that inverting the triple quoting with an f-string works as -# expected. -def doctest_with_triple_inverted_fstring(): - ''' +def markdown_first_line_indent_uses_tabs_8spaces(): + """ Do cool stuff. - >>> x = f"""tricksy""" - ''' + ```py + cool_stuff(1) + ``` + + Done. + """ pass -# Tests nested doctests are ignored. That is, we don't format doctests -# recursively. We only recognize "top level" doctests. -# -# This restriction primarily exists to avoid needing to deal with -# nesting quotes. It also seems like a generally sensible restriction, -# although it could be lifted if necessary I believe. -def doctest_nested_doctest_not_formatted(): - ''' +def markdown_first_line_indent_uses_tabs_8spaces_multiple(): + """ Do cool stuff. - >>> def nested(x): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass - ''' + ```py + cool_stuff(1) + cool_stuff(2) + ``` + + Done. + """ pass -# Tests that the starting column does not matter. -def doctest_varying_start_column(): +def markdown_first_line_tab_second_line_spaces(): """ Do cool stuff. - >>> assert "Easy!" - >>> import math - >>> math.floor(1.9) - 1 + ```py + cool_stuff(1) + cool_stuff(2) + ``` + + Done. """ pass -# Tests that long lines get wrapped... appropriately. -# -# The docstring code formatter uses the same line width settings as for -# formatting other code. This means that a line in the docstring can -# actually extend past the configured line limit. -# -# It's not quite clear whether this is desirable or not. We could in -# theory compute the intendation length of a code snippet and then -# adjust the line-width setting on a recursive call to the formatter. -# But there are assuredly pathological cases to consider. Another path -# would be to expose another formatter option for controlling the -# line-width of code snippets independently. -def doctest_long_lines(): +def markdown_odd_indentation(): """ Do cool stuff. - This won't get wrapped even though it exceeds our configured - line width because it doesn't exceed the line width within this - docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + ```py + cool_stuff(1) + cool_stuff(2) + ``` - But this one is long enough to get wrapped. - >>> foo, bar, quux = this_is_a_long_line( - ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard - ... ) + Done. """ - # This demostrates a normal line that will get wrapped but won't - # get wrapped in the docstring above because of how the line-width - # setting gets reset at the first column in each code snippet. - foo, bar, quux = this_is_a_long_line( - lion, giraffe, hippo, zeba, lemur, penguin, monkey - ) + pass -# Checks that a simple but invalid doctest gets skipped. -def doctest_skipped_simple(): +# Extra blanks should be *not* be preserved (unlike reST) because they are part +# of the code snippet (per CommonMark spec), and thus get trimmed as part of +# code formatting. +def markdown_extra_blanks(): """ Do cool stuff. - >>> cool-stuff( x ): - 2 + ```py + cool_stuff(1) + ``` + + Done. """ pass -# Checks that a simple doctest that is continued over multiple lines, -# but is invalid, gets skipped. -def doctest_skipped_simple_continued(): +# A block can contain many empty lines within it. +def markdown_extra_blanks_in_snippet(): """ Do cool stuff. - >>> def cool-stuff( x ): - ... print( f"hi {x}" ); - 2 + ```py + cool_stuff(1) + + + cool_stuff(2) + ``` + + Done. """ pass -# Checks that a doctest with improper indentation gets skipped. -def doctest_skipped_inconsistent_indent(): +def markdown_weird_closing(): """ - Do cool stuff. + Code block with weirdly placed closing fences. - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 + ```python + cool_stuff(1) + ``` + # The above fences look like it shouldn't close the block, but we + # allow it to. The fences below re-open a block (until the end of + # the docstring), but it's invalid Python and thus doesn't get + # reformatted. + a = 10 + ``` + + Now the code block is closed """ pass -# Checks that a doctest with some proper indentation and some improper -# indentation is "partially" formatted. That is, the part that appears -# before the inconsistent indentation is formatted. This requires that -# the part before it is valid Python. -def doctest_skipped_partial_inconsistent_indent(): +def markdown_over_indented(): """ - Do cool stuff. - - >>> def cool_stuff(x): - ... print(x) - ... print( f"hi {x}" ); - hi 2 + A docstring + over intended + ```python + print(5) + ``` """ pass -# Checks that a doctest with improper triple single quoted string gets -# skipped. That is, the code snippet is itself invalid Python, so it is -# left as is. -def doctest_skipped_triple_incorrect(): +# Tests that an unclosed block gobbles up everything remaining in the +# docstring, even if it isn't valid Python. Since it isn't valid Python, +# reformatting fails and the entire thing is skipped. +def markdown_skipped_unclosed_non_python(): """ Do cool stuff. - >>> foo( x ) - ... '''tri'''cksy''' + ```py + cool_stuff( 1 ) + + I forgot to close the code block, and this is definitely not + Python. So nothing here gets formatted. """ pass -# Tests that a doctest on a single line is skipped. -def doctest_skipped_one_line(): - ">>> foo( x )" +# This has a Python snippet with a docstring that contains a closing fence. +# This splits the embedded docstring and makes the overall snippet invalid. +def markdown_skipped_accidental_closure(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ''' + ``` + ''' + ``` + + Done. + """ pass -# f-strings are not considered docstrings[1], so any doctests -# inside of them should not be formatted. +# When a line is unindented all the way out before the standard indent of the +# docstring, the code reformatting ends up interacting poorly with the standard +# docstring whitespace normalization logic. This is probably a bug, and we +# should probably treat the Markdown block as valid, but for now, we detect +# the unindented line and declare the block as invalid and thus do no code +# reformatting. # -# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals -def doctest_skipped_fstring(): - f""" - Do cool stuff. +# FIXME: Fixing this (if we think it's a bug) probably requires refactoring the +# docstring whitespace normalization to be aware of code snippets. Or perhaps +# plausibly, to do normalization *after* code snippets have been formatted. +def markdown_skipped_unindented_completely(): + """ + Do cool stuff. - >>> cool_stuff( 1 ) - 2 - """ + ```py + cool_stuff( 1 ) + ``` + + Done. + """ pass -# Test that a doctest containing a triple quoted string at least -# does not result in invalid Python code. Ideally this would format -# correctly, but at time of writing it does not. -def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): +# This test is fallout from treating fenced code blocks with unindented lines +# as invalid. We probably should treat this as a valid block. Indeed, if we +# remove the logic that makes the `markdown_skipped_unindented_completely` test +# pass, then this code snippet will get reformatted correctly. +def markdown_skipped_unindented_somewhat(): """ Do cool stuff. - >>> x = '\"\"\"' + ```py + cool_stuff( 1 ) + ``` + + Done. """ pass -############################################################################### -# reStructuredText CODE EXAMPLES -# -# This section shows examples of docstrings that contain code snippets in -# reStructuredText formatted code blocks. +# This tests that if a Markdown block contains a line that has less of an +# indent than another line. # -# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks -# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 -############################################################################### - - -def rst_literal_simple(): +# There is some judgment involved in what the right behavior is here. We +# could "normalize" the indentation so that the minimum is the indent of the +# opening fence line. If we did that here, then the code snippet would become +# valid and format as Python. But at time of writing, we don't, which leads to +# inconsistent indentation and thus invalid Python. +def markdown_skipped_unindented_with_inconsistent_indentation(): """ - Do cool stuff:: + Do cool stuff. - cool_stuff(1) + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` Done. """ pass -def rst_literal_simple_continued(): +def markdown_skipped_doctest(): """ - Do cool stuff:: + Do cool stuff. - def cool_stuff(x): - print(f"hi {x}") + ```py + >>> cool_stuff( 1 ) + ``` Done. """ pass -# Tests that we can end the literal block on the second -# to last line of the docstring. -def rst_literal_second_to_last(): +def markdown_skipped_rst_literal(): """ - Do cool stuff:: + Do cool stuff. - cool_stuff(1) + ```py + And do this:: + + cool_stuff( 1 ) + + ``` + + Done. """ pass -# Tests that we can end the literal block on the actual -# last line of the docstring. -def rst_literal_actually_last(): +def markdown_skipped_rst_directive(): """ - Do cool stuff:: + Do cool stuff. - cool_stuff(1)""" - pass + ```py + .. code-block:: python + + cool_stuff( 1 ) + ``` -def rst_literal_with_blank_lines(): + Done. """ - Do cool stuff:: + pass +``` - def cool_stuff(x): - print(f"hi {x}") +### Output 8 +``` +indent-style = tab +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +preview = Disabled +``` - def other_stuff(y): - print(y) +```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### - Done. +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): """ - pass - + Do cool stuff. -# Extra blanks should be preserved. -def rst_literal_extra_blanks(): + >>> cool_stuff(1) + 2 """ - Do cool stuff:: - - - - cool_stuff(1) + pass +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. - Done. + >>> def cool_stuff(x): + ... print(f"hi {x}") + hi 2 """ pass -# If a literal block is never properly ended (via a non-empty unindented line), -# then the end of the block should be the last non-empty line. And subsequent -# empty lines should be preserved as-is. -def rst_literal_extra_blanks_at_end(): +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): """ - Do cool stuff:: - - - cool_stuff(1) - - + Do cool stuff. + >>> cool_stuff(x) + >>> cool_stuff(y) + 2 """ pass -# A literal block can contain many empty lines and it should not end the block -# if it continues. -def rst_literal_extra_blanks_in_snippet(): +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): """ - Do cool stuff:: - - cool_stuff(1) - - - cool_stuff(2) + Do cool stuff. - Done. + >>> cool_stuff(x) """ pass -# This tests that a unindented line appearing after an indented line (but where -# the indent is still beyond the minimum) gets formatted properly. -def rst_literal_subsequent_line_not_indented(): +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): """ - Do cool stuff:: - - if True: - cool_stuff( - ''' - hiya''' - ) + Do cool stuff. - Done. + >>> def cool_stuff(x): + ... print(f"hi {x}") """ pass -# This checks that if the first line in a code snippet has been indented with -# tabs, then so long as its "indentation length" is considered bigger than the -# line with `::`, it is reformatted as code. -# -# (If your tabwidth is set to 4, then it looks like the code snippet -# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST -# itself also seems to recognize this as a code block, although it appears -# under-specified.) -def rst_literal_first_line_indent_uses_tabs_4spaces(): +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): """ - Do cool stuff:: - - cool_stuff(1) + Do cool stuff. - Done. - """ + >>> cool_stuff(x)""" pass -# Like the test above, but with multiple lines. -def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): """ - Do cool stuff:: - - cool_stuff(1) - cool_stuff(2) + Do cool stuff. - Done. - """ + >>> cool_stuff(x) + ... more(y)""" pass -# Another test with tabs, except in this case, if your tabwidth is less than -# 8, than the code snippet actually looks like its indent is *less* than the -# opening line with a `::`. One might presume this means that the code snippet -# is not treated as a literal block and thus not reformatted, but since we -# assume all tabs have tabwidth=8 when computing indentation length, the code -# snippet is actually seen as being more indented than the opening `::` line. -# As with the above example, reST seems to behave the same way here. -def rst_literal_first_line_indent_uses_tabs_8spaces(): +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): """ - Do cool stuff:: - - cool_stuff(1) + Do cool stuff. - Done. + >>> def cool_stuff(x): + ... print(x) + ... + ... print(x) """ pass -# Like the test above, but with multiple lines. -def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): """ - Do cool stuff:: - - cool_stuff(1) - cool_stuff(2) + Do cool stuff. - Done. + >>> def cool_stuff(x): + ... print(x) + ... print(x) """ pass -# Tests that if two lines in a literal block are indented to the same level -# but by different means (tabs versus spaces), then we correctly recognize the -# block and format it. -def rst_literal_first_line_tab_second_line_spaces(): +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): """ - Do cool stuff:: + Do cool stuff. - cool_stuff(1) - cool_stuff(2) + >>> def cool_stuff(x): + ... print(x) + ... print(x) - Done. + And say something else. """ pass -# Tests that when two lines in a code snippet have weird and inconsistent -# indentation, the code still gets formatted so long as the indent is greater -# than the indent of the `::` line. -# -# In this case, the minimum indent is 5 spaces (from the second line) where as -# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). -# The minimum indent is stripped from each code line. Since tabs aren't -# divisible, the entire tab is stripped, which means the first and second lines -# wind up with the same level of indentation. -# -# An alternative behavior here would be that the tab is replaced with 3 spaces -# instead of being stripped entirely. The code snippet itself would then have -# inconsistent indentation to the point of being invalid Python, and thus code -# formatting would be skipped. -# -# I decided on the former behavior because it seems a bit easier to implement, -# but we might want to switch to the alternative if cases like this show up in -# the real world. ---AG -def rst_literal_odd_indentation(): +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): """ - Do cool stuff:: - - cool_stuff(1) - cool_stuff(2) + Do cool stuff. - Done. + >>> x = '''tricksy''' """ pass -# Tests that having a line with a lone `::` works as an introduction of a -# literal block. -def rst_literal_lone_colon(): +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): """ Do cool stuff. - :: - - cool_stuff(1) - - Done. + >>> x = f'''tricksy''' """ pass -def rst_directive_simple(): +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): """ - .. code-block:: python - - cool_stuff(1) + Do cool stuff. - Done. + >>> x = '''\"\"\"''' """ pass -def rst_directive_case_insensitive(): - """ - .. cOdE-bLoCk:: python - - cool_stuff(1) +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. - Done. - """ + >>> x = """tricksy""" + ''' pass -def rst_directive_sourcecode(): - """ - .. sourcecode:: python - - cool_stuff(1) +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. - Done. - """ + >>> x = f"""tricksy""" + ''' pass -def rst_directive_options(): - """ - .. code-block:: python - :linenos: - :emphasize-lines: 2,3 - :name: blah blah - - cool_stuff(1) - cool_stuff(2) - cool_stuff(3) - cool_stuff(4) +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. - Done. - """ + >>> def nested(x): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' pass -# In this case, since `pycon` isn't recognized as a Python code snippet, the -# docstring reformatter ignores it. But it then picks up the doctest and -# reformats it. -def rst_directive_doctest(): +# Tests that the starting column does not matter. +def doctest_varying_start_column(): """ - .. code-block:: pycon - - >>> cool_stuff(1) + Do cool stuff. - Done. + >>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1 """ pass -# This checks that if the first non-empty line after the start of a literal -# block is not indented more than the line containing the `::`, then it is not -# treated as a code snippet. -def rst_literal_skipped_first_line_not_indented(): +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): """ - Do cool stuff:: + Do cool stuff. - cool_stuff( 1 ) + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) - Done. + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard + ... ) """ - pass + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) -# Like the test above, but inserts an indented line after the un-indented one. -# This should not cause the literal block to be resumed. -def rst_literal_skipped_first_line_not_indented_then_indented(): +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): """ - Do cool stuff:: - - cool_stuff( 1 ) - cool_stuff( 2 ) + Do cool stuff. - Done. + >>> cool-stuff( x ): + 2 """ pass -# This also checks that a code snippet is not reformatted when the indentation -# of the first line is not more than the line with `::`, but this uses tabs to -# make it a little more confounding. It relies on the fact that indentation -# length is computed by assuming a tabwidth equal to 8. reST also rejects this -# and doesn't treat it as a literal block. -def rst_literal_skipped_first_line_not_indented_tab(): +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): """ - Do cool stuff:: - - cool_stuff( 1 ) + Do cool stuff. - Done. + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 """ pass -# Like the previous test, but adds a second line. -def rst_literal_skipped_first_line_not_indented_tab_multiple(): +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): """ - Do cool stuff:: - - cool_stuff( 1 ) - cool_stuff( 2 ) + Do cool stuff. - Done. + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 """ pass -# Tests that a code block with a second line that is not properly indented gets -# skipped. A valid code block needs to have an empty line separating these. -# -# One trick here is that we need to make sure the Python code in the snippet is -# valid, otherwise it would be skipped because of invalid Python. -def rst_literal_skipped_subsequent_line_not_indented(): +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): """ - Do cool stuff:: - - if True: - cool_stuff( ''' - hiya''' ) + Do cool stuff. - Done. + >>> def cool_stuff(x): + ... print(x) + ... print( f"hi {x}" ); + hi 2 """ pass -# In this test, we write what looks like a code-block, but it should be treated -# as invalid due to the missing `language` argument. -# -# It does still look like it could be a literal block according to the literal -# rules, but we currently consider the `.. ` prefix to indicate that it is not -# a literal block. -def rst_literal_skipped_not_directive(): +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): """ - .. code-block:: - - cool_stuff( 1 ) + Do cool stuff. - Done. + >>> foo( x ) + ... '''tri'''cksy''' """ pass -# In this test, we start a line with `.. `, which makes it look like it might -# be a directive. But instead continue it as if it was just some periods from -# the previous line, and then try to end it by starting a literal block. -# -# But because of the `.. ` in the beginning, we wind up not treating this as a -# code snippet. The reST render I was using to test things does actually treat -# this as a code block, so we may be out of conformance here. -def rst_literal_skipped_possible_false_negative(): - """ - This is a test. - .. This is a test:: - - cool_stuff( 1 ) - - Done. - """ +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" pass -# This tests that a doctest inside of a reST literal block doesn't get -# reformatted. It's plausible this isn't the right behavior, but it also seems -# like it might be the right behavior since it is a literal block. (The doctest -# makes the Python code invalid.) -def rst_literal_skipped_doctest(): - """ - Do cool stuff:: - - >>> cool_stuff( 1 ) +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. - Done. - """ + >>> cool_stuff( 1 ) + 2 + """ pass -def rst_directive_skipped_not_indented(): +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): """ - .. code-block:: python - - cool_stuff( 1 ) + Do cool stuff. - Done. + >>> x = '\"\"\"' """ pass -def rst_directive_skipped_wrong_language(): +############################################################################### +# reStructuredText CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# reStructuredText formatted code blocks. +# +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +############################################################################### + + +def rst_literal_simple(): """ - .. code-block:: rust + Do cool stuff:: - cool_stuff( 1 ) + cool_stuff(1) Done. """ pass -# This gets skipped for the same reason that the doctest in a literal block -# gets skipped. -def rst_directive_skipped_doctest(): +def rst_literal_simple_continued(): """ - .. code-block:: python + Do cool stuff:: - >>> cool_stuff( 1 ) + def cool_stuff(x): + print(f"hi {x}") Done. """ pass -``` -### Output 8 -``` -indent-style = tab -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Enabled -preview = Disabled -``` - -```python -############################################################################### -# DOCTEST CODE EXAMPLES -# -# This section shows examples of docstrings that contain code snippets in -# Python's "doctest" format. -# -# See: https://docs.python.org/3/library/doctest.html -############################################################################### - -# The simplest doctest to ensure basic formatting works. -def doctest_simple(): +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): """ - Do cool stuff. + Do cool stuff:: - >>> cool_stuff(1) - 2 + cool_stuff(1) """ pass -# Another simple test, but one where the Python code -# extends over multiple lines. -def doctest_simple_continued(): +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): """ - Do cool stuff. + Do cool stuff:: - >>> def cool_stuff(x): - ... print(f"hi {x}") - hi 2 - """ + cool_stuff(1)""" pass -# Test that we support multiple directly adjacent -# doctests. -def doctest_adjacent(): +def rst_literal_with_blank_lines(): """ - Do cool stuff. + Do cool stuff:: - >>> cool_stuff(x) - >>> cool_stuff(y) - 2 + def cool_stuff(x): + print(f"hi {x}") + + + def other_stuff(y): + print(y) + + Done. """ pass -# Test that a doctest on the last non-whitespace line of a docstring -# reformats correctly. -def doctest_last_line(): +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): """ - Do cool stuff. + Do cool stuff:: - >>> cool_stuff(x) + + + cool_stuff(1) + + + + Done. """ pass -# Test that a doctest that continues to the last non-whitespace line of -# a docstring reformats correctly. -def doctest_last_line_continued(): +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): """ - Do cool stuff. + Do cool stuff:: + + + cool_stuff(1) + + - >>> def cool_stuff(x): - ... print(f"hi {x}") """ pass -# Test that a doctest on the real last line of a docstring reformats -# correctly. -def doctest_really_last_line(): +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): """ - Do cool stuff. + Do cool stuff:: - >>> cool_stuff(x)""" - pass + cool_stuff(1) -# Test that a continued doctest on the real last line of a docstring reformats -# correctly. -def doctest_really_last_line_continued(): - """ - Do cool stuff. + cool_stuff(2) - >>> cool_stuff(x) - ... more(y)""" + Done. + """ pass -# Test that a doctest is correctly identified and formatted with a blank -# continuation line. -def doctest_blank_continued(): +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): """ - Do cool stuff. + Do cool stuff:: - >>> def cool_stuff(x): - ... print(x) - ... - ... print(x) + if True: + cool_stuff( + ''' + hiya''' + ) + + Done. """ pass -# Tests that a blank PS2 line at the end of a doctest can get dropped. -# It is treated as part of the Python snippet which will trim the -# trailing whitespace. -def doctest_blank_end(): +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): """ - Do cool stuff. + Do cool stuff:: - >>> def cool_stuff(x): - ... print(x) - ... print(x) + cool_stuff(1) + + Done. """ pass -# Tests that a blank PS2 line at the end of a doctest can get dropped -# even when there is text following it. -def doctest_blank_end_then_some_text(): +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): """ - Do cool stuff. + Do cool stuff:: - >>> def cool_stuff(x): - ... print(x) - ... print(x) + cool_stuff(1) + cool_stuff(2) - And say something else. + Done. """ pass -# Test that a doctest containing a triple quoted string gets formatted -# correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): """ - Do cool stuff. + Do cool stuff:: - >>> x = '''tricksy''' + cool_stuff(1) + + Done. """ pass -# Test that a doctest containing a triple quoted f-string gets -# formatted correctly and doesn't result in invalid syntax. -def doctest_with_triple_single(): +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): """ - Do cool stuff. + Do cool stuff:: - >>> x = f'''tricksy''' + cool_stuff(1) + cool_stuff(2) + + Done. """ pass -# Another nested multi-line string case, but with triple escaped double -# quotes inside a triple single quoted string. -def doctest_with_triple_escaped_double(): +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): """ - Do cool stuff. + Do cool stuff:: - >>> x = '''\"\"\"''' + cool_stuff(1) + cool_stuff(2) + + Done. """ pass -# Tests that inverting the triple quoting works as expected. -def doctest_with_triple_inverted(): - ''' - Do cool stuff. +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. +# +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: - >>> x = """tricksy""" - ''' + cool_stuff(1) + cool_stuff(2) + + Done. + """ pass -# Tests that inverting the triple quoting with an f-string works as -# expected. -def doctest_with_triple_inverted_fstring(): - ''' +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ Do cool stuff. - >>> x = f"""tricksy""" - ''' + :: + + cool_stuff(1) + + Done. + """ pass -# Tests nested doctests are ignored. That is, we don't format doctests -# recursively. We only recognize "top level" doctests. -# -# This restriction primarily exists to avoid needing to deal with -# nesting quotes. It also seems like a generally sensible restriction, -# although it could be lifted if necessary I believe. -def doctest_nested_doctest_not_formatted(): - ''' - Do cool stuff. +def rst_directive_simple(): + """ + .. code-block:: python - >>> def nested(x): - ... """ - ... Do nested cool stuff. - ... >>> func_call( 5 ) - ... """ - ... pass - ''' + cool_stuff(1) + + Done. + """ pass -# Tests that the starting column does not matter. -def doctest_varying_start_column(): +def rst_directive_case_insensitive(): """ - Do cool stuff. + .. cOdE-bLoCk:: python + + cool_stuff(1) - >>> assert "Easy!" - >>> import math - >>> math.floor(1.9) - 1 + Done. """ pass -# Tests that long lines get wrapped... appropriately. -# -# The docstring code formatter uses the same line width settings as for -# formatting other code. This means that a line in the docstring can -# actually extend past the configured line limit. -# -# It's not quite clear whether this is desirable or not. We could in -# theory compute the intendation length of a code snippet and then -# adjust the line-width setting on a recursive call to the formatter. -# But there are assuredly pathological cases to consider. Another path -# would be to expose another formatter option for controlling the -# line-width of code snippets independently. -def doctest_long_lines(): +def rst_directive_sourcecode(): """ - Do cool stuff. + .. sourcecode:: python - This won't get wrapped even though it exceeds our configured - line width because it doesn't exceed the line width within this - docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + cool_stuff(1) - But this one is long enough to get wrapped. - >>> foo, bar, quux = this_is_a_long_line( - ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard - ... ) + Done. """ - # This demostrates a normal line that will get wrapped but won't - # get wrapped in the docstring above because of how the line-width - # setting gets reset at the first column in each code snippet. - foo, bar, quux = this_is_a_long_line( - lion, giraffe, hippo, zeba, lemur, penguin, monkey - ) + pass -# Checks that a simple but invalid doctest gets skipped. -def doctest_skipped_simple(): +def rst_directive_options(): """ - Do cool stuff. + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah - >>> cool-stuff( x ): - 2 + cool_stuff(1) + cool_stuff(2) + cool_stuff(3) + cool_stuff(4) + + Done. """ pass -# Checks that a simple doctest that is continued over multiple lines, -# but is invalid, gets skipped. -def doctest_skipped_simple_continued(): +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): """ - Do cool stuff. + .. code-block:: pycon - >>> def cool-stuff( x ): - ... print( f"hi {x}" ); - 2 + >>> cool_stuff(1) + + Done. """ pass -# Checks that a doctest with improper indentation gets skipped. -def doctest_skipped_inconsistent_indent(): +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): """ - Do cool stuff. + Do cool stuff:: - >>> def cool_stuff( x ): - ... print( f"hi {x}" ); - hi 2 + cool_stuff( 1 ) + + Done. """ pass -# Checks that a doctest with some proper indentation and some improper -# indentation is "partially" formatted. That is, the part that appears -# before the inconsistent indentation is formatted. This requires that -# the part before it is valid Python. -def doctest_skipped_partial_inconsistent_indent(): +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): """ - Do cool stuff. + Do cool stuff:: - >>> def cool_stuff(x): - ... print(x) - ... print( f"hi {x}" ); - hi 2 + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. """ pass -# Checks that a doctest with improper triple single quoted string gets -# skipped. That is, the code snippet is itself invalid Python, so it is -# left as is. -def doctest_skipped_triple_incorrect(): +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): """ - Do cool stuff. + Do cool stuff:: - >>> foo( x ) - ... '''tri'''cksy''' + cool_stuff( 1 ) + + Done. """ pass -# Tests that a doctest on a single line is skipped. -def doctest_skipped_one_line(): - ">>> foo( x )" +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ pass -# f-strings are not considered docstrings[1], so any doctests -# inside of them should not be formatted. +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. # -# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals -def doctest_skipped_fstring(): - f""" - Do cool stuff. +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: - >>> cool_stuff( 1 ) - 2 - """ + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ pass -# Test that a doctest containing a triple quoted string at least -# does not result in invalid Python code. Ideally this would format -# correctly, but at time of writing it does not. -def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): """ - Do cool stuff. + .. code-block:: - >>> x = '\"\"\"' + cool_stuff( 1 ) + + Done. """ pass -############################################################################### -# reStructuredText CODE EXAMPLES -# -# This section shows examples of docstrings that contain code snippets in -# reStructuredText formatted code blocks. +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. # -# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks -# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 -# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 -############################################################################### - - -def rst_literal_simple(): +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): """ - Do cool stuff:: + This is a test. + .. This is a test:: - cool_stuff(1) + cool_stuff( 1 ) Done. """ pass -def rst_literal_simple_continued(): +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): """ Do cool stuff:: - def cool_stuff(x): - print(f"hi {x}") + >>> cool_stuff( 1 ) Done. """ pass -# Tests that we can end the literal block on the second -# to last line of the docstring. -def rst_literal_second_to_last(): +def rst_literal_skipped_markdown(): """ Do cool stuff:: - cool_stuff(1) + ```py + cool_stuff( 1 ) + ``` + + Done. """ pass -# Tests that we can end the literal block on the actual -# last line of the docstring. -def rst_literal_actually_last(): +def rst_directive_skipped_not_indented(): """ - Do cool stuff:: - - cool_stuff(1)""" - pass + .. code-block:: python + cool_stuff( 1 ) -def rst_literal_with_blank_lines(): + Done. """ - Do cool stuff:: + pass - def cool_stuff(x): - print(f"hi {x}") +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust - def other_stuff(y): - print(y) + cool_stuff( 1 ) Done. """ pass -# Extra blanks should be preserved. -def rst_literal_extra_blanks(): +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): """ - Do cool stuff:: + .. code-block:: python + + >>> cool_stuff( 1 ) + Done. + """ + pass - cool_stuff(1) +############################################################################### +# Markdown CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Markdown fenced code blocks. +# +# See: https://spec.commonmark.org/0.30/#fenced-code-blocks +############################################################################### + +def markdown_simple(): + """ + Do cool stuff. + ```py + cool_stuff(1) + ``` Done. """ pass -# If a literal block is never properly ended (via a non-empty unindented line), -# then the end of the block should be the last non-empty line. And subsequent -# empty lines should be preserved as-is. -def rst_literal_extra_blanks_at_end(): +def markdown_simple_continued(): """ - Do cool stuff:: - + Do cool stuff. - cool_stuff(1) + ```python + def cool_stuff(x): + print(f"hi {x}") + ``` + Done. + """ + pass +# Tests that unlabeled Markdown fenced code blocks are assumed to be Python. +def markdown_unlabeled(): """ - pass + Do cool stuff. + ``` + cool_stuff(1) + ``` -# A literal block can contain many empty lines and it should not end the block -# if it continues. -def rst_literal_extra_blanks_in_snippet(): + Done. """ - Do cool stuff:: + pass - cool_stuff(1) +# Tests that fenced code blocks using tildes work. +def markdown_tildes(): + """ + Do cool stuff. - cool_stuff(2) + ~~~py + cool_stuff(1) + ~~~ Done. """ pass -# This tests that a unindented line appearing after an indented line (but where -# the indent is still beyond the minimum) gets formatted properly. -def rst_literal_subsequent_line_not_indented(): +# Tests that a longer closing fence is just fine and dandy. +def markdown_longer_closing_fence(): """ - Do cool stuff:: + Do cool stuff. - if True: - cool_stuff( - ''' - hiya''' - ) + ```py + cool_stuff(1) + `````` Done. """ pass -# This checks that if the first line in a code snippet has been indented with -# tabs, then so long as its "indentation length" is considered bigger than the -# line with `::`, it is reformatted as code. +# Tests that an invalid closing fence is treated as invalid. # -# (If your tabwidth is set to 4, then it looks like the code snippet -# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST -# itself also seems to recognize this as a code block, although it appears -# under-specified.) -def rst_literal_first_line_indent_uses_tabs_4spaces(): +# We embed it into a docstring so that the surrounding Python +# remains valid. +def markdown_longer_closing_fence(): """ - Do cool stuff:: + Do cool stuff. - cool_stuff(1) + ```py + cool_stuff(1) + ''' + ```invalid + ''' + cool_stuff(2) + ``` Done. """ pass -# Like the test above, but with multiple lines. -def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): +# Tests that one can nest fenced code blocks by using different numbers of +# backticks. +def markdown_nested_fences(): """ - Do cool stuff:: + Do cool stuff. - cool_stuff(1) - cool_stuff(2) + `````` + do_something( + ''' + ``` + did i trick you? + ``` + ''' + ) + `````` Done. """ pass -# Another test with tabs, except in this case, if your tabwidth is less than -# 8, than the code snippet actually looks like its indent is *less* than the -# opening line with a `::`. One might presume this means that the code snippet -# is not treated as a literal block and thus not reformatted, but since we -# assume all tabs have tabwidth=8 when computing indentation length, the code -# snippet is actually seen as being more indented than the opening `::` line. -# As with the above example, reST seems to behave the same way here. -def rst_literal_first_line_indent_uses_tabs_8spaces(): +# Tests that an unclosed block gobbles up everything remaining in the +# docstring. When it's only empty lines, those are passed into the formatter +# and thus stripped. +def markdown_unclosed_empty_lines(): """ - Do cool stuff:: + Do cool stuff. - cool_stuff(1) + ```py + cool_stuff(1)""" + pass - Done. + +# Tests that we can end the block on the second to last line of the +# docstring. +def markdown_second_to_last(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ``` """ pass -# Like the test above, but with multiple lines. -def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): +# Tests that an unclosed block with one extra line at the end is treated +# correctly. As per the CommonMark spec, an unclosed fenced code block contains +# everything following the opening fences. Since formatting the code snippet +# trims lines, the last empty line is removed here. +def markdown_second_to_last(): """ - Do cool stuff:: + Do cool stuff. - cool_stuff(1) - cool_stuff(2) + ```py + cool_stuff(1)""" + pass - Done. + +# Tests that we can end the block on the actual last line of the docstring. +def markdown_actually_last(): """ + Do cool stuff. + + ```py + cool_stuff(1) + ```""" pass -# Tests that if two lines in a literal block are indented to the same level -# but by different means (tabs versus spaces), then we correctly recognize the -# block and format it. -def rst_literal_first_line_tab_second_line_spaces(): +# Tests that an unclosed block that ends on the last line of a docstring +# is handled correctly. +def markdown_unclosed_actually_last(): """ - Do cool stuff:: + Do cool stuff. - cool_stuff(1) - cool_stuff(2) + ```py + cool_stuff(1)""" + pass + + +def markdown_with_blank_lines(): + """ + Do cool stuff. + + ```py + def cool_stuff(x): + print(f"hi {x}") + + + def other_stuff(y): + print(y) + ``` Done. """ pass -# Tests that when two lines in a code snippet have weird and inconsistent -# indentation, the code still gets formatted so long as the indent is greater -# than the indent of the `::` line. -# -# In this case, the minimum indent is 5 spaces (from the second line) where as -# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). -# The minimum indent is stripped from each code line. Since tabs aren't -# divisible, the entire tab is stripped, which means the first and second lines -# wind up with the same level of indentation. -# -# An alternative behavior here would be that the tab is replaced with 3 spaces -# instead of being stripped entirely. The code snippet itself would then have -# inconsistent indentation to the point of being invalid Python, and thus code -# formatting would be skipped. -# -# I decided on the former behavior because it seems a bit easier to implement, -# but we might want to switch to the alternative if cases like this show up in -# the real world. ---AG -def rst_literal_odd_indentation(): +def markdown_first_line_indent_uses_tabs_4spaces(): """ - Do cool stuff:: + Do cool stuff. - cool_stuff(1) - cool_stuff(2) + ```py + cool_stuff(1) + ``` Done. """ pass -# Tests that having a line with a lone `::` works as an introduction of a -# literal block. -def rst_literal_lone_colon(): +def markdown_first_line_indent_uses_tabs_4spaces_multiple(): """ Do cool stuff. - :: - - cool_stuff(1) + ```py + cool_stuff(1) + cool_stuff(2) + ``` Done. """ pass -def rst_directive_simple(): +def markdown_first_line_indent_uses_tabs_8spaces(): """ - .. code-block:: python + Do cool stuff. - cool_stuff(1) + ```py + cool_stuff(1) + ``` Done. """ pass -def rst_directive_case_insensitive(): +def markdown_first_line_indent_uses_tabs_8spaces_multiple(): """ - .. cOdE-bLoCk:: python + Do cool stuff. - cool_stuff(1) + ```py + cool_stuff(1) + cool_stuff(2) + ``` Done. """ pass -def rst_directive_sourcecode(): +def markdown_first_line_tab_second_line_spaces(): """ - .. sourcecode:: python + Do cool stuff. + ```py cool_stuff(1) + cool_stuff(2) + ``` Done. """ pass -def rst_directive_options(): +def markdown_odd_indentation(): """ - .. code-block:: python - :linenos: - :emphasize-lines: 2,3 - :name: blah blah + Do cool stuff. + ```py cool_stuff(1) cool_stuff(2) - cool_stuff(3) - cool_stuff(4) + ``` Done. """ pass -# In this case, since `pycon` isn't recognized as a Python code snippet, the -# docstring reformatter ignores it. But it then picks up the doctest and -# reformats it. -def rst_directive_doctest(): +# Extra blanks should be *not* be preserved (unlike reST) because they are part +# of the code snippet (per CommonMark spec), and thus get trimmed as part of +# code formatting. +def markdown_extra_blanks(): """ - .. code-block:: pycon + Do cool stuff. - >>> cool_stuff(1) + ```py + cool_stuff(1) + ``` Done. """ pass -# This checks that if the first non-empty line after the start of a literal -# block is not indented more than the line containing the `::`, then it is not -# treated as a code snippet. -def rst_literal_skipped_first_line_not_indented(): +# A block can contain many empty lines within it. +def markdown_extra_blanks_in_snippet(): """ - Do cool stuff:: + Do cool stuff. - cool_stuff( 1 ) + ```py + cool_stuff(1) + + + cool_stuff(2) + ``` Done. """ pass -# Like the test above, but inserts an indented line after the un-indented one. -# This should not cause the literal block to be resumed. -def rst_literal_skipped_first_line_not_indented_then_indented(): +def markdown_weird_closing(): """ - Do cool stuff:: + Code block with weirdly placed closing fences. - cool_stuff( 1 ) - cool_stuff( 2 ) + ```python + cool_stuff(1) + ``` + # The above fences look like it shouldn't close the block, but we + # allow it to. The fences below re-open a block (until the end of + # the docstring), but it's invalid Python and thus doesn't get + # reformatted. + a = 10 + ``` - Done. + Now the code block is closed """ pass -# This also checks that a code snippet is not reformatted when the indentation -# of the first line is not more than the line with `::`, but this uses tabs to -# make it a little more confounding. It relies on the fact that indentation -# length is computed by assuming a tabwidth equal to 8. reST also rejects this -# and doesn't treat it as a literal block. -def rst_literal_skipped_first_line_not_indented_tab(): +def markdown_over_indented(): """ - Do cool stuff:: - - cool_stuff( 1 ) - - Done. + A docstring + over intended + ```python + print(5) + ``` """ pass -# Like the previous test, but adds a second line. -def rst_literal_skipped_first_line_not_indented_tab_multiple(): +# Tests that an unclosed block gobbles up everything remaining in the +# docstring, even if it isn't valid Python. Since it isn't valid Python, +# reformatting fails and the entire thing is skipped. +def markdown_skipped_unclosed_non_python(): """ - Do cool stuff:: + Do cool stuff. + ```py cool_stuff( 1 ) - cool_stuff( 2 ) - Done. + I forgot to close the code block, and this is definitely not + Python. So nothing here gets formatted. """ pass -# Tests that a code block with a second line that is not properly indented gets -# skipped. A valid code block needs to have an empty line separating these. -# -# One trick here is that we need to make sure the Python code in the snippet is -# valid, otherwise it would be skipped because of invalid Python. -def rst_literal_skipped_subsequent_line_not_indented(): +# This has a Python snippet with a docstring that contains a closing fence. +# This splits the embedded docstring and makes the overall snippet invalid. +def markdown_skipped_accidental_closure(): """ - Do cool stuff:: + Do cool stuff. - if True: - cool_stuff( ''' - hiya''' ) + ```py + cool_stuff( 1 ) + ''' + ``` + ''' + ``` Done. """ pass -# In this test, we write what looks like a code-block, but it should be treated -# as invalid due to the missing `language` argument. +# When a line is unindented all the way out before the standard indent of the +# docstring, the code reformatting ends up interacting poorly with the standard +# docstring whitespace normalization logic. This is probably a bug, and we +# should probably treat the Markdown block as valid, but for now, we detect +# the unindented line and declare the block as invalid and thus do no code +# reformatting. # -# It does still look like it could be a literal block according to the literal -# rules, but we currently consider the `.. ` prefix to indicate that it is not -# a literal block. -def rst_literal_skipped_not_directive(): +# FIXME: Fixing this (if we think it's a bug) probably requires refactoring the +# docstring whitespace normalization to be aware of code snippets. Or perhaps +# plausibly, to do normalization *after* code snippets have been formatted. +def markdown_skipped_unindented_completely(): """ - .. code-block:: + Do cool stuff. - cool_stuff( 1 ) + ```py + cool_stuff( 1 ) + ``` - Done. + Done. """ pass -# In this test, we start a line with `.. `, which makes it look like it might -# be a directive. But instead continue it as if it was just some periods from -# the previous line, and then try to end it by starting a literal block. -# -# But because of the `.. ` in the beginning, we wind up not treating this as a -# code snippet. The reST render I was using to test things does actually treat -# this as a code block, so we may be out of conformance here. -def rst_literal_skipped_possible_false_negative(): +# This test is fallout from treating fenced code blocks with unindented lines +# as invalid. We probably should treat this as a valid block. Indeed, if we +# remove the logic that makes the `markdown_skipped_unindented_completely` test +# pass, then this code snippet will get reformatted correctly. +def markdown_skipped_unindented_somewhat(): """ - This is a test. - .. This is a test:: + Do cool stuff. - cool_stuff( 1 ) + ```py + cool_stuff( 1 ) + ``` Done. """ pass -# This tests that a doctest inside of a reST literal block doesn't get -# reformatted. It's plausible this isn't the right behavior, but it also seems -# like it might be the right behavior since it is a literal block. (The doctest -# makes the Python code invalid.) -def rst_literal_skipped_doctest(): +# This tests that if a Markdown block contains a line that has less of an +# indent than another line. +# +# There is some judgment involved in what the right behavior is here. We +# could "normalize" the indentation so that the minimum is the indent of the +# opening fence line. If we did that here, then the code snippet would become +# valid and format as Python. But at time of writing, we don't, which leads to +# inconsistent indentation and thus invalid Python. +def markdown_skipped_unindented_with_inconsistent_indentation(): """ - Do cool stuff:: + Do cool stuff. - >>> cool_stuff( 1 ) + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` Done. """ pass -def rst_directive_skipped_not_indented(): +def markdown_skipped_doctest(): """ - .. code-block:: python + Do cool stuff. - cool_stuff( 1 ) + ```py + >>> cool_stuff( 1 ) + ``` Done. """ pass -def rst_directive_skipped_wrong_language(): +def markdown_skipped_rst_literal(): """ - .. code-block:: rust + Do cool stuff. + + ```py + And do this:: cool_stuff( 1 ) + ``` + Done. """ pass -# This gets skipped for the same reason that the doctest in a literal block -# gets skipped. -def rst_directive_skipped_doctest(): +def markdown_skipped_rst_directive(): """ + Do cool stuff. + + ```py .. code-block:: python - >>> cool_stuff( 1 ) + cool_stuff( 1 ) + + ``` Done. """ From 6bbabceead840e0d232950a1ed1e8f02cdafb92c Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Thu, 7 Dec 2023 14:15:43 -0600 Subject: [PATCH 140/197] Allow transparent cell magics (#8911) ## Summary This PR updates the logic for `is_magic_cell` to include certain cell magics. These cell magics would contain Python code following the line defining the command. The code could define a variable which can then be referenced in other cells. Currently, we would ignore the cell completely leading to undefined-name violation. As discussed in https://github.com/astral-sh/ruff/issues/8354#issuecomment-1832221009 ## Test Plan Add new test case to validate this scenario. --- ...er__linter__tests__ipy_escape_command.snap | 15 +++++++ .../fixtures/jupyter/cell/cell_magic.json | 7 ++- .../jupyter/cell/valid_cell_magic.json | 11 +++++ .../fixtures/jupyter/ipy_escape_command.ipynb | 12 +++++ .../jupyter/ipy_escape_command_expected.ipynb | 15 ++++++- crates/ruff_notebook/src/cell.rs | 45 ++++++++++++++++++- crates/ruff_notebook/src/notebook.rs | 1 + 7 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 crates/ruff_notebook/resources/test/fixtures/jupyter/cell/valid_cell_magic.json diff --git a/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__ipy_escape_command.snap b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__ipy_escape_command.snap index 58aa72d7da26b..8c1a547e85966 100644 --- a/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__ipy_escape_command.snap +++ b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__ipy_escape_command.snap @@ -19,5 +19,20 @@ ipy_escape_command.ipynb:cell 1:5:8: F401 [*] `os` imported but unused 5 |-import os 6 5 | 7 6 | _ = math.pi +8 7 | %%timeit + +ipy_escape_command.ipynb:cell 2:2:8: F401 [*] `sys` imported but unused + | +1 | %%timeit +2 | import sys + | ^^^ F401 + | + = help: Remove unused import: `sys` + +ℹ Safe fix +6 6 | +7 7 | _ = math.pi +8 8 | %%timeit +9 |-import sys diff --git a/crates/ruff_notebook/resources/test/fixtures/jupyter/cell/cell_magic.json b/crates/ruff_notebook/resources/test/fixtures/jupyter/cell/cell_magic.json index ef68b202e6811..e0de8c0241141 100644 --- a/crates/ruff_notebook/resources/test/fixtures/jupyter/cell/cell_magic.json +++ b/crates/ruff_notebook/resources/test/fixtures/jupyter/cell/cell_magic.json @@ -4,5 +4,10 @@ "id": "1", "metadata": {}, "outputs": [], - "source": ["%%timeit\n", "print('hello world')"] + "source": [ + "%%script bash\n", + "for i in 1 2 3; do\n", + " echo $i\n", + "done" + ] } diff --git a/crates/ruff_notebook/resources/test/fixtures/jupyter/cell/valid_cell_magic.json b/crates/ruff_notebook/resources/test/fixtures/jupyter/cell/valid_cell_magic.json new file mode 100644 index 0000000000000..2cb89fa63b9bd --- /dev/null +++ b/crates/ruff_notebook/resources/test/fixtures/jupyter/cell/valid_cell_magic.json @@ -0,0 +1,11 @@ +{ + "execution_count": null, + "cell_type": "code", + "id": "1", + "metadata": {}, + "outputs": [], + "source": [ + "%%timeit\n", + "print('hello world')" + ] +} diff --git a/crates/ruff_notebook/resources/test/fixtures/jupyter/ipy_escape_command.ipynb b/crates/ruff_notebook/resources/test/fixtures/jupyter/ipy_escape_command.ipynb index 5e9b10bb7b0e1..6937096cc0a51 100644 --- a/crates/ruff_notebook/resources/test/fixtures/jupyter/ipy_escape_command.ipynb +++ b/crates/ruff_notebook/resources/test/fixtures/jupyter/ipy_escape_command.ipynb @@ -26,6 +26,18 @@ "%%timeit\n", "import sys" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36dedfd1-6c03-4894-bea6-6c1687b82b3c", + "metadata": {}, + "outputs": [], + "source": [ + "%%random\n", + "# This cell is ignored\n", + "import pathlib" + ] } ], "metadata": { diff --git a/crates/ruff_notebook/resources/test/fixtures/jupyter/ipy_escape_command_expected.ipynb b/crates/ruff_notebook/resources/test/fixtures/jupyter/ipy_escape_command_expected.ipynb index 8419f031e78f8..6a5eebc05fa80 100644 --- a/crates/ruff_notebook/resources/test/fixtures/jupyter/ipy_escape_command_expected.ipynb +++ b/crates/ruff_notebook/resources/test/fixtures/jupyter/ipy_escape_command_expected.ipynb @@ -22,8 +22,19 @@ "metadata": {}, "outputs": [], "source": [ - "%%timeit\n", - "import sys" + "%%timeit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b6d7faa-72b3-4087-8670-fe6d35e41fb6", + "metadata": {}, + "outputs": [], + "source": [ + "%%random\n", + "# This cell is ignored\n", + "import pathlib" ] } ], diff --git a/crates/ruff_notebook/src/cell.rs b/crates/ruff_notebook/src/cell.rs index d80ef336de02e..caa4cb3204a03 100644 --- a/crates/ruff_notebook/src/cell.rs +++ b/crates/ruff_notebook/src/cell.rs @@ -170,7 +170,50 @@ impl Cell { } // Detect cell magics (which operate on multiple lines). - lines.any(|line| line.trim_start().starts_with("%%")) + lines.any(|line| { + line.split_whitespace().next().is_some_and(|first| { + if first.len() < 2 { + return false; + } + let (token, command) = first.split_at(2); + // These cell magics are special in that the lines following them are valid + // Python code and the variables defined in that scope are available to the + // rest of the notebook. + // + // For example: + // + // Cell 1: + // ```python + // x = 1 + // ``` + // + // Cell 2: + // ```python + // %%time + // y = x + // ``` + // + // Cell 3: + // ```python + // print(y) # Here, `y` is available. + // ``` + // + // This is to avoid false positives when these variables are referenced + // elsewhere in the notebook. + token == "%%" + && !matches!( + command, + "capture" + | "debug" + | "prun" + | "pypy" + | "python" + | "python3" + | "time" + | "timeit" + ) + }) + }) } } diff --git a/crates/ruff_notebook/src/notebook.rs b/crates/ruff_notebook/src/notebook.rs index a6714fa12b496..7c9e8356b79d3 100644 --- a/crates/ruff_notebook/src/notebook.rs +++ b/crates/ruff_notebook/src/notebook.rs @@ -426,6 +426,7 @@ mod tests { #[test_case(Path::new("code_and_magic.json"), true; "code_and_magic")] #[test_case(Path::new("only_code.json"), true; "only_code")] #[test_case(Path::new("cell_magic.json"), false; "cell_magic")] + #[test_case(Path::new("valid_cell_magic.json"), true; "valid_cell_magic")] #[test_case(Path::new("automagic.json"), false; "automagic")] #[test_case(Path::new("automagics.json"), false; "automagics")] #[test_case(Path::new("automagic_before_code.json"), false; "automagic_before_code")] From 241429828905ef1287a53423f0c6f12d52fba313 Mon Sep 17 00:00:00 2001 From: Samuel Cormier-Iijima Date: Thu, 7 Dec 2023 18:59:22 -0500 Subject: [PATCH 141/197] Add "preserve" quote-style to mimic Black's skip-string-normalization (#8822) Co-authored-by: Micha Reiser --- .../fixtures/ruff/quote_style.options.json | 11 + .../test/fixtures/ruff/quote_style.py | 50 ++++ crates/ruff_python_formatter/src/context.rs | 17 +- .../src/expression/string/docstring.rs | 26 +- .../src/expression/string/mod.rs | 134 ++++++--- crates/ruff_python_formatter/src/options.rs | 31 +- .../snapshots/format@quote_style.py.snap | 270 ++++++++++++++++++ crates/ruff_workspace/src/configuration.rs | 19 +- crates/ruff_workspace/src/options.rs | 15 +- ruff.schema.json | 5 +- 10 files changed, 482 insertions(+), 96 deletions(-) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/quote_style.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/quote_style.py create mode 100644 crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/quote_style.options.json b/crates/ruff_python_formatter/resources/test/fixtures/ruff/quote_style.options.json new file mode 100644 index 0000000000000..59431bf1c4874 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/quote_style.options.json @@ -0,0 +1,11 @@ +[ + { + "quote_style": "single" + }, + { + "quote_style": "double" + }, + { + "quote_style": "preserve" + } +] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/quote_style.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/quote_style.py new file mode 100644 index 0000000000000..8f0d159bebd4a --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/quote_style.py @@ -0,0 +1,50 @@ +'single' +"double" +r'r single' +r"r double" +f'f single' +f"f double" +fr'fr single' +fr"fr double" +rf'rf single' +rf"rf double" +b'b single' +b"b double" +rb'rb single' +rb"rb double" +br'br single' +br"br double" + +'''single triple''' +"""double triple""" +r'''r single triple''' +r"""r double triple""" +f'''f single triple''' +f"""f double triple""" +fr'''fr single triple''' +fr"""fr double triple""" +rf'''rf single triple''' +rf"""rf double triple""" +b'''b single triple''' +b"""b double triple""" +rb'''rb single triple''' +rb"""rb double triple""" +br'''br single triple''' +br"""br double triple""" + +'single1' 'single2' +'single1' "double2" +"double1" 'single2' +"double1" "double2" + +def docstring_single_triple(): + '''single triple''' + +def docstring_double_triple(): + """double triple""" + +def docstring_double(): + "double triple" + +def docstring_single(): + 'single' diff --git a/crates/ruff_python_formatter/src/context.rs b/crates/ruff_python_formatter/src/context.rs index 2e6cdc0d2ed51..ac5dea3710017 100644 --- a/crates/ruff_python_formatter/src/context.rs +++ b/crates/ruff_python_formatter/src/context.rs @@ -1,5 +1,6 @@ use crate::comments::Comments; -use crate::{PyFormatOptions, QuoteStyle}; +use crate::expression::string::QuoteChar; +use crate::PyFormatOptions; use ruff_formatter::{Buffer, FormatContext, GroupId, SourceCode}; use ruff_source_file::Locator; use std::fmt::{Debug, Formatter}; @@ -12,14 +13,14 @@ pub struct PyFormatContext<'a> { comments: Comments<'a>, node_level: NodeLevel, /// Set to a non-None value when the formatter is running on a code - /// snippet within a docstring. The value should be the quote style of the + /// snippet within a docstring. The value should be the quote character of the /// docstring containing the code snippet. /// /// Various parts of the formatter may inspect this state to change how it /// works. For example, multi-line strings will always be written with a /// quote style that is inverted from the one here in order to ensure that /// the formatted Python code will be valid. - docstring: Option, + docstring: Option, } impl<'a> PyFormatContext<'a> { @@ -57,20 +58,20 @@ impl<'a> PyFormatContext<'a> { /// Returns a non-None value only if the formatter is running on a code /// snippet within a docstring. /// - /// The quote style returned corresponds to the quoting used for the + /// The quote character returned corresponds to the quoting used for the /// docstring containing the code snippet currently being formatted. - pub(crate) fn docstring(&self) -> Option { + pub(crate) fn docstring(&self) -> Option { self.docstring } /// Return a new context suitable for formatting code snippets within a /// docstring. /// - /// The quote style given should correspond to the style of quoting used + /// The quote character given should correspond to the quote character used /// for the docstring containing the code snippets. - pub(crate) fn in_docstring(self, style: QuoteStyle) -> PyFormatContext<'a> { + pub(crate) fn in_docstring(self, quote: QuoteChar) -> PyFormatContext<'a> { PyFormatContext { - docstring: Some(style), + docstring: Some(quote), ..self } } diff --git a/crates/ruff_python_formatter/src/expression/string/docstring.rs b/crates/ruff_python_formatter/src/expression/string/docstring.rs index bb453d20b6518..8dfa6001b7149 100644 --- a/crates/ruff_python_formatter/src/expression/string/docstring.rs +++ b/crates/ruff_python_formatter/src/expression/string/docstring.rs @@ -13,9 +13,9 @@ use { ruff_text_size::{Ranged, TextLen, TextRange, TextSize}, }; -use crate::{prelude::*, FormatModuleError, QuoteStyle}; +use crate::{prelude::*, FormatModuleError}; -use super::NormalizedString; +use super::{NormalizedString, QuoteChar}; /// Format a docstring by trimming whitespace and adjusting the indentation. /// @@ -139,7 +139,7 @@ pub(super) fn format(normalized: &NormalizedString, f: &mut PyFormatter) -> Form // Edge case: The first line is `""" "content`, so we need to insert chaperone space that keep // inner quotes and closing quotes from getting to close to avoid `""""content` - if trim_both.starts_with(normalized.quotes.style.as_char()) { + if trim_both.starts_with(normalized.quotes.quote_char.as_char()) { space().fmt(f)?; } @@ -192,7 +192,7 @@ pub(super) fn format(normalized: &NormalizedString, f: &mut PyFormatter) -> Form offset, stripped_indentation_length, already_normalized, - quote_style: normalized.quotes.style, + quote_char: normalized.quotes.quote_char, code_example: CodeExample::default(), } .add_iter(lines)?; @@ -250,8 +250,8 @@ struct DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { /// is, the formatter can take a fast path. already_normalized: bool, - /// The quote style used by the docstring being printed. - quote_style: QuoteStyle, + /// The quote character used by the docstring being printed. + quote_char: QuoteChar, /// The current code example detected in the docstring. code_example: CodeExample<'src>, @@ -476,7 +476,7 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { // instead of later, and as a result, get more consistent // results. .with_indent_style(IndentStyle::Space); - let printed = match docstring_format_source(options, self.quote_style, &codeblob) { + let printed = match docstring_format_source(options, self.quote_char, &codeblob) { Ok(printed) => printed, Err(FormatModuleError::FormatError(err)) => return Err(err), Err( @@ -498,9 +498,11 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { // a docstring. As we fix corner cases over time, we can perhaps // remove this check. See the `doctest_invalid_skipped` tests in // `docstring_code_examples.py` for when this check is relevant. - let wrapped = match self.quote_style { - QuoteStyle::Single => std::format!("'''{}'''", printed.as_code()), - QuoteStyle::Double => std::format!(r#""""{}""""#, printed.as_code()), + let wrapped = match self.quote_char { + QuoteChar::Single => std::format!("'''{}'''", printed.as_code()), + QuoteChar::Double => { + std::format!(r#""""{}""""#, printed.as_code()) + } }; let result = ruff_python_parser::parse( &wrapped, @@ -1483,7 +1485,7 @@ enum CodeExampleAddAction<'src> { /// inside of a docstring. fn docstring_format_source( options: crate::PyFormatOptions, - docstring_quote_style: QuoteStyle, + docstring_quote_style: QuoteChar, source: &str, ) -> Result { use ruff_python_parser::AsMode; @@ -1510,7 +1512,7 @@ fn docstring_format_source( /// that avoids `content""""` and `content\"""`. This does only applies to un-escaped backslashes, /// so `content\\ """` doesn't need a space while `content\\\ """` does. fn needs_chaperone_space(normalized: &NormalizedString, trim_end: &str) -> bool { - trim_end.ends_with(normalized.quotes.style.as_char()) + trim_end.ends_with(normalized.quotes.quote_char.as_char()) || trim_end.chars().rev().take_while(|c| *c == '\\').count() % 2 == 1 } diff --git a/crates/ruff_python_formatter/src/expression/string/mod.rs b/crates/ruff_python_formatter/src/expression/string/mod.rs index 260f2da239d32..1bd7f28af9c56 100644 --- a/crates/ruff_python_formatter/src/expression/string/mod.rs +++ b/crates/ruff_python_formatter/src/expression/string/mod.rs @@ -325,7 +325,7 @@ impl StringPart { quoting: Quoting, locator: &'a Locator, configured_style: QuoteStyle, - parent_docstring_quote_style: Option, + parent_docstring_quote_char: Option, ) -> NormalizedString<'a> { // Per PEP 8, always prefer double quotes for triple-quoted strings. let preferred_style = if self.quotes.triple { @@ -374,8 +374,8 @@ impl StringPart { // Overall this is a bit of a corner case and just inverting the // style from what the parent ultimately decided upon works, even // if it doesn't have perfect alignment with PEP8. - if let Some(style) = parent_docstring_quote_style { - style.invert() + if let Some(quote) = parent_docstring_quote_char { + QuoteStyle::from(quote.invert()) } else { QuoteStyle::Double } @@ -388,10 +388,14 @@ impl StringPart { let quotes = match quoting { Quoting::Preserve => self.quotes, Quoting::CanChange => { - if self.prefix.is_raw_string() { - choose_quotes_raw(raw_content, self.quotes, preferred_style) + if let Some(preferred_quote) = QuoteChar::from_style(preferred_style) { + if self.prefix.is_raw_string() { + choose_quotes_raw(raw_content, self.quotes, preferred_quote) + } else { + choose_quotes(raw_content, self.quotes, preferred_quote) + } } else { - choose_quotes(raw_content, self.quotes, preferred_style) + self.quotes } } }; @@ -526,9 +530,9 @@ impl Format> for StringPrefix { fn choose_quotes_raw( input: &str, quotes: StringQuotes, - preferred_style: QuoteStyle, + preferred_quote: QuoteChar, ) -> StringQuotes { - let preferred_quote_char = preferred_style.as_char(); + let preferred_quote_char = preferred_quote.as_char(); let mut chars = input.chars().peekable(); let contains_unescaped_configured_quotes = loop { match chars.next() { @@ -566,10 +570,10 @@ fn choose_quotes_raw( StringQuotes { triple: quotes.triple, - style: if contains_unescaped_configured_quotes { - quotes.style + quote_char: if contains_unescaped_configured_quotes { + quotes.quote_char } else { - preferred_style + preferred_quote }, } } @@ -582,14 +586,14 @@ fn choose_quotes_raw( /// For triple quoted strings, the preferred quote style is always used, unless the string contains /// a triplet of the quote character (e.g., if double quotes are preferred, double quotes will be /// used unless the string contains `"""`). -fn choose_quotes(input: &str, quotes: StringQuotes, preferred_style: QuoteStyle) -> StringQuotes { - let style = if quotes.triple { +fn choose_quotes(input: &str, quotes: StringQuotes, preferred_quote: QuoteChar) -> StringQuotes { + let quote = if quotes.triple { // True if the string contains a triple quote sequence of the configured quote style. let mut uses_triple_quotes = false; let mut chars = input.chars().peekable(); while let Some(c) = chars.next() { - let preferred_quote_char = preferred_style.as_char(); + let preferred_quote_char = preferred_quote.as_char(); match c { '\\' => { if matches!(chars.peek(), Some('"' | '\\')) { @@ -637,9 +641,9 @@ fn choose_quotes(input: &str, quotes: StringQuotes, preferred_style: QuoteStyle) if uses_triple_quotes { // String contains a triple quote sequence of the configured quote style. // Keep the existing quote style. - quotes.style + quotes.quote_char } else { - preferred_style + preferred_quote } } else { let mut single_quotes = 0u32; @@ -659,19 +663,19 @@ fn choose_quotes(input: &str, quotes: StringQuotes, preferred_style: QuoteStyle) } } - match preferred_style { - QuoteStyle::Single => { + match preferred_quote { + QuoteChar::Single => { if single_quotes > double_quotes { - QuoteStyle::Double + QuoteChar::Double } else { - QuoteStyle::Single + QuoteChar::Single } } - QuoteStyle::Double => { + QuoteChar::Double => { if double_quotes > single_quotes { - QuoteStyle::Single + QuoteChar::Single } else { - QuoteStyle::Double + QuoteChar::Double } } } @@ -679,14 +683,14 @@ fn choose_quotes(input: &str, quotes: StringQuotes, preferred_style: QuoteStyle) StringQuotes { triple: quotes.triple, - style, + quote_char: quote, } } #[derive(Copy, Clone, Debug)] pub(super) struct StringQuotes { triple: bool, - style: QuoteStyle, + quote_char: QuoteChar, } impl StringQuotes { @@ -694,11 +698,14 @@ impl StringQuotes { let mut chars = input.chars(); let quote_char = chars.next()?; - let style = QuoteStyle::try_from(quote_char).ok()?; + let quote = QuoteChar::try_from(quote_char).ok()?; let triple = chars.next() == Some(quote_char) && chars.next() == Some(quote_char); - Some(Self { triple, style }) + Some(Self { + triple, + quote_char: quote, + }) } pub(super) const fn is_triple(self) -> bool { @@ -716,17 +723,74 @@ impl StringQuotes { impl Format> for StringQuotes { fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { - let quotes = match (self.style, self.triple) { - (QuoteStyle::Single, false) => "'", - (QuoteStyle::Single, true) => "'''", - (QuoteStyle::Double, false) => "\"", - (QuoteStyle::Double, true) => "\"\"\"", + let quotes = match (self.quote_char, self.triple) { + (QuoteChar::Single, false) => "'", + (QuoteChar::Single, true) => "'''", + (QuoteChar::Double, false) => "\"", + (QuoteChar::Double, true) => "\"\"\"", }; token(quotes).fmt(f) } } +/// The quotation character used to quote a string, byte, or fstring literal. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum QuoteChar { + /// A single quote: `'` + Single, + + /// A double quote: '"' + Double, +} + +impl QuoteChar { + pub const fn as_char(self) -> char { + match self { + QuoteChar::Single => '\'', + QuoteChar::Double => '"', + } + } + + #[must_use] + pub const fn invert(self) -> QuoteChar { + match self { + QuoteChar::Single => QuoteChar::Double, + QuoteChar::Double => QuoteChar::Single, + } + } + + #[must_use] + pub const fn from_style(style: QuoteStyle) -> Option { + match style { + QuoteStyle::Single => Some(QuoteChar::Single), + QuoteStyle::Double => Some(QuoteChar::Double), + QuoteStyle::Preserve => None, + } + } +} + +impl From for QuoteStyle { + fn from(value: QuoteChar) -> Self { + match value { + QuoteChar::Single => QuoteStyle::Single, + QuoteChar::Double => QuoteStyle::Double, + } + } +} + +impl TryFrom for QuoteChar { + type Error = (); + + fn try_from(value: char) -> Result { + match value { + '\'' => Ok(QuoteChar::Single), + '"' => Ok(QuoteChar::Double), + _ => Err(()), + } + } +} + /// Adds the necessary quote escapes and removes unnecessary escape sequences when quoting `input` /// with the provided [`StringQuotes`] style. /// @@ -739,9 +803,9 @@ fn normalize_string(input: &str, quotes: StringQuotes, prefix: StringPrefix) -> // If `last_index` is `0` at the end, then the input is already normalized and can be returned as is. let mut last_index = 0; - let style = quotes.style; - let preferred_quote = style.as_char(); - let opposite_quote = style.invert().as_char(); + let quote = quotes.quote_char; + let preferred_quote = quote.as_char(); + let opposite_quote = quote.invert().as_char(); let mut chars = input.char_indices().peekable(); diff --git a/crates/ruff_python_formatter/src/options.rs b/crates/ruff_python_formatter/src/options.rs index a07fabbb9a795..8ff979959cfe5 100644 --- a/crates/ruff_python_formatter/src/options.rs +++ b/crates/ruff_python_formatter/src/options.rs @@ -207,35 +207,7 @@ pub enum QuoteStyle { Single, #[default] Double, -} - -impl QuoteStyle { - pub const fn as_char(self) -> char { - match self { - QuoteStyle::Single => '\'', - QuoteStyle::Double => '"', - } - } - - #[must_use] - pub const fn invert(self) -> QuoteStyle { - match self { - QuoteStyle::Single => QuoteStyle::Double, - QuoteStyle::Double => QuoteStyle::Single, - } - } -} - -impl TryFrom for QuoteStyle { - type Error = (); - - fn try_from(value: char) -> std::result::Result { - match value { - '\'' => Ok(QuoteStyle::Single), - '"' => Ok(QuoteStyle::Double), - _ => Err(()), - } - } + Preserve, } impl FromStr for QuoteStyle { @@ -245,6 +217,7 @@ impl FromStr for QuoteStyle { match s { "\"" | "double" | "Double" => Ok(Self::Double), "'" | "single" | "Single" => Ok(Self::Single), + "preserve" | "Preserve" => Ok(Self::Preserve), // TODO: replace this error with a diagnostic _ => Err("Value not supported for QuoteStyle"), } diff --git a/crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap new file mode 100644 index 0000000000000..b78c7666e9636 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap @@ -0,0 +1,270 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/quote_style.py +--- +## Input +```python +'single' +"double" +r'r single' +r"r double" +f'f single' +f"f double" +fr'fr single' +fr"fr double" +rf'rf single' +rf"rf double" +b'b single' +b"b double" +rb'rb single' +rb"rb double" +br'br single' +br"br double" + +'''single triple''' +"""double triple""" +r'''r single triple''' +r"""r double triple""" +f'''f single triple''' +f"""f double triple""" +fr'''fr single triple''' +fr"""fr double triple""" +rf'''rf single triple''' +rf"""rf double triple""" +b'''b single triple''' +b"""b double triple""" +rb'''rb single triple''' +rb"""rb double triple""" +br'''br single triple''' +br"""br double triple""" + +'single1' 'single2' +'single1' "double2" +"double1" 'single2' +"double1" "double2" + +def docstring_single_triple(): + '''single triple''' + +def docstring_double_triple(): + """double triple""" + +def docstring_double(): + "double triple" + +def docstring_single(): + 'single' +``` + +## Outputs +### Output 1 +``` +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Single +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +preview = Disabled +``` + +```python +'single' +'double' +r'r single' +r'r double' +f'f single' +f'f double' +rf'fr single' +rf'fr double' +rf'rf single' +rf'rf double' +b'b single' +b'b double' +rb'rb single' +rb'rb double' +rb'br single' +rb'br double' + +"""single triple""" +"""double triple""" +r"""r single triple""" +r"""r double triple""" +f"""f single triple""" +f"""f double triple""" +rf"""fr single triple""" +rf"""fr double triple""" +rf"""rf single triple""" +rf"""rf double triple""" +b"""b single triple""" +b"""b double triple""" +rb"""rb single triple""" +rb"""rb double triple""" +rb"""br single triple""" +rb"""br double triple""" + +'single1' 'single2' +'single1' 'double2' +'double1' 'single2' +'double1' 'double2' + + +def docstring_single_triple(): + """single triple""" + + +def docstring_double_triple(): + """double triple""" + + +def docstring_double(): + "double triple" + + +def docstring_single(): + "single" +``` + + +### Output 2 +``` +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +preview = Disabled +``` + +```python +"single" +"double" +r"r single" +r"r double" +f"f single" +f"f double" +rf"fr single" +rf"fr double" +rf"rf single" +rf"rf double" +b"b single" +b"b double" +rb"rb single" +rb"rb double" +rb"br single" +rb"br double" + +"""single triple""" +"""double triple""" +r"""r single triple""" +r"""r double triple""" +f"""f single triple""" +f"""f double triple""" +rf"""fr single triple""" +rf"""fr double triple""" +rf"""rf single triple""" +rf"""rf double triple""" +b"""b single triple""" +b"""b double triple""" +rb"""rb single triple""" +rb"""rb double triple""" +rb"""br single triple""" +rb"""br double triple""" + +"single1" "single2" +"single1" "double2" +"double1" "single2" +"double1" "double2" + + +def docstring_single_triple(): + """single triple""" + + +def docstring_double_triple(): + """double triple""" + + +def docstring_double(): + "double triple" + + +def docstring_single(): + "single" +``` + + +### Output 3 +``` +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Preserve +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +preview = Disabled +``` + +```python +'single' +"double" +r'r single' +r"r double" +f'f single' +f"f double" +rf'fr single' +rf"fr double" +rf'rf single' +rf"rf double" +b'b single' +b"b double" +rb'rb single' +rb"rb double" +rb'br single' +rb"br double" + +"""single triple""" +"""double triple""" +r"""r single triple""" +r"""r double triple""" +f"""f single triple""" +f"""f double triple""" +rf"""fr single triple""" +rf"""fr double triple""" +rf"""rf single triple""" +rf"""rf double triple""" +b"""b single triple""" +b"""b double triple""" +rb"""rb single triple""" +rb"""rb double triple""" +rb"""br single triple""" +rb"""br double triple""" + +'single1' 'single2' +'single1' "double2" +"double1" 'single2' +"double1" "double2" + + +def docstring_single_triple(): + """single triple""" + + +def docstring_double_triple(): + """double triple""" + + +def docstring_double(): + "double triple" + + +def docstring_single(): + "single" +``` + + + diff --git a/crates/ruff_workspace/src/configuration.rs b/crates/ruff_workspace/src/configuration.rs index 4c38249b0e5dc..6b3e2abbc45a1 100644 --- a/crates/ruff_workspace/src/configuration.rs +++ b/crates/ruff_workspace/src/configuration.rs @@ -158,12 +158,21 @@ impl Configuration { let format = self.format; let format_defaults = FormatterSettings::default(); + let quote_style = format.quote_style.unwrap_or(format_defaults.quote_style); + let format_preview = match format.preview.unwrap_or(global_preview) { + PreviewMode::Disabled => ruff_python_formatter::PreviewMode::Disabled, + PreviewMode::Enabled => ruff_python_formatter::PreviewMode::Enabled, + }; + + if quote_style == QuoteStyle::Preserve && !format_preview.is_enabled() { + return Err(anyhow!( + "'quote-style = preserve' is a preview only feature. Run with '--preview' to enable it." + )); + } + let formatter = FormatterSettings { exclude: FilePatternSet::try_from_iter(format.exclude.unwrap_or_default())?, - preview: match format.preview.unwrap_or(global_preview) { - PreviewMode::Disabled => ruff_python_formatter::PreviewMode::Disabled, - PreviewMode::Enabled => ruff_python_formatter::PreviewMode::Enabled, - }, + preview: format_preview, line_width: self .line_length .map_or(format_defaults.line_width, |length| { @@ -176,7 +185,7 @@ impl Configuration { .map_or(format_defaults.indent_width, |tab_size| { ruff_formatter::IndentWidth::from(NonZeroU8::from(tab_size)) }), - quote_style: format.quote_style.unwrap_or(format_defaults.quote_style), + quote_style, magic_trailing_comma: format .magic_trailing_comma .unwrap_or(format_defaults.magic_trailing_comma), diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index 1d8386d80ab1d..be92ddcf1634a 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -2819,13 +2819,18 @@ pub struct FormatOptions { )] pub indent_style: Option, - /// Whether to prefer single `'` or double `"` quotes for strings. Defaults to double quotes. + /// Configures the preferred quote character for strings. Valid options are: + /// + /// * `double` (default): Use double quotes `"` + /// * `single`: Use single quotes `'` + /// * `preserve` (preview only): Keeps the existing quote character. We don't recommend using this option except for projects + /// that already use a mixture of single and double quotes and can't migrate to using double or single quotes. /// /// In compliance with [PEP 8](https://peps.python.org/pep-0008/) and [PEP 257](https://peps.python.org/pep-0257/), /// Ruff prefers double quotes for multiline strings and docstrings, regardless of the /// configured quote style. /// - /// Ruff may also deviate from this option if using the configured quotes would require + /// Ruff may also deviate from using the configured quotes if doing so requires /// escaping quote characters within the string. For example, given: /// /// ```python @@ -2834,11 +2839,11 @@ pub struct FormatOptions { /// ``` /// /// Ruff will change `a` to use single quotes when using `quote-style = "single"`. However, - /// `b` will be unchanged, as converting to single quotes would require the inner `'` to be - /// escaped, which leads to less readable code: `'It\'s monday morning'`. + /// `b` remains unchanged, as converting to single quotes requires escaping the inner `'`, + /// which leads to less readable code: `'It\'s monday morning'`. This does not apply when using `preserve`. #[option( default = r#"double"#, - value_type = r#""double" | "single""#, + value_type = r#""double" | "single" | "preserve""#, example = r#" # Prefer single quotes over double quotes. quote-style = "single" diff --git a/ruff.schema.json b/ruff.schema.json index 3bd21232a2551..90228a59020d0 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -1281,7 +1281,7 @@ ] }, "quote-style": { - "description": "Whether to prefer single `'` or double `\"` quotes for strings. Defaults to double quotes.\n\nIn compliance with [PEP 8](https://peps.python.org/pep-0008/) and [PEP 257](https://peps.python.org/pep-0257/), Ruff prefers double quotes for multiline strings and docstrings, regardless of the configured quote style.\n\nRuff may also deviate from this option if using the configured quotes would require escaping quote characters within the string. For example, given:\n\n```python a = \"a string without any quotes\" b = \"It's monday morning\" ```\n\nRuff will change `a` to use single quotes when using `quote-style = \"single\"`. However, `b` will be unchanged, as converting to single quotes would require the inner `'` to be escaped, which leads to less readable code: `'It\\'s monday morning'`.", + "description": "Configures the preferred quote character for strings. Valid options are:\n\n* `double` (default): Use double quotes `\"` * `single`: Use single quotes `'` * `preserve` (preview only): Keeps the existing quote character. We don't recommend using this option except for projects that already use a mixture of single and double quotes and can't migrate to using double or single quotes.\n\nIn compliance with [PEP 8](https://peps.python.org/pep-0008/) and [PEP 257](https://peps.python.org/pep-0257/), Ruff prefers double quotes for multiline strings and docstrings, regardless of the configured quote style.\n\nRuff may also deviate from using the configured quotes if doing so requires escaping quote characters within the string. For example, given:\n\n```python a = \"a string without any quotes\" b = \"It's monday morning\" ```\n\nRuff will change `a` to use single quotes when using `quote-style = \"single\"`. However, `b` remains unchanged, as converting to single quotes requires escaping the inner `'`, which leads to less readable code: `'It\\'s monday morning'`. This does not apply when using `preserve`.", "anyOf": [ { "$ref": "#/definitions/QuoteStyle" @@ -2441,7 +2441,8 @@ "type": "string", "enum": [ "single", - "double" + "double", + "preserve" ] }, "RelativeImportsOrder": { From a224f1990331fea5506455d3706468788412ea12 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Thu, 7 Dec 2023 19:52:14 -0500 Subject: [PATCH 142/197] ruff_python_formatter: add test for extraneous info string text (#9050) @ofek asked [about this][ref]. I did specifically add support for it, but neglected to add a test. This PR adds a test. [ref]: https://github.com/astral-sh/ruff/pull/9030#issuecomment-1846054764 --- .../fixtures/ruff/docstring_code_examples.py | 14 ++ .../format@docstring_code_examples.py.snap | 126 ++++++++++++++++++ 2 files changed, 140 insertions(+) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py index 68c7a528a6cf8..381f04b757adf 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py @@ -1195,6 +1195,20 @@ def markdown_over_indented(): pass +# This tests that we can have additional text after the language specifier. +def markdown_additional_info_string(): + """ + Do cool stuff. + + ```python tab="plugin.py" + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + # Tests that an unclosed block gobbles up everything remaining in the # docstring, even if it isn't valid Python. Since it isn't valid Python, # reformatting fails and the entire thing is skipped. diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap index 7dc1badfe2b8a..ce33622b634f1 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap @@ -1201,6 +1201,20 @@ def markdown_over_indented(): pass +# This tests that we can have additional text after the language specifier. +def markdown_additional_info_string(): + """ + Do cool stuff. + + ```python tab="plugin.py" + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + # Tests that an unclosed block gobbles up everything remaining in the # docstring, even if it isn't valid Python. Since it isn't valid Python, # reformatting fails and the entire thing is skipped. @@ -2556,6 +2570,20 @@ def markdown_over_indented(): pass +# This tests that we can have additional text after the language specifier. +def markdown_additional_info_string(): + """ + Do cool stuff. + + ```python tab="plugin.py" + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + # Tests that an unclosed block gobbles up everything remaining in the # docstring, even if it isn't valid Python. Since it isn't valid Python, # reformatting fails and the entire thing is skipped. @@ -3911,6 +3939,20 @@ def markdown_over_indented(): pass +# This tests that we can have additional text after the language specifier. +def markdown_additional_info_string(): + """ + Do cool stuff. + + ```python tab="plugin.py" + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + # Tests that an unclosed block gobbles up everything remaining in the # docstring, even if it isn't valid Python. Since it isn't valid Python, # reformatting fails and the entire thing is skipped. @@ -5266,6 +5308,20 @@ def markdown_over_indented(): pass +# This tests that we can have additional text after the language specifier. +def markdown_additional_info_string(): + """ + Do cool stuff. + + ```python tab="plugin.py" + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + # Tests that an unclosed block gobbles up everything remaining in the # docstring, even if it isn't valid Python. Since it isn't valid Python, # reformatting fails and the entire thing is skipped. @@ -6621,6 +6677,20 @@ def markdown_over_indented(): pass +# This tests that we can have additional text after the language specifier. +def markdown_additional_info_string(): + """ + Do cool stuff. + + ```python tab="plugin.py" + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + # Tests that an unclosed block gobbles up everything remaining in the # docstring, even if it isn't valid Python. Since it isn't valid Python, # reformatting fails and the entire thing is skipped. @@ -7971,6 +8041,20 @@ def markdown_over_indented(): pass +# This tests that we can have additional text after the language specifier. +def markdown_additional_info_string(): + """ + Do cool stuff. + + ```python tab="plugin.py" + cool_stuff(1) + ``` + + Done. + """ + pass + + # Tests that an unclosed block gobbles up everything remaining in the # docstring, even if it isn't valid Python. Since it isn't valid Python, # reformatting fails and the entire thing is skipped. @@ -9321,6 +9405,20 @@ def markdown_over_indented(): pass +# This tests that we can have additional text after the language specifier. +def markdown_additional_info_string(): + """ + Do cool stuff. + + ```python tab="plugin.py" + cool_stuff(1) + ``` + + Done. + """ + pass + + # Tests that an unclosed block gobbles up everything remaining in the # docstring, even if it isn't valid Python. Since it isn't valid Python, # reformatting fails and the entire thing is skipped. @@ -10671,6 +10769,20 @@ def markdown_over_indented(): pass +# This tests that we can have additional text after the language specifier. +def markdown_additional_info_string(): + """ + Do cool stuff. + + ```python tab="plugin.py" + cool_stuff(1) + ``` + + Done. + """ + pass + + # Tests that an unclosed block gobbles up everything remaining in the # docstring, even if it isn't valid Python. Since it isn't valid Python, # reformatting fails and the entire thing is skipped. @@ -12021,6 +12133,20 @@ def markdown_over_indented(): pass +# This tests that we can have additional text after the language specifier. +def markdown_additional_info_string(): + """ + Do cool stuff. + + ```python tab="plugin.py" + cool_stuff(1) + ``` + + Done. + """ + pass + + # Tests that an unclosed block gobbles up everything remaining in the # docstring, even if it isn't valid Python. Since it isn't valid Python, # reformatting fails and the entire thing is skipped. From d0d88d9375080daad369564d5c8a970225cc08a7 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Fri, 8 Dec 2023 14:00:36 +0900 Subject: [PATCH 143/197] Fix handling of trailing target comment (#9051) --- .../test/fixtures/ruff/statement/assign.py | 9 +++++++++ .../src/statement/stmt_assign.rs | 2 +- .../snapshots/format@statement__assign.py.snap | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/assign.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/assign.py index 36022ddd7f979..e70ab7c9a604a 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/assign.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/assign.py @@ -67,3 +67,12 @@ def main() -> None: db_request.POST["name"] ) )[0] + + +c = b[dddddd, aaaaaa] = ( + a[ + aaaaaaa, + bbbbbbbbbbbbbbbbbbb + ] + # comment +) = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx diff --git a/crates/ruff_python_formatter/src/statement/stmt_assign.rs b/crates/ruff_python_formatter/src/statement/stmt_assign.rs index 5044e450bbee0..a183e4e2ada25 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_assign.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_assign.rs @@ -69,7 +69,7 @@ impl Format> for FormatTargets<'_> { if let Some((first, rest)) = self.targets.split_first() { let comments = f.context().comments(); - let parenthesize = if comments.has_leading(first) { + let parenthesize = if comments.has_leading(first) || comments.has_trailing(first) { ParenthesizeTarget::Always } else if has_own_parentheses(first, f.context()).is_some() { ParenthesizeTarget::Never diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__assign.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__assign.py.snap index 075824ab64f32..203d43b643802 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__assign.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__assign.py.snap @@ -73,6 +73,15 @@ def main() -> None: db_request.POST["name"] ) )[0] + + +c = b[dddddd, aaaaaa] = ( + a[ + aaaaaaa, + bbbbbbbbbbbbbbbbbbb + ] + # comment +) = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` ## Output @@ -151,6 +160,12 @@ def main() -> None: db_request.POST["name"] ) )[0] + + +c = b[dddddd, aaaaaa] = ( + a[aaaaaaa, bbbbbbbbbbbbbbbbbbb] + # comment +) = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` From e043bd46b56d9184c764ddc00604d39f17e73a3c Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 8 Dec 2023 12:42:18 -0500 Subject: [PATCH 144/197] Make `math-constant` rule more targeted (#9054) ## Summary We now only flag `math.pi` if the value is in `[3.14, 3.15)`, and apply similar rules to the other constants. Closes https://github.com/astral-sh/ruff/issues/9049. --- .../resources/test/fixtures/refurb/FURB152.py | 8 +++ .../src/rules/refurb/rules/math_constant.rs | 58 +++++++++++++------ ...es__refurb__tests__FURB152_FURB152.py.snap | 57 ++++++++++++++++++ 3 files changed, 106 insertions(+), 17 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/refurb/FURB152.py b/crates/ruff_linter/resources/test/fixtures/refurb/FURB152.py index 5e1bfbb16640d..e9339a86fcd3d 100644 --- a/crates/ruff_linter/resources/test/fixtures/refurb/FURB152.py +++ b/crates/ruff_linter/resources/test/fixtures/refurb/FURB152.py @@ -5,3 +5,11 @@ C = 6.28 * r # FURB152 e = 2.71 # FURB152 + +r = 3.15 # OK + +r = 3.141 # FURB152 + +r = 3.1415 # FURB152 + +e = 2.7 # OK diff --git a/crates/ruff_linter/src/rules/refurb/rules/math_constant.rs b/crates/ruff_linter/src/rules/refurb/rules/math_constant.rs index 6b590275a38ba..23ef1aa8c1d21 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/math_constant.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/math_constant.rs @@ -53,23 +53,17 @@ pub(crate) fn math_constant(checker: &mut Checker, literal: &ast::ExprNumberLite let Number::Float(value) = literal.value else { return; }; - for (real_value, constant) in [ - (std::f64::consts::PI, "pi"), - (std::f64::consts::E, "e"), - (std::f64::consts::TAU, "tau"), - ] { - if (value - real_value).abs() < 1e-2 { - let mut diagnostic = Diagnostic::new( - MathConstant { - literal: checker.locator().slice(literal).into(), - constant, - }, - literal.range(), - ); - diagnostic.try_set_fix(|| convert_to_constant(literal, constant, checker)); - checker.diagnostics.push(diagnostic); - return; - } + + if let Some(constant) = Constant::from_value(value) { + let mut diagnostic = Diagnostic::new( + MathConstant { + literal: checker.locator().slice(literal).into(), + constant: constant.name(), + }, + literal.range(), + ); + diagnostic.try_set_fix(|| convert_to_constant(literal, constant.name(), checker)); + checker.diagnostics.push(diagnostic); } } @@ -88,3 +82,33 @@ fn convert_to_constant( [edit], )) } + +#[derive(Debug, Clone, Copy)] +enum Constant { + Pi, + E, + Tau, +} + +impl Constant { + #[allow(clippy::approx_constant)] + fn from_value(value: f64) -> Option { + if (3.14..3.15).contains(&value) { + Some(Self::Pi) + } else if (2.71..2.72).contains(&value) { + Some(Self::E) + } else if (6.28..6.29).contains(&value) { + Some(Self::Tau) + } else { + None + } + } + + fn name(self) -> &'static str { + match self { + Constant::Pi => "pi", + Constant::E => "e", + Constant::Tau => "tau", + } + } +} diff --git a/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB152_FURB152.py.snap b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB152_FURB152.py.snap index aa97aead864cb..094f30df73e58 100644 --- a/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB152_FURB152.py.snap +++ b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB152_FURB152.py.snap @@ -43,6 +43,7 @@ FURB152.py:5:5: FURB152 [*] Replace `6.28` with `math.tau` 6 |+C = math.tau * r # FURB152 6 7 | 7 8 | e = 2.71 # FURB152 +8 9 | FURB152.py:7:5: FURB152 [*] Replace `2.71` with `math.e` | @@ -50,6 +51,8 @@ FURB152.py:7:5: FURB152 [*] Replace `2.71` with `math.e` 6 | 7 | e = 2.71 # FURB152 | ^^^^ FURB152 +8 | +9 | r = 3.15 # OK | = help: Use `math.e` @@ -63,5 +66,59 @@ FURB152.py:7:5: FURB152 [*] Replace `2.71` with `math.e` 6 7 | 7 |-e = 2.71 # FURB152 8 |+e = math.e # FURB152 +8 9 | +9 10 | r = 3.15 # OK +10 11 | + +FURB152.py:11:5: FURB152 [*] Replace `3.141` with `math.pi` + | + 9 | r = 3.15 # OK +10 | +11 | r = 3.141 # FURB152 + | ^^^^^ FURB152 +12 | +13 | r = 3.1415 # FURB152 + | + = help: Use `math.pi` + +ℹ Safe fix + 1 |+import math +1 2 | r = 3.1 # OK +2 3 | +3 4 | A = 3.14 * r ** 2 # FURB152 +-------------------------------------------------------------------------------- +8 9 | +9 10 | r = 3.15 # OK +10 11 | +11 |-r = 3.141 # FURB152 + 12 |+r = math.pi # FURB152 +12 13 | +13 14 | r = 3.1415 # FURB152 +14 15 | + +FURB152.py:13:5: FURB152 [*] Replace `3.1415` with `math.pi` + | +11 | r = 3.141 # FURB152 +12 | +13 | r = 3.1415 # FURB152 + | ^^^^^^ FURB152 +14 | +15 | e = 2.7 # OK + | + = help: Use `math.pi` + +ℹ Safe fix + 1 |+import math +1 2 | r = 3.1 # OK +2 3 | +3 4 | A = 3.14 * r ** 2 # FURB152 +-------------------------------------------------------------------------------- +10 11 | +11 12 | r = 3.141 # FURB152 +12 13 | +13 |-r = 3.1415 # FURB152 + 14 |+r = math.pi # FURB152 +14 15 | +15 16 | e = 2.7 # OK From b7dd2b59416ec1f388b868371b8d70d455b66f3a Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Fri, 8 Dec 2023 15:16:15 -0600 Subject: [PATCH 145/197] Allow `EM` fixes even if `msg` variable is defined (#9059) This PR updates the `EM` rules to generate the auto-fix even if the `msg` variable is defined in the current scope. As discussed in https://github.com/astral-sh/ruff/issues/9052. --- .../test/fixtures/flake8_errmsg/EM.py | 2 +- .../rules/string_in_exception.rs | 48 ++++++++----------- ...__rules__flake8_errmsg__tests__custom.snap | 28 +++++++++-- ...rules__flake8_errmsg__tests__defaults.snap | 28 +++++++++-- 4 files changed, 72 insertions(+), 34 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_errmsg/EM.py b/crates/ruff_linter/resources/test/fixtures/flake8_errmsg/EM.py index 01e53ac3ddedd..fbf6eb464aa24 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_errmsg/EM.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_errmsg/EM.py @@ -27,7 +27,7 @@ def f_ok(): raise RuntimeError(msg) -def f_unfixable(): +def f_msg_defined(): msg = "hello" raise RuntimeError("This is an example exception") diff --git a/crates/ruff_linter/src/rules/flake8_errmsg/rules/string_in_exception.rs b/crates/ruff_linter/src/rules/flake8_errmsg/rules/string_in_exception.rs index 173e60078977b..a7298ea73c439 100644 --- a/crates/ruff_linter/src/rules/flake8_errmsg/rules/string_in_exception.rs +++ b/crates/ruff_linter/src/rules/flake8_errmsg/rules/string_in_exception.rs @@ -191,15 +191,13 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr if let Some(indentation) = whitespace::indentation(checker.locator(), stmt) { - if checker.semantic().is_available("msg") { - diagnostic.set_fix(generate_fix( - stmt, - first, - indentation, - checker.stylist(), - checker.locator(), - )); - } + diagnostic.set_fix(generate_fix( + stmt, + first, + indentation, + checker.stylist(), + checker.locator(), + )); } checker.diagnostics.push(diagnostic); } @@ -211,15 +209,13 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr let mut diagnostic = Diagnostic::new(FStringInException, first.range()); if let Some(indentation) = whitespace::indentation(checker.locator(), stmt) { - if checker.semantic().is_available("msg") { - diagnostic.set_fix(generate_fix( - stmt, - first, - indentation, - checker.stylist(), - checker.locator(), - )); - } + diagnostic.set_fix(generate_fix( + stmt, + first, + indentation, + checker.stylist(), + checker.locator(), + )); } checker.diagnostics.push(diagnostic); } @@ -236,15 +232,13 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr if let Some(indentation) = whitespace::indentation(checker.locator(), stmt) { - if checker.semantic().is_available("msg") { - diagnostic.set_fix(generate_fix( - stmt, - first, - indentation, - checker.stylist(), - checker.locator(), - )); - } + diagnostic.set_fix(generate_fix( + stmt, + first, + indentation, + checker.stylist(), + checker.locator(), + )); } checker.diagnostics.push(diagnostic); } diff --git a/crates/ruff_linter/src/rules/flake8_errmsg/snapshots/ruff_linter__rules__flake8_errmsg__tests__custom.snap b/crates/ruff_linter/src/rules/flake8_errmsg/snapshots/ruff_linter__rules__flake8_errmsg__tests__custom.snap index 92912b35e263b..d29e987d4952a 100644 --- a/crates/ruff_linter/src/rules/flake8_errmsg/snapshots/ruff_linter__rules__flake8_errmsg__tests__custom.snap +++ b/crates/ruff_linter/src/rules/flake8_errmsg/snapshots/ruff_linter__rules__flake8_errmsg__tests__custom.snap @@ -59,15 +59,26 @@ EM.py:22:24: EM103 [*] Exception must not use a `.format()` string directly, ass 24 25 | 25 26 | def f_ok(): -EM.py:32:24: EM101 Exception must not use a string literal, assign to variable first +EM.py:32:24: EM101 [*] Exception must not use a string literal, assign to variable first | -30 | def f_unfixable(): +30 | def f_msg_defined(): 31 | msg = "hello" 32 | raise RuntimeError("This is an example exception") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM101 | = help: Assign to variable; remove string literal +ℹ Unsafe fix +29 29 | +30 30 | def f_msg_defined(): +31 31 | msg = "hello" +32 |- raise RuntimeError("This is an example exception") + 32 |+ msg = "This is an example exception" + 33 |+ raise RuntimeError(msg) +33 34 | +34 35 | +35 36 | def f_msg_in_nested_scope(): + EM.py:39:24: EM101 [*] Exception must not use a string literal, assign to variable first | 37 | msg = "hello" @@ -88,7 +99,7 @@ EM.py:39:24: EM101 [*] Exception must not use a string literal, assign to variab 41 42 | 42 43 | def f_msg_in_parent_scope(): -EM.py:46:28: EM101 Exception must not use a string literal, assign to variable first +EM.py:46:28: EM101 [*] Exception must not use a string literal, assign to variable first | 45 | def nested(): 46 | raise RuntimeError("This is an example exception") @@ -96,6 +107,17 @@ EM.py:46:28: EM101 Exception must not use a string literal, assign to variable f | = help: Assign to variable; remove string literal +ℹ Unsafe fix +43 43 | msg = "hello" +44 44 | +45 45 | def nested(): +46 |- raise RuntimeError("This is an example exception") + 46 |+ msg = "This is an example exception" + 47 |+ raise RuntimeError(msg) +47 48 | +48 49 | +49 50 | def f_fix_indentation_check(foo): + EM.py:51:28: EM101 [*] Exception must not use a string literal, assign to variable first | 49 | def f_fix_indentation_check(foo): diff --git a/crates/ruff_linter/src/rules/flake8_errmsg/snapshots/ruff_linter__rules__flake8_errmsg__tests__defaults.snap b/crates/ruff_linter/src/rules/flake8_errmsg/snapshots/ruff_linter__rules__flake8_errmsg__tests__defaults.snap index a50458f892404..593d6b30dcc0e 100644 --- a/crates/ruff_linter/src/rules/flake8_errmsg/snapshots/ruff_linter__rules__flake8_errmsg__tests__defaults.snap +++ b/crates/ruff_linter/src/rules/flake8_errmsg/snapshots/ruff_linter__rules__flake8_errmsg__tests__defaults.snap @@ -97,15 +97,26 @@ EM.py:22:24: EM103 [*] Exception must not use a `.format()` string directly, ass 24 25 | 25 26 | def f_ok(): -EM.py:32:24: EM101 Exception must not use a string literal, assign to variable first +EM.py:32:24: EM101 [*] Exception must not use a string literal, assign to variable first | -30 | def f_unfixable(): +30 | def f_msg_defined(): 31 | msg = "hello" 32 | raise RuntimeError("This is an example exception") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM101 | = help: Assign to variable; remove string literal +ℹ Unsafe fix +29 29 | +30 30 | def f_msg_defined(): +31 31 | msg = "hello" +32 |- raise RuntimeError("This is an example exception") + 32 |+ msg = "This is an example exception" + 33 |+ raise RuntimeError(msg) +33 34 | +34 35 | +35 36 | def f_msg_in_nested_scope(): + EM.py:39:24: EM101 [*] Exception must not use a string literal, assign to variable first | 37 | msg = "hello" @@ -126,7 +137,7 @@ EM.py:39:24: EM101 [*] Exception must not use a string literal, assign to variab 41 42 | 42 43 | def f_msg_in_parent_scope(): -EM.py:46:28: EM101 Exception must not use a string literal, assign to variable first +EM.py:46:28: EM101 [*] Exception must not use a string literal, assign to variable first | 45 | def nested(): 46 | raise RuntimeError("This is an example exception") @@ -134,6 +145,17 @@ EM.py:46:28: EM101 Exception must not use a string literal, assign to variable f | = help: Assign to variable; remove string literal +ℹ Unsafe fix +43 43 | msg = "hello" +44 44 | +45 45 | def nested(): +46 |- raise RuntimeError("This is an example exception") + 46 |+ msg = "This is an example exception" + 47 |+ raise RuntimeError(msg) +47 48 | +48 49 | +49 50 | def f_fix_indentation_check(foo): + EM.py:51:28: EM101 [*] Exception must not use a string literal, assign to variable first | 49 | def f_fix_indentation_check(foo): From 20e33bf5147a027e1d0d4ef28f88cfb5b3916efe Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 8 Dec 2023 22:59:05 -0500 Subject: [PATCH 146/197] Allow class names when `apps.get_model` is a non-string (#9065) See: https://github.com/astral-sh/ruff/issues/7675#issuecomment-1848206022 --- .../resources/test/fixtures/pep8_naming/N806.py | 3 +++ crates/ruff_linter/src/rules/pep8_naming/helpers.rs | 10 ++++++++-- ...inter__rules__pep8_naming__tests__N806_N806.py.snap | 9 +++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py b/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py index d3a0585cb46a1..80114331302d5 100644 --- a/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py +++ b/crates/ruff_linter/resources/test/fixtures/pep8_naming/N806.py @@ -55,3 +55,6 @@ def model_assign() -> None: Bad = apps.get_model() # N806 Bad = apps.get_model(model_name="Stream") # N806 + + Address: Type = apps.get_model("zerver", variable) # OK + ValidationError = import_string(variable) # N806 diff --git a/crates/ruff_linter/src/rules/pep8_naming/helpers.rs b/crates/ruff_linter/src/rules/pep8_naming/helpers.rs index 00ad10b77f4da..b48388935cfff 100644 --- a/crates/ruff_linter/src/rules/pep8_naming/helpers.rs +++ b/crates/ruff_linter/src/rules/pep8_naming/helpers.rs @@ -112,7 +112,11 @@ pub(super) fn is_django_model_import(name: &str, stmt: &Stmt, semantic: &Semanti arguments.find_argument("model_name", arguments.args.len().saturating_sub(1)) { if let Some(string_literal) = argument.as_string_literal_expr() { - return string_literal.value.to_str() == name; + if string_literal.value.to_str() == name { + return true; + } + } else { + return true; } } } @@ -127,7 +131,9 @@ pub(super) fn is_django_model_import(name: &str, stmt: &Stmt, semantic: &Semanti if let Some(argument) = arguments.find_argument("dotted_path", 0) { if let Some(string_literal) = argument.as_string_literal_expr() { if let Some((.., model)) = string_literal.value.to_str().rsplit_once('.') { - return model == name; + if model == name { + return true; + } } } } diff --git a/crates/ruff_linter/src/rules/pep8_naming/snapshots/ruff_linter__rules__pep8_naming__tests__N806_N806.py.snap b/crates/ruff_linter/src/rules/pep8_naming/snapshots/ruff_linter__rules__pep8_naming__tests__N806_N806.py.snap index d53fb46f9df72..1baa39c61040b 100644 --- a/crates/ruff_linter/src/rules/pep8_naming/snapshots/ruff_linter__rules__pep8_naming__tests__N806_N806.py.snap +++ b/crates/ruff_linter/src/rules/pep8_naming/snapshots/ruff_linter__rules__pep8_naming__tests__N806_N806.py.snap @@ -52,6 +52,15 @@ N806.py:57:5: N806 Variable `Bad` in function should be lowercase 56 | Bad = apps.get_model() # N806 57 | Bad = apps.get_model(model_name="Stream") # N806 | ^^^ N806 +58 | +59 | Address: Type = apps.get_model("zerver", variable) # OK + | + +N806.py:60:5: N806 Variable `ValidationError` in function should be lowercase + | +59 | Address: Type = apps.get_model("zerver", variable) # OK +60 | ValidationError = import_string(variable) # N806 + | ^^^^^^^^^^^^^^^ N806 | From 85fc57e7f9ff1db23ffad7098959aab9e8c15475 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sat, 9 Dec 2023 17:06:49 +0100 Subject: [PATCH 147/197] Fix typo in documentation (#9069) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fix a couple typos: - I'm certain about `It's is` → `It is`. - Not sure about `is it's` → `if it's` because I don't understand the sentence. ## Test Plan No tests. --- crates/ruff_linter/src/rules/refurb/rules/delete_full_slice.rs | 2 +- crates/ruff_python_formatter/CONTRIBUTING.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/src/rules/refurb/rules/delete_full_slice.rs b/crates/ruff_linter/src/rules/refurb/rules/delete_full_slice.rs index a6584201fcfca..1b0e610bdbe54 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/delete_full_slice.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/delete_full_slice.rs @@ -14,7 +14,7 @@ use crate::rules::refurb::helpers::generate_method_call; /// dictionary. /// /// ## Why is this bad? -/// It's is faster and more succinct to remove all items via the `clear()` +/// It is faster and more succinct to remove all items via the `clear()` /// method. /// /// ## Known problems diff --git a/crates/ruff_python_formatter/CONTRIBUTING.md b/crates/ruff_python_formatter/CONTRIBUTING.md index c302a4dc49ba8..193ff8ef32004 100644 --- a/crates/ruff_python_formatter/CONTRIBUTING.md +++ b/crates/ruff_python_formatter/CONTRIBUTING.md @@ -218,7 +218,7 @@ call, for single items `.format().fmt(f)` or `.fmt(f)` is sufficient. impl FormatNodeRule for FormatStmtReturn { fn fmt_fields(&self, item: &StmtReturn, f: &mut PyFormatter) -> FormatResult<()> { // Here we destructure item and make sure each field is listed. - // We generally don't need range is it's underscore-ignored + // We generally don't need range if it's underscore-ignored let StmtReturn { range: _, value } = item; // Implement some formatting logic, in this case no space (and no value) after a return with // no value From 829a808526e853867ee790dc4f3c1dc2b3cc87ad Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 9 Dec 2023 11:23:34 -0500 Subject: [PATCH 148/197] Upgrade `ahash` (#9071) The version we're using now was yanked. --- Cargo.lock | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f2c658a7ac7f..faa41ca9c0e6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,14 +16,15 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", "getrandom", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -3796,3 +3797,23 @@ checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" dependencies = [ "winapi", ] + +[[package]] +name = "zerocopy" +version = "0.7.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306dca4455518f1f31635ec308b6b3e4eb1b11758cefafc782827d0aa7acb5c7" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] From f69a35a021ef5394c3bc368d27723d3868585d11 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 9 Dec 2023 13:15:28 -0500 Subject: [PATCH 149/197] Add fix for unexpected-spaces-around-keyword-parameter-equals (#9072) Closes https://github.com/astral-sh/ruff/issues/9066. --- ...hitespace_around_named_parameter_equals.rs | 21 ++- ...ules__pycodestyle__tests__E251_E25.py.snap | 141 ++++++++++++++++-- 2 files changed, 147 insertions(+), 15 deletions(-) diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs index f5baea15080dc..a0c4f49bf2250 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs @@ -1,4 +1,4 @@ -use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, Violation}; +use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_parser::TokenKind; use ruff_text_size::{Ranged, TextRange, TextSize}; @@ -34,11 +34,15 @@ use crate::rules::pycodestyle::rules::logical_lines::{LogicalLine, LogicalLineTo #[violation] pub struct UnexpectedSpacesAroundKeywordParameterEquals; -impl Violation for UnexpectedSpacesAroundKeywordParameterEquals { +impl AlwaysFixableViolation for UnexpectedSpacesAroundKeywordParameterEquals { #[derive_message_formats] fn message(&self) -> String { format!("Unexpected spaces around keyword / parameter equals") } + + fn fix_title(&self) -> String { + format!("Remove whitespace") + } } /// ## What it does @@ -165,22 +169,31 @@ pub(crate) fn whitespace_around_named_parameter_equals( } } } else { + // If there's space between the preceding token and the equals sign, report it. if token.start() != prev_end { - context.push( + let mut diagnostic = Diagnostic::new( UnexpectedSpacesAroundKeywordParameterEquals, TextRange::new(prev_end, token.start()), ); + diagnostic.set_fix(Fix::safe_edit(Edit::deletion(prev_end, token.start()))); + context.push_diagnostic(diagnostic); } + // If there's space between the equals sign and the following token, report it. while let Some(next) = iter.peek() { if next.kind() == TokenKind::NonLogicalNewline { iter.next(); } else { if next.start() != token.end() { - context.push( + let mut diagnostic = Diagnostic::new( UnexpectedSpacesAroundKeywordParameterEquals, TextRange::new(token.end(), next.start()), ); + diagnostic.set_fix(Fix::safe_edit(Edit::deletion( + token.end(), + next.start(), + ))); + context.push_diagnostic(diagnostic); } break; } diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E251_E25.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E251_E25.py.snap index 88d211954bd9b..a87bcdff5586b 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E251_E25.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E251_E25.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/pycodestyle/mod.rs --- -E25.py:2:12: E251 Unexpected spaces around keyword / parameter equals +E25.py:2:12: E251 [*] Unexpected spaces around keyword / parameter equals | 1 | #: E251 E251 2 | def foo(bar = False): @@ -9,8 +9,17 @@ E25.py:2:12: E251 Unexpected spaces around keyword / parameter equals 3 | '''Test function with an error in declaration''' 4 | pass | + = help: Remove whitespace -E25.py:2:14: E251 Unexpected spaces around keyword / parameter equals +ℹ Safe fix +1 1 | #: E251 E251 +2 |-def foo(bar = False): + 2 |+def foo(bar= False): +3 3 | '''Test function with an error in declaration''' +4 4 | pass +5 5 | #: E251 + +E25.py:2:14: E251 [*] Unexpected spaces around keyword / parameter equals | 1 | #: E251 E251 2 | def foo(bar = False): @@ -18,8 +27,17 @@ E25.py:2:14: E251 Unexpected spaces around keyword / parameter equals 3 | '''Test function with an error in declaration''' 4 | pass | + = help: Remove whitespace + +ℹ Safe fix +1 1 | #: E251 E251 +2 |-def foo(bar = False): + 2 |+def foo(bar =False): +3 3 | '''Test function with an error in declaration''' +4 4 | pass +5 5 | #: E251 -E25.py:6:9: E251 Unexpected spaces around keyword / parameter equals +E25.py:6:9: E251 [*] Unexpected spaces around keyword / parameter equals | 4 | pass 5 | #: E251 @@ -28,8 +46,19 @@ E25.py:6:9: E251 Unexpected spaces around keyword / parameter equals 7 | #: E251 8 | foo(bar =True) | + = help: Remove whitespace + +ℹ Safe fix +3 3 | '''Test function with an error in declaration''' +4 4 | pass +5 5 | #: E251 +6 |-foo(bar= True) + 6 |+foo(bar=True) +7 7 | #: E251 +8 8 | foo(bar =True) +9 9 | #: E251 E251 -E25.py:8:8: E251 Unexpected spaces around keyword / parameter equals +E25.py:8:8: E251 [*] Unexpected spaces around keyword / parameter equals | 6 | foo(bar= True) 7 | #: E251 @@ -38,8 +67,19 @@ E25.py:8:8: E251 Unexpected spaces around keyword / parameter equals 9 | #: E251 E251 10 | foo(bar = True) | + = help: Remove whitespace -E25.py:10:8: E251 Unexpected spaces around keyword / parameter equals +ℹ Safe fix +5 5 | #: E251 +6 6 | foo(bar= True) +7 7 | #: E251 +8 |-foo(bar =True) + 8 |+foo(bar=True) +9 9 | #: E251 E251 +10 10 | foo(bar = True) +11 11 | #: E251 + +E25.py:10:8: E251 [*] Unexpected spaces around keyword / parameter equals | 8 | foo(bar =True) 9 | #: E251 E251 @@ -48,8 +88,19 @@ E25.py:10:8: E251 Unexpected spaces around keyword / parameter equals 11 | #: E251 12 | y = bar(root= "sdasd") | + = help: Remove whitespace + +ℹ Safe fix +7 7 | #: E251 +8 8 | foo(bar =True) +9 9 | #: E251 E251 +10 |-foo(bar = True) + 10 |+foo(bar= True) +11 11 | #: E251 +12 12 | y = bar(root= "sdasd") +13 13 | #: E251:2:29 -E25.py:10:10: E251 Unexpected spaces around keyword / parameter equals +E25.py:10:10: E251 [*] Unexpected spaces around keyword / parameter equals | 8 | foo(bar =True) 9 | #: E251 E251 @@ -58,8 +109,19 @@ E25.py:10:10: E251 Unexpected spaces around keyword / parameter equals 11 | #: E251 12 | y = bar(root= "sdasd") | + = help: Remove whitespace + +ℹ Safe fix +7 7 | #: E251 +8 8 | foo(bar =True) +9 9 | #: E251 E251 +10 |-foo(bar = True) + 10 |+foo(bar =True) +11 11 | #: E251 +12 12 | y = bar(root= "sdasd") +13 13 | #: E251:2:29 -E25.py:12:14: E251 Unexpected spaces around keyword / parameter equals +E25.py:12:14: E251 [*] Unexpected spaces around keyword / parameter equals | 10 | foo(bar = True) 11 | #: E251 @@ -68,8 +130,19 @@ E25.py:12:14: E251 Unexpected spaces around keyword / parameter equals 13 | #: E251:2:29 14 | parser.add_argument('--long-option', | + = help: Remove whitespace -E25.py:15:29: E251 Unexpected spaces around keyword / parameter equals +ℹ Safe fix +9 9 | #: E251 E251 +10 10 | foo(bar = True) +11 11 | #: E251 +12 |-y = bar(root= "sdasd") + 12 |+y = bar(root="sdasd") +13 13 | #: E251:2:29 +14 14 | parser.add_argument('--long-option', +15 15 | default= + +E25.py:15:29: E251 [*] Unexpected spaces around keyword / parameter equals | 13 | #: E251:2:29 14 | parser.add_argument('--long-option', @@ -80,8 +153,20 @@ E25.py:15:29: E251 Unexpected spaces around keyword / parameter equals 17 | #: E251:1:45 18 | parser.add_argument('--long-option', default | + = help: Remove whitespace + +ℹ Safe fix +12 12 | y = bar(root= "sdasd") +13 13 | #: E251:2:29 +14 14 | parser.add_argument('--long-option', +15 |- default= +16 |- "/rather/long/filesystem/path/here/blah/blah/blah") + 15 |+ default="/rather/long/filesystem/path/here/blah/blah/blah") +17 16 | #: E251:1:45 +18 17 | parser.add_argument('--long-option', default +19 18 | ="/rather/long/filesystem/path/here/blah/blah/blah") -E25.py:18:45: E251 Unexpected spaces around keyword / parameter equals +E25.py:18:45: E251 [*] Unexpected spaces around keyword / parameter equals | 16 | "/rather/long/filesystem/path/here/blah/blah/blah") 17 | #: E251:1:45 @@ -92,8 +177,20 @@ E25.py:18:45: E251 Unexpected spaces around keyword / parameter equals 20 | #: E251:3:8 E251:3:10 21 | foo(True, | + = help: Remove whitespace + +ℹ Safe fix +15 15 | default= +16 16 | "/rather/long/filesystem/path/here/blah/blah/blah") +17 17 | #: E251:1:45 +18 |-parser.add_argument('--long-option', default +19 |- ="/rather/long/filesystem/path/here/blah/blah/blah") + 18 |+parser.add_argument('--long-option', default="/rather/long/filesystem/path/here/blah/blah/blah") +20 19 | #: E251:3:8 E251:3:10 +21 20 | foo(True, +22 21 | baz=(1, 2), -E25.py:23:8: E251 Unexpected spaces around keyword / parameter equals +E25.py:23:8: E251 [*] Unexpected spaces around keyword / parameter equals | 21 | foo(True, 22 | baz=(1, 2), @@ -102,8 +199,19 @@ E25.py:23:8: E251 Unexpected spaces around keyword / parameter equals 24 | ) 25 | #: Okay | + = help: Remove whitespace -E25.py:23:10: E251 Unexpected spaces around keyword / parameter equals +ℹ Safe fix +20 20 | #: E251:3:8 E251:3:10 +21 21 | foo(True, +22 22 | baz=(1, 2), +23 |- biz = 'foo' + 23 |+ biz= 'foo' +24 24 | ) +25 25 | #: Okay +26 26 | foo(bar=(1 == 1)) + +E25.py:23:10: E251 [*] Unexpected spaces around keyword / parameter equals | 21 | foo(True, 22 | baz=(1, 2), @@ -112,5 +220,16 @@ E25.py:23:10: E251 Unexpected spaces around keyword / parameter equals 24 | ) 25 | #: Okay | + = help: Remove whitespace + +ℹ Safe fix +20 20 | #: E251:3:8 E251:3:10 +21 21 | foo(True, +22 22 | baz=(1, 2), +23 |- biz = 'foo' + 23 |+ biz ='foo' +24 24 | ) +25 25 | #: Okay +26 26 | foo(bar=(1 == 1)) From b7b137abc87c049fdf02ee2ec6ac25dfd805e29d Mon Sep 17 00:00:00 2001 From: Sai-Suraj-27 Date: Sun, 10 Dec 2023 01:22:57 +0530 Subject: [PATCH 150/197] Fix: Fixed a line in docs to make it more clear (#9073) ## Summary I was using `ruff` on one of my repo's and found this small error. I think the sentence can be made more clear. --- .../src/rules/flake8_pytest_style/rules/assertion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/assertion.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/assertion.rs index 80a6181832a0a..dde7f269280b3 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/assertion.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/assertion.rs @@ -33,7 +33,7 @@ use super::unittest_assert::UnittestAssert; /// Checks for assertions that combine multiple independent conditions. /// /// ## Why is this bad? -/// Composite assertion statements are harder debug upon failure, as the +/// Composite assertion statements are harder to debug upon failure, as the /// failure message will not indicate which condition failed. /// /// ## Example From cb8a2f56155ac5ab69a8582a2a62f171b6dae926 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 9 Dec 2023 15:18:07 -0500 Subject: [PATCH 151/197] Add fix for comment-related whitespace rules (#9075) Closes https://github.com/astral-sh/ruff/issues/9067. Closes https://github.com/astral-sh/ruff/issues/9068. Closes https://github.com/astral-sh/ruff/issues/8119. --- .../test/fixtures/pycodestyle/E26.py | 12 +++ .../whitespace_before_comment.rs | 56 ++++++++-- ...ules__pycodestyle__tests__E262_E26.py.snap | 101 +++++++++++++++++- ...ules__pycodestyle__tests__E265_E26.py.snap | 86 ++++++++++++++- ...ules__pycodestyle__tests__E266_E26.py.snap | 73 ++++++++++++- ...r__rules__pycodestyle__tests__shebang.snap | 10 +- 6 files changed, 316 insertions(+), 22 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E26.py b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E26.py index 9d35553dc521a..052baafcab781 100644 --- a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E26.py +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E26.py @@ -72,3 +72,15 @@ def oof(): # EF Means test is giving error and Failing #! Means test is segfaulting # 8 Means test runs forever + +#: Colon prefix is okay + +###This is a variable ### + +# We should strip the space, but preserve the hashes. +#: E266:1:3 +## Foo + +a = 1 ## Foo + +a = 1 #:Foo diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs index 235c12f7b6c65..0df27d8fe583b 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs @@ -1,4 +1,4 @@ -use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, Violation}; +use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_parser::TokenKind; use ruff_python_trivia::PythonWhitespace; @@ -66,11 +66,15 @@ impl AlwaysFixableViolation for TooFewSpacesBeforeInlineComment { #[violation] pub struct NoSpaceAfterInlineComment; -impl Violation for NoSpaceAfterInlineComment { +impl AlwaysFixableViolation for NoSpaceAfterInlineComment { #[derive_message_formats] fn message(&self) -> String { format!("Inline comment should start with `# `") } + + fn fix_title(&self) -> String { + format!("Format space") + } } /// ## What it does @@ -98,11 +102,15 @@ impl Violation for NoSpaceAfterInlineComment { #[violation] pub struct NoSpaceAfterBlockComment; -impl Violation for NoSpaceAfterBlockComment { +impl AlwaysFixableViolation for NoSpaceAfterBlockComment { #[derive_message_formats] fn message(&self) -> String { format!("Block comment should start with `# `") } + + fn fix_title(&self) -> String { + format!("Format space") + } } /// ## What it does @@ -130,11 +138,15 @@ impl Violation for NoSpaceAfterBlockComment { #[violation] pub struct MultipleLeadingHashesForBlockComment; -impl Violation for MultipleLeadingHashesForBlockComment { +impl AlwaysFixableViolation for MultipleLeadingHashesForBlockComment { #[derive_message_formats] fn message(&self) -> String { format!("Too many leading `#` before block comment") } + + fn fix_title(&self) -> String { + format!("Remove leading `#`") + } } /// E261, E262, E265, E266 @@ -184,14 +196,30 @@ pub(crate) fn whitespace_before_comment( if is_inline_comment { if bad_prefix.is_some() || comment.chars().next().is_some_and(char::is_whitespace) { - context.push(NoSpaceAfterInlineComment, range); + let mut diagnostic = Diagnostic::new(NoSpaceAfterInlineComment, range); + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + format_leading_space(token_text), + range, + ))); + context.push_diagnostic(diagnostic); } } else if let Some(bad_prefix) = bad_prefix { if bad_prefix != '!' || !line.is_start_of_file() { if bad_prefix != '#' { - context.push(NoSpaceAfterBlockComment, range); + let mut diagnostic = Diagnostic::new(NoSpaceAfterBlockComment, range); + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + format_leading_space(token_text), + range, + ))); + context.push_diagnostic(diagnostic); } else if !comment.is_empty() { - context.push(MultipleLeadingHashesForBlockComment, range); + let mut diagnostic = + Diagnostic::new(MultipleLeadingHashesForBlockComment, range); + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + format_leading_hashes(token_text), + range, + ))); + context.push_diagnostic(diagnostic); } } } @@ -200,3 +228,17 @@ pub(crate) fn whitespace_before_comment( } } } + +/// Format a comment to have a single space after the `#`. +fn format_leading_space(comment: &str) -> String { + if let Some(rest) = comment.strip_prefix("#:") { + format!("#: {}", rest.trim_start()) + } else { + format!("# {}", comment.trim_start_matches('#').trim_start()) + } +} + +/// Format a comment to strip multiple leading `#` characters. +fn format_leading_hashes(comment: &str) -> String { + format!("# {}", comment.trim_start_matches('#').trim_start()) +} diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E262_E26.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E262_E26.py.snap index a01a1eb2d7cd1..658391acdc36b 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E262_E26.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E262_E26.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/pycodestyle/mod.rs --- -E26.py:4:12: E262 Inline comment should start with `# ` +E26.py:4:12: E262 [*] Inline comment should start with `# ` | 2 | pass # an inline comment 3 | #: E262:1:12 @@ -10,8 +10,19 @@ E26.py:4:12: E262 Inline comment should start with `# ` 5 | #: E262:1:12 6 | x = x + 1 # Increment x | + = help: Format space -E26.py:6:12: E262 Inline comment should start with `# ` +ℹ Safe fix +1 1 | #: E261:1:5 +2 2 | pass # an inline comment +3 3 | #: E262:1:12 +4 |-x = x + 1 #Increment x + 4 |+x = x + 1 # Increment x +5 5 | #: E262:1:12 +6 6 | x = x + 1 # Increment x +7 7 | #: E262:1:12 + +E26.py:6:12: E262 [*] Inline comment should start with `# ` | 4 | x = x + 1 #Increment x 5 | #: E262:1:12 @@ -20,8 +31,19 @@ E26.py:6:12: E262 Inline comment should start with `# ` 7 | #: E262:1:12 8 | x = y + 1 #: Increment x | + = help: Format space + +ℹ Safe fix +3 3 | #: E262:1:12 +4 4 | x = x + 1 #Increment x +5 5 | #: E262:1:12 +6 |-x = x + 1 # Increment x + 6 |+x = x + 1 # Increment x +7 7 | #: E262:1:12 +8 8 | x = y + 1 #: Increment x +9 9 | #: E265:1:1 -E26.py:8:12: E262 Inline comment should start with `# ` +E26.py:8:12: E262 [*] Inline comment should start with `# ` | 6 | x = x + 1 # Increment x 7 | #: E262:1:12 @@ -30,8 +52,19 @@ E26.py:8:12: E262 Inline comment should start with `# ` 9 | #: E265:1:1 10 | #Block comment | + = help: Format space -E26.py:63:9: E262 Inline comment should start with `# ` +ℹ Safe fix +5 5 | #: E262:1:12 +6 6 | x = x + 1 # Increment x +7 7 | #: E262:1:12 +8 |-x = y + 1 #: Increment x + 8 |+x = y + 1 #: Increment x +9 9 | #: E265:1:1 +10 10 | #Block comment +11 11 | a = 1 + +E26.py:63:9: E262 [*] Inline comment should start with `# ` | 61 | # -*- coding: utf8 -*- 62 | #  (One space one NBSP) Ok for block comment @@ -40,8 +73,19 @@ E26.py:63:9: E262 Inline comment should start with `# ` 64 | #: E262:2:9 65 | # (Two spaces) Ok for block comment | + = help: Format space + +ℹ Safe fix +60 60 | #: E262:3:9 +61 61 | # -*- coding: utf8 -*- +62 62 | #  (One space one NBSP) Ok for block comment +63 |-a = 42 #  (One space one NBSP) + 63 |+a = 42 # (One space one NBSP) +64 64 | #: E262:2:9 +65 65 | # (Two spaces) Ok for block comment +66 66 | a = 42 # (Two spaces) -E26.py:66:9: E262 Inline comment should start with `# ` +E26.py:66:9: E262 [*] Inline comment should start with `# ` | 64 | #: E262:2:9 65 | # (Two spaces) Ok for block comment @@ -50,5 +94,52 @@ E26.py:66:9: E262 Inline comment should start with `# ` 67 | 68 | #: E265:5:1 | + = help: Format space + +ℹ Safe fix +63 63 | a = 42 #  (One space one NBSP) +64 64 | #: E262:2:9 +65 65 | # (Two spaces) Ok for block comment +66 |-a = 42 # (Two spaces) + 66 |+a = 42 # (Two spaces) +67 67 | +68 68 | #: E265:5:1 +69 69 | ### Means test is not done yet + +E26.py:84:8: E262 [*] Inline comment should start with `# ` + | +82 | ## Foo +83 | +84 | a = 1 ## Foo + | ^^^^^^ E262 +85 | +86 | a = 1 #:Foo + | + = help: Format space + +ℹ Safe fix +81 81 | #: E266:1:3 +82 82 | ## Foo +83 83 | +84 |-a = 1 ## Foo + 84 |+a = 1 # Foo +85 85 | +86 86 | a = 1 #:Foo + +E26.py:86:8: E262 [*] Inline comment should start with `# ` + | +84 | a = 1 ## Foo +85 | +86 | a = 1 #:Foo + | ^^^^^ E262 + | + = help: Format space + +ℹ Safe fix +83 83 | +84 84 | a = 1 ## Foo +85 85 | +86 |-a = 1 #:Foo + 86 |+a = 1 #: Foo diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E265_E26.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E265_E26.py.snap index 6017827141782..92b25ccb212b6 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E265_E26.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E265_E26.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/pycodestyle/mod.rs --- -E26.py:10:1: E265 Block comment should start with `# ` +E26.py:10:1: E265 [*] Block comment should start with `# ` | 8 | x = y + 1 #: Increment x 9 | #: E265:1:1 @@ -10,8 +10,19 @@ E26.py:10:1: E265 Block comment should start with `# ` 11 | a = 1 12 | #: E265:2:1 | + = help: Format space -E26.py:14:1: E265 Block comment should start with `# ` +ℹ Safe fix +7 7 | #: E262:1:12 +8 8 | x = y + 1 #: Increment x +9 9 | #: E265:1:1 +10 |-#Block comment + 10 |+# Block comment +11 11 | a = 1 +12 12 | #: E265:2:1 +13 13 | m = 42 + +E26.py:14:1: E265 [*] Block comment should start with `# ` | 12 | #: E265:2:1 13 | m = 42 @@ -20,8 +31,19 @@ E26.py:14:1: E265 Block comment should start with `# ` 15 | mx = 42 - 42 16 | #: E266:3:5 E266:6:5 | + = help: Format space + +ℹ Safe fix +11 11 | a = 1 +12 12 | #: E265:2:1 +13 13 | m = 42 +14 |-#! This is important + 14 |+# ! This is important +15 15 | mx = 42 - 42 +16 16 | #: E266:3:5 E266:6:5 +17 17 | def how_it_feel(r): -E26.py:25:1: E265 Block comment should start with `# ` +E26.py:25:1: E265 [*] Block comment should start with `# ` | 23 | return 24 | #: E265:1:1 E266:2:1 @@ -30,8 +52,19 @@ E26.py:25:1: E265 Block comment should start with `# ` 26 | ## logging.error() 27 | #: W291:1:42 | + = help: Format space + +ℹ Safe fix +22 22 | ### Of course it is unused +23 23 | return +24 24 | #: E265:1:1 E266:2:1 +25 |-##if DEBUG: + 25 |+# if DEBUG: +26 26 | ## logging.error() +27 27 | #: W291:1:42 +28 28 | ######################################### -E26.py:32:1: E265 Block comment should start with `# ` +E26.py:32:1: E265 [*] Block comment should start with `# ` | 31 | #: Okay 32 | #!/usr/bin/env python @@ -39,8 +72,19 @@ E26.py:32:1: E265 Block comment should start with `# ` 33 | 34 | pass # an inline comment | + = help: Format space -E26.py:73:1: E265 Block comment should start with `# ` +ℹ Safe fix +29 29 | #: +30 30 | +31 31 | #: Okay +32 |-#!/usr/bin/env python + 32 |+# !/usr/bin/env python +33 33 | +34 34 | pass # an inline comment +35 35 | x = x + 1 # Increment x + +E26.py:73:1: E265 [*] Block comment should start with `# ` | 71 | # F Means test is failing (F) 72 | # EF Means test is giving error and Failing @@ -48,5 +92,37 @@ E26.py:73:1: E265 Block comment should start with `# ` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E265 74 | # 8 Means test runs forever | + = help: Format space + +ℹ Safe fix +70 70 | # E Means test is giving error (E) +71 71 | # F Means test is failing (F) +72 72 | # EF Means test is giving error and Failing +73 |-#! Means test is segfaulting + 73 |+# ! Means test is segfaulting +74 74 | # 8 Means test runs forever +75 75 | +76 76 | #: Colon prefix is okay + +E26.py:78:1: E265 [*] Block comment should start with `# ` + | +76 | #: Colon prefix is okay +77 | +78 | ###This is a variable ### + | ^^^^^^^^^^^^^^^^^^^^^^^^^ E265 +79 | +80 | # We should strip the space, but preserve the hashes. + | + = help: Format space + +ℹ Safe fix +75 75 | +76 76 | #: Colon prefix is okay +77 77 | +78 |-###This is a variable ### + 78 |+# This is a variable ### +79 79 | +80 80 | # We should strip the space, but preserve the hashes. +81 81 | #: E266:1:3 diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E266_E26.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E266_E26.py.snap index 5eb382385cccb..4469e1b225d64 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E266_E26.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E266_E26.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/pycodestyle/mod.rs --- -E26.py:19:5: E266 Too many leading `#` before block comment +E26.py:19:5: E266 [*] Too many leading `#` before block comment | 17 | def how_it_feel(r): 18 | @@ -9,8 +9,19 @@ E26.py:19:5: E266 Too many leading `#` before block comment | ^^^^^^^^^^^^^^^^^^^^^^^^^^ E266 20 | a = 42 | + = help: Remove leading `#` -E26.py:22:5: E266 Too many leading `#` before block comment +ℹ Safe fix +16 16 | #: E266:3:5 E266:6:5 +17 17 | def how_it_feel(r): +18 18 | +19 |- ### This is a variable ### + 19 |+ # This is a variable ### +20 20 | a = 42 +21 21 | +22 22 | ### Of course it is unused + +E26.py:22:5: E266 [*] Too many leading `#` before block comment | 20 | a = 42 21 | @@ -19,8 +30,19 @@ E26.py:22:5: E266 Too many leading `#` before block comment 23 | return 24 | #: E265:1:1 E266:2:1 | + = help: Remove leading `#` + +ℹ Safe fix +19 19 | ### This is a variable ### +20 20 | a = 42 +21 21 | +22 |- ### Of course it is unused + 22 |+ # Of course it is unused +23 23 | return +24 24 | #: E265:1:1 E266:2:1 +25 25 | ##if DEBUG: -E26.py:26:1: E266 Too many leading `#` before block comment +E26.py:26:1: E266 [*] Too many leading `#` before block comment | 24 | #: E265:1:1 E266:2:1 25 | ##if DEBUG: @@ -29,8 +51,19 @@ E26.py:26:1: E266 Too many leading `#` before block comment 27 | #: W291:1:42 28 | ######################################### | + = help: Remove leading `#` -E26.py:69:1: E266 Too many leading `#` before block comment +ℹ Safe fix +23 23 | return +24 24 | #: E265:1:1 E266:2:1 +25 25 | ##if DEBUG: +26 |-## logging.error() + 26 |+# logging.error() +27 27 | #: W291:1:42 +28 28 | ######################################### +29 29 | #: + +E26.py:69:1: E266 [*] Too many leading `#` before block comment | 68 | #: E265:5:1 69 | ### Means test is not done yet @@ -38,5 +71,37 @@ E26.py:69:1: E266 Too many leading `#` before block comment 70 | # E Means test is giving error (E) 71 | # F Means test is failing (F) | + = help: Remove leading `#` + +ℹ Safe fix +66 66 | a = 42 # (Two spaces) +67 67 | +68 68 | #: E265:5:1 +69 |-### Means test is not done yet + 69 |+# Means test is not done yet +70 70 | # E Means test is giving error (E) +71 71 | # F Means test is failing (F) +72 72 | # EF Means test is giving error and Failing + +E26.py:82:1: E266 [*] Too many leading `#` before block comment + | +80 | # We should strip the space, but preserve the hashes. +81 | #: E266:1:3 +82 | ## Foo + | ^^^^^^^ E266 +83 | +84 | a = 1 ## Foo + | + = help: Remove leading `#` + +ℹ Safe fix +79 79 | +80 80 | # We should strip the space, but preserve the hashes. +81 81 | #: E266:1:3 +82 |-## Foo + 82 |+# Foo +83 83 | +84 84 | a = 1 ## Foo +85 85 | diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__shebang.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__shebang.snap index 63d5b9fefc8c5..fa3897bebc056 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__shebang.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__shebang.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/pycodestyle/mod.rs --- -shebang.py:3:1: E265 Block comment should start with `# ` +shebang.py:3:1: E265 [*] Block comment should start with `# ` | 1 | #!/usr/bin/python 2 | # @@ -9,5 +9,13 @@ shebang.py:3:1: E265 Block comment should start with `# ` | ^^ E265 4 | #: | + = help: Format space + +ℹ Safe fix +1 1 | #!/usr/bin/python +2 2 | # +3 |-#! + 3 |+# ! +4 4 | #: From 6c2613b44e23936bc3631811c3f28ef16335a779 Mon Sep 17 00:00:00 2001 From: asafamr-mm <112866104+asafamr-mm@users.noreply.github.com> Date: Sat, 9 Dec 2023 23:10:38 +0200 Subject: [PATCH 152/197] Detect `unused-asyncio-dangling-task` (`RUF006`) on unused assignments (#9060) ## Summary Fixes #8863 : Detect asyncio-dangling-task (RUF006) when discarding return value ## Test Plan added new two testcases, changed result of an old one that was made more specific --- .../resources/test/fixtures/ruff/RUF006.py | 36 +++++++++++- .../src/checkers/ast/analyze/bindings.rs | 10 +++- .../src/checkers/ast/analyze/statement.rs | 6 +- .../rules/ruff/rules/asyncio_dangling_task.rs | 57 ++++++++++++------- ..._rules__ruff__tests__RUF006_RUF006.py.snap | 24 ++++++-- 5 files changed, 107 insertions(+), 26 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF006.py b/crates/ruff_linter/resources/test/fixtures/ruff/RUF006.py index eedce2563153b..6c7792d5c4391 100644 --- a/crates/ruff_linter/resources/test/fixtures/ruff/RUF006.py +++ b/crates/ruff_linter/resources/test/fixtures/ruff/RUF006.py @@ -63,11 +63,29 @@ def f(): tasks = [asyncio.create_task(task) for task in tasks] -# OK (false negative) +# Error def f(): task = asyncio.create_task(coordinator.ws_connect()) +# Error +def f(): + loop = asyncio.get_running_loop() + task: asyncio.Task = loop.create_task(coordinator.ws_connect()) + + +# OK (potential false negative) +def f(): + task = asyncio.create_task(coordinator.ws_connect()) + background_tasks.add(task) + + +# OK +async def f(): + task = asyncio.create_task(coordinator.ws_connect()) + await task + + # OK (potential false negative) def f(): do_nothing_with_the_task(asyncio.create_task(coordinator.ws_connect())) @@ -88,3 +106,19 @@ def f(): def f(): loop = asyncio.get_running_loop() loop.do_thing(coordinator.ws_connect()) + + +# OK +async def f(): + task = unused = asyncio.create_task(coordinator.ws_connect()) + await task + + +# OK (false negative) +async def f(): + task = unused = asyncio.create_task(coordinator.ws_connect()) + + +# OK +async def f(): + task[i] = asyncio.create_task(coordinator.ws_connect()) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/bindings.rs b/crates/ruff_linter/src/checkers/ast/analyze/bindings.rs index 0fbc85f5552fa..e279dd5fbf7e9 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/bindings.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/bindings.rs @@ -3,11 +3,12 @@ use ruff_text_size::Ranged; use crate::checkers::ast::Checker; use crate::codes::Rule; -use crate::rules::{flake8_import_conventions, flake8_pyi, pyflakes, pylint}; +use crate::rules::{flake8_import_conventions, flake8_pyi, pyflakes, pylint, ruff}; /// Run lint rules over the [`Binding`]s. pub(crate) fn bindings(checker: &mut Checker) { if !checker.any_enabled(&[ + Rule::AsyncioDanglingTask, Rule::InvalidAllFormat, Rule::InvalidAllObject, Rule::NonAsciiName, @@ -71,5 +72,12 @@ pub(crate) fn bindings(checker: &mut Checker) { checker.diagnostics.push(diagnostic); } } + if checker.enabled(Rule::AsyncioDanglingTask) { + if let Some(diagnostic) = + ruff::rules::asyncio_dangling_binding(binding, &checker.semantic) + { + checker.diagnostics.push(diagnostic); + } + } } } diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index afb80e227a539..5fb77629a28c8 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -1571,7 +1571,11 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { pylint::rules::named_expr_without_context(checker, value); } if checker.enabled(Rule::AsyncioDanglingTask) { - ruff::rules::asyncio_dangling_task(checker, value); + if let Some(diagnostic) = + ruff::rules::asyncio_dangling_task(value, checker.semantic()) + { + checker.diagnostics.push(diagnostic); + } } if checker.enabled(Rule::RepeatedAppend) { refurb::rules::repeated_append(checker, stmt); diff --git a/crates/ruff_linter/src/rules/ruff/rules/asyncio_dangling_task.rs b/crates/ruff_linter/src/rules/ruff/rules/asyncio_dangling_task.rs index f6f03fc8d955e..2f339b95c35dd 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/asyncio_dangling_task.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/asyncio_dangling_task.rs @@ -1,14 +1,12 @@ use std::fmt; -use ruff_python_ast::{self as ast, Expr}; - +use ast::Stmt; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_semantic::analyze::typing; +use ruff_python_ast::{self as ast, Expr}; +use ruff_python_semantic::{analyze::typing, Binding, SemanticModel}; use ruff_text_size::Ranged; -use crate::checkers::ast::Checker; - /// ## What it does /// Checks for `asyncio.create_task` and `asyncio.ensure_future` calls /// that do not store a reference to the returned result. @@ -66,35 +64,34 @@ impl Violation for AsyncioDanglingTask { } /// RUF006 -pub(crate) fn asyncio_dangling_task(checker: &mut Checker, expr: &Expr) { +pub(crate) fn asyncio_dangling_task(expr: &Expr, semantic: &SemanticModel) -> Option { let Expr::Call(ast::ExprCall { func, .. }) = expr else { - return; + return None; }; // Ex) `asyncio.create_task(...)` - if let Some(method) = checker - .semantic() - .resolve_call_path(func) - .and_then(|call_path| match call_path.as_slice() { - ["asyncio", "create_task"] => Some(Method::CreateTask), - ["asyncio", "ensure_future"] => Some(Method::EnsureFuture), - _ => None, - }) + if let Some(method) = + semantic + .resolve_call_path(func) + .and_then(|call_path| match call_path.as_slice() { + ["asyncio", "create_task"] => Some(Method::CreateTask), + ["asyncio", "ensure_future"] => Some(Method::EnsureFuture), + _ => None, + }) { - checker.diagnostics.push(Diagnostic::new( + return Some(Diagnostic::new( AsyncioDanglingTask { method }, expr.range(), )); - return; } // Ex) `loop = asyncio.get_running_loop(); loop.create_task(...)` if let Expr::Attribute(ast::ExprAttribute { attr, value, .. }) = func.as_ref() { if attr == "create_task" { - if typing::resolve_assignment(value, checker.semantic()).is_some_and(|call_path| { + if typing::resolve_assignment(value, semantic).is_some_and(|call_path| { matches!(call_path.as_slice(), ["asyncio", "get_running_loop"]) }) { - checker.diagnostics.push(Diagnostic::new( + return Some(Diagnostic::new( AsyncioDanglingTask { method: Method::CreateTask, }, @@ -103,6 +100,28 @@ pub(crate) fn asyncio_dangling_task(checker: &mut Checker, expr: &Expr) { } } } + None +} + +/// RUF006 +pub(crate) fn asyncio_dangling_binding( + binding: &Binding, + semantic: &SemanticModel, +) -> Option { + if binding.is_used() || !binding.kind.is_assignment() { + return None; + } + + let source = binding.source?; + match semantic.statement(source) { + Stmt::Assign(ast::StmtAssign { value, targets, .. }) if targets.len() == 1 => { + asyncio_dangling_task(value, semantic) + } + Stmt::AnnAssign(ast::StmtAnnAssign { + value: Some(value), .. + }) => asyncio_dangling_task(value, semantic), + _ => None, + } } #[derive(Debug, PartialEq, Eq, Copy, Clone)] diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF006_RUF006.py.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF006_RUF006.py.snap index 11a0bababe525..def73e5a2e11e 100644 --- a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF006_RUF006.py.snap +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF006_RUF006.py.snap @@ -17,11 +17,27 @@ RUF006.py:11:5: RUF006 Store a reference to the return value of `asyncio.ensure_ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF006 | -RUF006.py:79:5: RUF006 Store a reference to the return value of `asyncio.create_task` +RUF006.py:68:12: RUF006 Store a reference to the return value of `asyncio.create_task` | -77 | def f(): -78 | loop = asyncio.get_running_loop() -79 | loop.create_task(coordinator.ws_connect()) # Error +66 | # Error +67 | def f(): +68 | task = asyncio.create_task(coordinator.ws_connect()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF006 + | + +RUF006.py:74:26: RUF006 Store a reference to the return value of `asyncio.create_task` + | +72 | def f(): +73 | loop = asyncio.get_running_loop() +74 | task: asyncio.Task = loop.create_task(coordinator.ws_connect()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF006 + | + +RUF006.py:97:5: RUF006 Store a reference to the return value of `asyncio.create_task` + | +95 | def f(): +96 | loop = asyncio.get_running_loop() +97 | loop.create_task(coordinator.ws_connect()) # Error | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF006 | From febc69ab48416dacdad2499ccb6512dd8e56cc7c Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 9 Dec 2023 18:03:31 -0500 Subject: [PATCH 153/197] Avoid trailing comma for single-argument with positional separator (#9076) ## Summary In https://github.com/astral-sh/ruff/pull/8921, we changed our parameter formatting behavior to add a trailing comma whenever a single-argument function breaks. This introduced a deviation in the case that a function contains a single argument, but _also_ includes a positional-only or keyword-only separator. Closes https://github.com/astral-sh/ruff/issues/9074. --- .../test/fixtures/ruff/statement/function.py | 10 +++++++++ .../src/other/parameters.rs | 2 +- .../format@statement__function.py.snap | 22 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/function.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/function.py index 98eb09eefafcb..20eca870395fd 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/function.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/function.py @@ -410,3 +410,13 @@ def default_arg_comments2(# # ): print(x) + +def function_with_one_argument_and_a_positional_separator( + argument: str, / +) -> ReallyReallyReallyReallyReallyReallyReallyReallyLongName: + pass + +def function_with_one_argument_and_a_keyword_separator( + *, argument: str +) -> ReallyReallyReallyReallyReallyReallyReallyReallyLongName: + pass diff --git a/crates/ruff_python_formatter/src/other/parameters.rs b/crates/ruff_python_formatter/src/other/parameters.rs index d095d33ae1975..c3e251ebe97e5 100644 --- a/crates/ruff_python_formatter/src/other/parameters.rs +++ b/crates/ruff_python_formatter/src/other/parameters.rs @@ -252,7 +252,7 @@ impl FormatNodeRule for FormatParameters { let mut f = WithNodeLevel::new(NodeLevel::ParenthesizedExpression, f); // No parameters, format any dangling comments between `()` write!(f, [empty_parenthesized("(", dangling, ")")]) - } else if num_parameters == 1 { + } else if num_parameters == 1 && posonlyargs.is_empty() && kwonlyargs.is_empty() { // If we have a single argument, avoid the inner group, to ensure that we insert a // trailing comma if the outer group breaks. let mut f = WithNodeLevel::new(NodeLevel::ParenthesizedExpression, f); diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__function.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__function.py.snap index 7a8e97566ecb3..4c040409d7c33 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__function.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__function.py.snap @@ -416,6 +416,16 @@ def default_arg_comments2(# # ): print(x) + +def function_with_one_argument_and_a_positional_separator( + argument: str, / +) -> ReallyReallyReallyReallyReallyReallyReallyReallyLongName: + pass + +def function_with_one_argument_and_a_keyword_separator( + *, argument: str +) -> ReallyReallyReallyReallyReallyReallyReallyReallyLongName: + pass ``` ## Output @@ -993,6 +1003,18 @@ def default_arg_comments2( # # ): print(x) + + +def function_with_one_argument_and_a_positional_separator( + argument: str, / +) -> ReallyReallyReallyReallyReallyReallyReallyReallyLongName: + pass + + +def function_with_one_argument_and_a_keyword_separator( + *, argument: str +) -> ReallyReallyReallyReallyReallyReallyReallyReallyLongName: + pass ``` From 6e36dcfefe39045494d372775652337327501114 Mon Sep 17 00:00:00 2001 From: Simon Brugman Date: Sun, 10 Dec 2023 03:00:11 +0100 Subject: [PATCH 154/197] [`refurb`] Implement `hashlib-digest-hex` (`FURB181`) (#9077) ## Summary Implementation of Refurb FURB181 Part of https://github.com/astral-sh/ruff/issues/1348 ## Test Plan Test cases from Refurb --- .../resources/test/fixtures/refurb/FURB181.py | 57 +++ .../src/checkers/ast/analyze/expression.rs | 5 + crates/ruff_linter/src/codes.rs | 1 + crates/ruff_linter/src/rules/refurb/mod.rs | 1 + .../rules/refurb/rules/hashlib_digest_hex.rs | 120 +++++++ .../ruff_linter/src/rules/refurb/rules/mod.rs | 2 + ...es__refurb__tests__FURB181_FURB181.py.snap | 339 ++++++++++++++++++ ruff.schema.json | 2 + 8 files changed, 527 insertions(+) create mode 100644 crates/ruff_linter/resources/test/fixtures/refurb/FURB181.py create mode 100644 crates/ruff_linter/src/rules/refurb/rules/hashlib_digest_hex.rs create mode 100644 crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB181_FURB181.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/refurb/FURB181.py b/crates/ruff_linter/resources/test/fixtures/refurb/FURB181.py new file mode 100644 index 0000000000000..559f67ee30442 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/refurb/FURB181.py @@ -0,0 +1,57 @@ +import hashlib +from hashlib import ( + blake2b, + blake2s, + md5, + sha1, + sha3_224, + sha3_256, + sha3_384, + sha3_512, + sha224, +) +from hashlib import sha256 +from hashlib import sha256 as hash_algo +from hashlib import sha384, sha512, shake_128, shake_256 + +# these will match + +blake2b().digest().hex() +blake2s().digest().hex() +md5().digest().hex() +sha1().digest().hex() +sha224().digest().hex() +sha256().digest().hex() +sha384().digest().hex() +sha3_224().digest().hex() +sha3_256().digest().hex() +sha3_384().digest().hex() +sha3_512().digest().hex() +sha512().digest().hex() +shake_128().digest(10).hex() +shake_256().digest(10).hex() + +hashlib.sha256().digest().hex() + +sha256(b"text").digest().hex() + +hash_algo().digest().hex() + +# not yet supported +h = sha256() +h.digest().hex() + + +# these will not + +sha256().digest() +sha256().digest().hex("_") +sha256().digest().hex(bytes_per_sep=4) +sha256().hexdigest() + +class Hash: + def digest(self) -> bytes: + return b"" + + +Hash().digest().hex() diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 64b2d1a8abcd0..ee666e48c96d4 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -356,6 +356,8 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { Rule::FString, // flynt Rule::StaticJoinToFString, + // refurb + Rule::HashlibDigestHex, ]) { if let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() { let attr = attr.as_str(); @@ -581,6 +583,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::HashlibInsecureHashFunction) { flake8_bandit::rules::hashlib_insecure_hash_functions(checker, call); } + if checker.enabled(Rule::HashlibDigestHex) { + refurb::rules::hashlib_digest_hex(checker, call); + } if checker.enabled(Rule::RequestWithoutTimeout) { flake8_bandit::rules::request_without_timeout(checker, call); } diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index fd0b85727bbec..a42aa50daa1c3 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -965,6 +965,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Refurb, "169") => (RuleGroup::Preview, rules::refurb::rules::TypeNoneComparison), (Refurb, "171") => (RuleGroup::Preview, rules::refurb::rules::SingleItemMembershipTest), (Refurb, "177") => (RuleGroup::Preview, rules::refurb::rules::ImplicitCwd), + (Refurb, "181") => (RuleGroup::Preview, rules::refurb::rules::HashlibDigestHex), // flake8-logging (Flake8Logging, "001") => (RuleGroup::Preview, rules::flake8_logging::rules::DirectLoggerInstantiation), diff --git a/crates/ruff_linter/src/rules/refurb/mod.rs b/crates/ruff_linter/src/rules/refurb/mod.rs index a7640bcd4c72b..d27985762cef4 100644 --- a/crates/ruff_linter/src/rules/refurb/mod.rs +++ b/crates/ruff_linter/src/rules/refurb/mod.rs @@ -29,6 +29,7 @@ mod tests { #[test_case(Rule::IsinstanceTypeNone, Path::new("FURB168.py"))] #[test_case(Rule::TypeNoneComparison, Path::new("FURB169.py"))] #[test_case(Rule::RedundantLogBase, Path::new("FURB163.py"))] + #[test_case(Rule::HashlibDigestHex, Path::new("FURB181.py"))] fn rules(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/refurb/rules/hashlib_digest_hex.rs b/crates/ruff_linter/src/rules/refurb/rules/hashlib_digest_hex.rs new file mode 100644 index 0000000000000..b8c7adf7cc833 --- /dev/null +++ b/crates/ruff_linter/src/rules/refurb/rules/hashlib_digest_hex.rs @@ -0,0 +1,120 @@ +use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; +use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::{Expr, ExprAttribute, ExprCall}; +use ruff_text_size::{Ranged, TextRange}; + +use crate::checkers::ast::Checker; + +/// ## What it does +/// Checks for the use of `.digest().hex()` on a hashlib hash, like `sha512`. +/// +/// ## Why is this bad? +/// When generating a hex digest from a hash, it's preferable to use the +/// `.hexdigest()` method, rather than calling `.digest()` and then `.hex()`, +/// as the former is more concise and readable. +/// +/// ## Example +/// ```python +/// from hashlib import sha512 +/// +/// hashed = sha512(b"some data").digest().hex() +/// ``` +/// +/// Use instead: +/// ```python +/// from hashlib import sha512 +/// +/// hashed = sha512(b"some data").hexdigest() +/// ``` +/// +/// ## Fix safety +/// This rule's fix is marked as unsafe, as the target of the `.digest()` call +/// could be a user-defined class that implements a `.hex()` method, rather +/// than a hashlib hash object. +/// +/// ## References +/// - [Python documentation: `hashlib`](https://docs.python.org/3/library/hashlib.html) +#[violation] +pub struct HashlibDigestHex; + +impl Violation for HashlibDigestHex { + const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes; + + #[derive_message_formats] + fn message(&self) -> String { + format!("Use of hashlib's `.digest().hex()`") + } + + fn fix_title(&self) -> Option { + Some("Replace with `.hexdigest()`".to_string()) + } +} + +/// FURB181 +pub(crate) fn hashlib_digest_hex(checker: &mut Checker, call: &ExprCall) { + if !call.arguments.is_empty() { + return; + } + + let Expr::Attribute(ExprAttribute { attr, value, .. }) = call.func.as_ref() else { + return; + }; + + if attr.as_str() != "hex" { + return; + } + + let Expr::Call(ExprCall { + func, arguments, .. + }) = value.as_ref() + else { + return; + }; + + let Expr::Attribute(ExprAttribute { attr, value, .. }) = func.as_ref() else { + return; + }; + + if attr.as_str() != "digest" { + return; + } + + let Expr::Call(ExprCall { func, .. }) = value.as_ref() else { + return; + }; + + if checker.semantic().resolve_call_path(func).is_some_and( + |call_path: smallvec::SmallVec<[&str; 8]>| { + matches!( + call_path.as_slice(), + [ + "hashlib", + "md5" + | "sha1" + | "sha224" + | "sha256" + | "sha384" + | "sha512" + | "blake2b" + | "blake2s" + | "sha3_224" + | "sha3_256" + | "sha3_384" + | "sha3_512" + | "shake_128" + | "shake_256" + | "_Hash" + ] + ) + }, + ) { + let mut diagnostic = Diagnostic::new(HashlibDigestHex, call.range()); + if arguments.is_empty() { + diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( + ".hexdigest".to_string(), + TextRange::new(value.end(), call.func.end()), + ))); + } + checker.diagnostics.push(diagnostic); + } +} diff --git a/crates/ruff_linter/src/rules/refurb/rules/mod.rs b/crates/ruff_linter/src/rules/refurb/rules/mod.rs index d43f87bced0aa..4f165af3b36e5 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/mod.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/mod.rs @@ -1,5 +1,6 @@ pub(crate) use check_and_remove_from_set::*; pub(crate) use delete_full_slice::*; +pub(crate) use hashlib_digest_hex::*; pub(crate) use if_expr_min_max::*; pub(crate) use implicit_cwd::*; pub(crate) use isinstance_type_none::*; @@ -16,6 +17,7 @@ pub(crate) use unnecessary_enumerate::*; mod check_and_remove_from_set; mod delete_full_slice; +mod hashlib_digest_hex; mod if_expr_min_max; mod implicit_cwd; mod isinstance_type_none; diff --git a/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB181_FURB181.py.snap b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB181_FURB181.py.snap new file mode 100644 index 0000000000000..cca7645c90adf --- /dev/null +++ b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB181_FURB181.py.snap @@ -0,0 +1,339 @@ +--- +source: crates/ruff_linter/src/rules/refurb/mod.rs +--- +FURB181.py:19:1: FURB181 [*] Use of hashlib's `.digest().hex()` + | +17 | # these will match +18 | +19 | blake2b().digest().hex() + | ^^^^^^^^^^^^^^^^^^^^^^^^ FURB181 +20 | blake2s().digest().hex() +21 | md5().digest().hex() + | + = help: Replace with `.hexdigest()` + +ℹ Unsafe fix +16 16 | +17 17 | # these will match +18 18 | +19 |-blake2b().digest().hex() + 19 |+blake2b().hexdigest() +20 20 | blake2s().digest().hex() +21 21 | md5().digest().hex() +22 22 | sha1().digest().hex() + +FURB181.py:20:1: FURB181 [*] Use of hashlib's `.digest().hex()` + | +19 | blake2b().digest().hex() +20 | blake2s().digest().hex() + | ^^^^^^^^^^^^^^^^^^^^^^^^ FURB181 +21 | md5().digest().hex() +22 | sha1().digest().hex() + | + = help: Replace with `.hexdigest()` + +ℹ Unsafe fix +17 17 | # these will match +18 18 | +19 19 | blake2b().digest().hex() +20 |-blake2s().digest().hex() + 20 |+blake2s().hexdigest() +21 21 | md5().digest().hex() +22 22 | sha1().digest().hex() +23 23 | sha224().digest().hex() + +FURB181.py:21:1: FURB181 [*] Use of hashlib's `.digest().hex()` + | +19 | blake2b().digest().hex() +20 | blake2s().digest().hex() +21 | md5().digest().hex() + | ^^^^^^^^^^^^^^^^^^^^ FURB181 +22 | sha1().digest().hex() +23 | sha224().digest().hex() + | + = help: Replace with `.hexdigest()` + +ℹ Unsafe fix +18 18 | +19 19 | blake2b().digest().hex() +20 20 | blake2s().digest().hex() +21 |-md5().digest().hex() + 21 |+md5().hexdigest() +22 22 | sha1().digest().hex() +23 23 | sha224().digest().hex() +24 24 | sha256().digest().hex() + +FURB181.py:22:1: FURB181 [*] Use of hashlib's `.digest().hex()` + | +20 | blake2s().digest().hex() +21 | md5().digest().hex() +22 | sha1().digest().hex() + | ^^^^^^^^^^^^^^^^^^^^^ FURB181 +23 | sha224().digest().hex() +24 | sha256().digest().hex() + | + = help: Replace with `.hexdigest()` + +ℹ Unsafe fix +19 19 | blake2b().digest().hex() +20 20 | blake2s().digest().hex() +21 21 | md5().digest().hex() +22 |-sha1().digest().hex() + 22 |+sha1().hexdigest() +23 23 | sha224().digest().hex() +24 24 | sha256().digest().hex() +25 25 | sha384().digest().hex() + +FURB181.py:23:1: FURB181 [*] Use of hashlib's `.digest().hex()` + | +21 | md5().digest().hex() +22 | sha1().digest().hex() +23 | sha224().digest().hex() + | ^^^^^^^^^^^^^^^^^^^^^^^ FURB181 +24 | sha256().digest().hex() +25 | sha384().digest().hex() + | + = help: Replace with `.hexdigest()` + +ℹ Unsafe fix +20 20 | blake2s().digest().hex() +21 21 | md5().digest().hex() +22 22 | sha1().digest().hex() +23 |-sha224().digest().hex() + 23 |+sha224().hexdigest() +24 24 | sha256().digest().hex() +25 25 | sha384().digest().hex() +26 26 | sha3_224().digest().hex() + +FURB181.py:24:1: FURB181 [*] Use of hashlib's `.digest().hex()` + | +22 | sha1().digest().hex() +23 | sha224().digest().hex() +24 | sha256().digest().hex() + | ^^^^^^^^^^^^^^^^^^^^^^^ FURB181 +25 | sha384().digest().hex() +26 | sha3_224().digest().hex() + | + = help: Replace with `.hexdigest()` + +ℹ Unsafe fix +21 21 | md5().digest().hex() +22 22 | sha1().digest().hex() +23 23 | sha224().digest().hex() +24 |-sha256().digest().hex() + 24 |+sha256().hexdigest() +25 25 | sha384().digest().hex() +26 26 | sha3_224().digest().hex() +27 27 | sha3_256().digest().hex() + +FURB181.py:25:1: FURB181 [*] Use of hashlib's `.digest().hex()` + | +23 | sha224().digest().hex() +24 | sha256().digest().hex() +25 | sha384().digest().hex() + | ^^^^^^^^^^^^^^^^^^^^^^^ FURB181 +26 | sha3_224().digest().hex() +27 | sha3_256().digest().hex() + | + = help: Replace with `.hexdigest()` + +ℹ Unsafe fix +22 22 | sha1().digest().hex() +23 23 | sha224().digest().hex() +24 24 | sha256().digest().hex() +25 |-sha384().digest().hex() + 25 |+sha384().hexdigest() +26 26 | sha3_224().digest().hex() +27 27 | sha3_256().digest().hex() +28 28 | sha3_384().digest().hex() + +FURB181.py:26:1: FURB181 [*] Use of hashlib's `.digest().hex()` + | +24 | sha256().digest().hex() +25 | sha384().digest().hex() +26 | sha3_224().digest().hex() + | ^^^^^^^^^^^^^^^^^^^^^^^^^ FURB181 +27 | sha3_256().digest().hex() +28 | sha3_384().digest().hex() + | + = help: Replace with `.hexdigest()` + +ℹ Unsafe fix +23 23 | sha224().digest().hex() +24 24 | sha256().digest().hex() +25 25 | sha384().digest().hex() +26 |-sha3_224().digest().hex() + 26 |+sha3_224().hexdigest() +27 27 | sha3_256().digest().hex() +28 28 | sha3_384().digest().hex() +29 29 | sha3_512().digest().hex() + +FURB181.py:27:1: FURB181 [*] Use of hashlib's `.digest().hex()` + | +25 | sha384().digest().hex() +26 | sha3_224().digest().hex() +27 | sha3_256().digest().hex() + | ^^^^^^^^^^^^^^^^^^^^^^^^^ FURB181 +28 | sha3_384().digest().hex() +29 | sha3_512().digest().hex() + | + = help: Replace with `.hexdigest()` + +ℹ Unsafe fix +24 24 | sha256().digest().hex() +25 25 | sha384().digest().hex() +26 26 | sha3_224().digest().hex() +27 |-sha3_256().digest().hex() + 27 |+sha3_256().hexdigest() +28 28 | sha3_384().digest().hex() +29 29 | sha3_512().digest().hex() +30 30 | sha512().digest().hex() + +FURB181.py:28:1: FURB181 [*] Use of hashlib's `.digest().hex()` + | +26 | sha3_224().digest().hex() +27 | sha3_256().digest().hex() +28 | sha3_384().digest().hex() + | ^^^^^^^^^^^^^^^^^^^^^^^^^ FURB181 +29 | sha3_512().digest().hex() +30 | sha512().digest().hex() + | + = help: Replace with `.hexdigest()` + +ℹ Unsafe fix +25 25 | sha384().digest().hex() +26 26 | sha3_224().digest().hex() +27 27 | sha3_256().digest().hex() +28 |-sha3_384().digest().hex() + 28 |+sha3_384().hexdigest() +29 29 | sha3_512().digest().hex() +30 30 | sha512().digest().hex() +31 31 | shake_128().digest(10).hex() + +FURB181.py:29:1: FURB181 [*] Use of hashlib's `.digest().hex()` + | +27 | sha3_256().digest().hex() +28 | sha3_384().digest().hex() +29 | sha3_512().digest().hex() + | ^^^^^^^^^^^^^^^^^^^^^^^^^ FURB181 +30 | sha512().digest().hex() +31 | shake_128().digest(10).hex() + | + = help: Replace with `.hexdigest()` + +ℹ Unsafe fix +26 26 | sha3_224().digest().hex() +27 27 | sha3_256().digest().hex() +28 28 | sha3_384().digest().hex() +29 |-sha3_512().digest().hex() + 29 |+sha3_512().hexdigest() +30 30 | sha512().digest().hex() +31 31 | shake_128().digest(10).hex() +32 32 | shake_256().digest(10).hex() + +FURB181.py:30:1: FURB181 [*] Use of hashlib's `.digest().hex()` + | +28 | sha3_384().digest().hex() +29 | sha3_512().digest().hex() +30 | sha512().digest().hex() + | ^^^^^^^^^^^^^^^^^^^^^^^ FURB181 +31 | shake_128().digest(10).hex() +32 | shake_256().digest(10).hex() + | + = help: Replace with `.hexdigest()` + +ℹ Unsafe fix +27 27 | sha3_256().digest().hex() +28 28 | sha3_384().digest().hex() +29 29 | sha3_512().digest().hex() +30 |-sha512().digest().hex() + 30 |+sha512().hexdigest() +31 31 | shake_128().digest(10).hex() +32 32 | shake_256().digest(10).hex() +33 33 | + +FURB181.py:31:1: FURB181 Use of hashlib's `.digest().hex()` + | +29 | sha3_512().digest().hex() +30 | sha512().digest().hex() +31 | shake_128().digest(10).hex() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB181 +32 | shake_256().digest(10).hex() + | + = help: Replace with `.hexdigest()` + +FURB181.py:32:1: FURB181 Use of hashlib's `.digest().hex()` + | +30 | sha512().digest().hex() +31 | shake_128().digest(10).hex() +32 | shake_256().digest(10).hex() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB181 +33 | +34 | hashlib.sha256().digest().hex() + | + = help: Replace with `.hexdigest()` + +FURB181.py:34:1: FURB181 [*] Use of hashlib's `.digest().hex()` + | +32 | shake_256().digest(10).hex() +33 | +34 | hashlib.sha256().digest().hex() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB181 +35 | +36 | sha256(b"text").digest().hex() + | + = help: Replace with `.hexdigest()` + +ℹ Unsafe fix +31 31 | shake_128().digest(10).hex() +32 32 | shake_256().digest(10).hex() +33 33 | +34 |-hashlib.sha256().digest().hex() + 34 |+hashlib.sha256().hexdigest() +35 35 | +36 36 | sha256(b"text").digest().hex() +37 37 | + +FURB181.py:36:1: FURB181 [*] Use of hashlib's `.digest().hex()` + | +34 | hashlib.sha256().digest().hex() +35 | +36 | sha256(b"text").digest().hex() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB181 +37 | +38 | hash_algo().digest().hex() + | + = help: Replace with `.hexdigest()` + +ℹ Unsafe fix +33 33 | +34 34 | hashlib.sha256().digest().hex() +35 35 | +36 |-sha256(b"text").digest().hex() + 36 |+sha256(b"text").hexdigest() +37 37 | +38 38 | hash_algo().digest().hex() +39 39 | + +FURB181.py:38:1: FURB181 [*] Use of hashlib's `.digest().hex()` + | +36 | sha256(b"text").digest().hex() +37 | +38 | hash_algo().digest().hex() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB181 +39 | +40 | # not yet supported + | + = help: Replace with `.hexdigest()` + +ℹ Unsafe fix +35 35 | +36 36 | sha256(b"text").digest().hex() +37 37 | +38 |-hash_algo().digest().hex() + 38 |+hash_algo().hexdigest() +39 39 | +40 40 | # not yet supported +41 41 | h = sha256() + + diff --git a/ruff.schema.json b/ruff.schema.json index 90228a59020d0..b7ddd6e209602 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -2879,6 +2879,8 @@ "FURB17", "FURB171", "FURB177", + "FURB18", + "FURB181", "G", "G0", "G00", From cd2bf26845e1f80afc216c55d92e16932ef8a8f8 Mon Sep 17 00:00:00 2001 From: konsti Date: Mon, 11 Dec 2023 09:47:38 +0100 Subject: [PATCH 155/197] Fix alpine CI (#9085) The builds are failing with > error: externally-managed-environment I've added a venv --- .github/workflows/release.yaml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 86eac6ebcdbf3..6b6ab5e9fee51 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -332,10 +332,10 @@ jobs: image: alpine:latest options: -v ${{ github.workspace }}:/io -w /io run: | - apk add py3-pip - pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links /io/dist/ --force-reinstall - ruff --help - python -m ruff --help + apk add python3 + python -m venv .venv + .venv/bin/pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall + .venv/bin/ruff check --help - name: "Upload wheels" uses: actions/upload-artifact@v3 with: @@ -388,10 +388,11 @@ jobs: distro: alpine_latest githubToken: ${{ github.token }} install: | - apk add py3-pip + apk add python3 run: | - pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall - ruff check --help + python -m venv .venv + .venv/bin/pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall + .venv/bin/ruff check --help - name: "Upload wheels" uses: actions/upload-artifact@v3 with: From b8dd499b2ac2fa3c150408615bf8a260bccd1101 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 08:50:00 +0000 Subject: [PATCH 156/197] Bump filetime from 0.2.22 to 0.2.23 (#9088) Bumps [filetime](https://github.com/alexcrichton/filetime) from 0.2.22 to 0.2.23.

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=filetime&package-manager=cargo&previous-version=0.2.22&new-version=0.2.23)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++--- Cargo.toml | 2 +- 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index faa41ca9c0e6b..09ddd444fcf73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -791,14 +791,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", - "windows-sys 0.48.0", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", ] [[package]] @@ -3645,6 +3645,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -3675,6 +3684,21 @@ dependencies = [ "windows_x86_64_msvc 0.48.5", ] +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -3687,6 +3711,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -3699,6 +3729,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -3711,6 +3747,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -3723,6 +3765,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -3735,6 +3783,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -3747,6 +3801,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -3759,6 +3819,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winnow" version = "0.5.15" diff --git a/Cargo.toml b/Cargo.toml index 3328c0c98968a..313a280e14915 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ bitflags = { version = "2.4.1" } chrono = { version = "0.4.31", default-features = false, features = ["clock"] } clap = { version = "4.4.7", features = ["derive"] } colored = { version = "2.0.0" } -filetime = { version = "0.2.20" } +filetime = { version = "0.2.23" } glob = { version = "0.3.1" } globset = { version = "0.4.14" } ignore = { version = "0.4.20" } From 93417b56441901d2e0ad8de002129a256bd919c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 08:50:09 +0000 Subject: [PATCH 157/197] Bump serde from 1.0.190 to 1.0.193 (#9087) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [serde](https://github.com/serde-rs/serde) from 1.0.190 to 1.0.193.
Release notes

Sourced from serde's releases.

v1.0.193

v1.0.192

v1.0.191

  • Documentation improvements
Commits
  • 44613c7 Release 1.0.193
  • c706281 Merge pull request #2655 from dtolnay/rangestartend
  • 65d75b8 Add RangeFrom and RangeTo tests
  • 332b0cb Merge pull request #2654 from dtolnay/rangestartend
  • 8c4af41 Fix more RangeFrom / RangeEnd mixups
  • 24a78f0 Merge pull request #2653 from emilbonnek/fix/range-to-from-de-mixup
  • c91c334 Fix Range{From,To} deserialize mixup
  • 2083f43 Update ui test suite to nightly-2023-11-19
  • 4676abd Release 1.0.192
  • 35700eb Merge pull request #2646 from robsdedude/fix/2643/allow-tag-field-in-untagged
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=serde&package-manager=cargo&previous-version=1.0.190&new-version=1.0.193)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 09ddd444fcf73..754ccbfc3af20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2677,9 +2677,9 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.190" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] @@ -2697,9 +2697,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.190" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 313a280e14915..b682546967487 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ quote = { version = "1.0.23" } regex = { version = "1.10.2" } rustc-hash = { version = "1.1.0" } schemars = { version = "0.8.16" } -serde = { version = "1.0.190", features = ["derive"] } +serde = { version = "1.0.193", features = ["derive"] } serde_json = { version = "1.0.108" } shellexpand = { version = "3.0.0" } similar = { version = "2.3.0", features = ["inline"] } From 4e461cbf03e875f0981cdd3607f21ef8ae271155 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 08:50:22 +0000 Subject: [PATCH 158/197] Bump syn from 2.0.39 to 2.0.40 (#9086) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.39 to 2.0.40.
Release notes

Sourced from syn's releases.

2.0.40

Commits
  • cf7f40a Release 2.0.40
  • 1ce8ccf Merge pull request #1538 from dtolnay/testinvisible
  • d06bff8 Add test for parsing Delimiter::None in expressions
  • 9ec66d4 Merge pull request #1545 from dtolnay/groupedlet
  • 384621a Fix None-delimited let expression in stmt position
  • 5325b6d Add test of let expr surrounded in None-delimited group
  • 0ddfc27 Merge pull request #1544 from dtolnay/nonedelimloop
  • 9c99b3f Fix stmt boundary after None-delimited group containing loop
  • 2781584 Add test of None-delimited group containing loop in match arm
  • d332928 Simplify token stream construction in Delimiter::None tests
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=syn&package-manager=cargo&previous-version=2.0.39&new-version=2.0.40)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 40 ++++++++++++++++++++-------------------- Cargo.toml | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 754ccbfc3af20..bf1e6bb38b38a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -382,7 +382,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -607,7 +607,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -618,7 +618,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -1131,7 +1131,7 @@ dependencies = [ "pmutil 0.6.1", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -1709,7 +1709,7 @@ checksum = "52a40bc70c2c58040d2d8b167ba9a5ff59fc9dab7ad44771cfde3dcfde7a09c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -2270,7 +2270,7 @@ dependencies = [ "proc-macro2", "quote", "ruff_python_trivia", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -2703,7 +2703,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -2765,7 +2765,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -2869,7 +2869,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -2885,9 +2885,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e" dependencies = [ "proc-macro2", "quote", @@ -2974,7 +2974,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -2986,7 +2986,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", "test-case-core", ] @@ -3007,7 +3007,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -3169,7 +3169,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -3387,7 +3387,7 @@ checksum = "f49e7f3f3db8040a100710a11932239fd30697115e2ba4107080d8252939845e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -3481,7 +3481,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", "wasm-bindgen-shared", ] @@ -3515,7 +3515,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3548,7 +3548,7 @@ checksum = "493fcbab756bb764fa37e6bee8cec2dd709eb4273d06d0c282a5e74275ded735" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -3881,5 +3881,5 @@ checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] diff --git a/Cargo.toml b/Cargo.toml index b682546967487..aea4613d4e959 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ smallvec = { version = "1.11.2" } static_assertions = "1.1.0" strum = { version = "0.25.0", features = ["strum_macros"] } strum_macros = { version = "0.25.3" } -syn = { version = "2.0.39" } +syn = { version = "2.0.40" } test-case = { version = "3.2.1" } thiserror = { version = "1.0.50" } toml = { version = "0.7.8" } From efb76ffa648e11ead2529353dfa6372237852aeb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 08:51:57 +0000 Subject: [PATCH 159/197] Bump is-macro from 0.3.0 to 0.3.1 (#9090) Bumps [is-macro](https://github.com/kdy1/is-macro) from 0.3.0 to 0.3.1.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=is-macro&package-manager=cargo&previous-version=0.3.0&new-version=0.3.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bf1e6bb38b38a..db68fc3a05462 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1123,9 +1123,9 @@ dependencies = [ [[package]] name = "is-macro" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4467ed1321b310c2625c5aa6c1b1ffc5de4d9e42668cf697a08fb033ee8265e" +checksum = "bc74b7abae208af9314a406bd7dcc65091230b6e749c09e07a645885fecf34f9" dependencies = [ "Inflector", "pmutil 0.6.1", diff --git a/Cargo.toml b/Cargo.toml index aea4613d4e959..304162dba62ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ glob = { version = "0.3.1" } globset = { version = "0.4.14" } ignore = { version = "0.4.20" } insta = { version = "1.34.0", feature = ["filters", "glob"] } -is-macro = { version = "0.3.0" } +is-macro = { version = "0.3.1" } itertools = { version = "0.11.0" } libcst = { version = "1.1.0", default-features = false } log = { version = "0.4.17" } From 3aa6a303950046b490e05d9ba23ac6baa8d3b830 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 08:52:07 +0000 Subject: [PATCH 160/197] Bump serde-wasm-bindgen from 0.6.1 to 0.6.3 (#9089) Bumps [serde-wasm-bindgen](https://github.com/RReverser/serde-wasm-bindgen) from 0.6.1 to 0.6.3.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=serde-wasm-bindgen&package-manager=cargo&previous-version=0.6.1&new-version=0.6.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- crates/ruff_wasm/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index db68fc3a05462..9b71a65a67481 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2686,9 +2686,9 @@ dependencies = [ [[package]] name = "serde-wasm-bindgen" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ba92964781421b6cef36bf0d7da26d201e96d84e1b10e7ae6ed416e516906d" +checksum = "b9b713f70513ae1f8d92665bbbbda5c295c2cf1da5542881ae5eefe20c9af132" dependencies = [ "js-sys", "serde", diff --git a/crates/ruff_wasm/Cargo.toml b/crates/ruff_wasm/Cargo.toml index d7b3190658cd6..7b5875a0bc440 100644 --- a/crates/ruff_wasm/Cargo.toml +++ b/crates/ruff_wasm/Cargo.toml @@ -36,7 +36,7 @@ console_log = { version = "1.0.0" } log = { workspace = true } serde = { workspace = true } -serde-wasm-bindgen = { version = "0.6.1" } +serde-wasm-bindgen = { version = "0.6.3" } wasm-bindgen = { version = "0.2.84" } js-sys = { version = "0.3.66" } From 07380e06573c793d37856261f7a968a4fe020154 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Mon, 11 Dec 2023 08:20:59 -0500 Subject: [PATCH 161/197] ruff_python_formatter: add docstring-code-line-width internal setting (#9055) ## Summary This does the light plumbing necessary to add a new internal option that permits setting the line width of code examples in docstrings. The plan is to add the corresponding user facing knob in #8854. Note that this effectively removes the `same-as-global` configuration style discussed [in this comment](https://github.com/astral-sh/ruff/issues/8855#issuecomment-1847230440). It replaces it with the `{integer}` configuration style only. There are a lot of commits here, but they are each tiny to make review easier because of the changes to snapshots. ## Test Plan I added a new docstring test configuration that sets `docstring-code-line-width = 60` and examined the differences. --- .../ruff/docstring_code_examples.options.json | 6 + .../src/expression/string/docstring.rs | 1 + crates/ruff_python_formatter/src/options.rs | 11 + .../ruff_python_formatter/tests/fixtures.rs | 18 +- .../tests/snapshots/format@docstring.py.snap | 85 +- .../format@docstring_code_examples.py.snap | 1512 ++++++++++++++++- ...ormat@docstring_code_examples_crlf.py.snap | 17 +- .../format@expression__bytes.py.snap | 34 +- .../format@expression__string.py.snap | 34 +- ...rmat@fmt_on_off__fmt_off_docstring.py.snap | 34 +- .../format@fmt_on_off__indent.py.snap | 51 +- ...at@fmt_on_off__mixed_space_and_tab.py.snap | 51 +- .../tests/snapshots/format@preview.py.snap | 34 +- .../snapshots/format@quote_style.py.snap | 51 +- .../format@skip_magic_trailing_comma.py.snap | 34 +- .../tests/snapshots/format@tab_width.py.snap | 51 +- 16 files changed, 1728 insertions(+), 296 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.options.json b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.options.json index b2a2d8a4e537d..75eee27329dfe 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.options.json @@ -38,5 +38,11 @@ "docstring_code": "enabled", "indent_style": "tab", "indent_width": 4 + }, + { + "docstring_code": "enabled", + "docstring_code_line_width": 60, + "indent_style": "space", + "indent_width": 4 } ] diff --git a/crates/ruff_python_formatter/src/expression/string/docstring.rs b/crates/ruff_python_formatter/src/expression/string/docstring.rs index 8dfa6001b7149..0fb03ce07d882 100644 --- a/crates/ruff_python_formatter/src/expression/string/docstring.rs +++ b/crates/ruff_python_formatter/src/expression/string/docstring.rs @@ -464,6 +464,7 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { .f .options() .clone() + .with_line_width(self.f.options().docstring_code_line_width()) // It's perhaps a little odd to be hard-coding the indent // style here, but I believe it is necessary as a result // of the whitespace normalization otherwise done in diff --git a/crates/ruff_python_formatter/src/options.rs b/crates/ruff_python_formatter/src/options.rs index 8ff979959cfe5..003cfea4bf041 100644 --- a/crates/ruff_python_formatter/src/options.rs +++ b/crates/ruff_python_formatter/src/options.rs @@ -49,6 +49,12 @@ pub struct PyFormatOptions { /// enabled by default (opt-out) in the future. docstring_code: DocstringCode, + /// The preferred line width at which the formatter should wrap lines in + /// docstring code examples. This only has an impact when `docstring_code` + /// is enabled. + #[cfg_attr(feature = "serde", serde(default = "default_line_width"))] + docstring_code_line_width: LineWidth, + /// Whether preview style formatting is enabled or not preview: PreviewMode, } @@ -77,6 +83,7 @@ impl Default for PyFormatOptions { magic_trailing_comma: MagicTrailingComma::default(), source_map_generation: SourceMapGeneration::default(), docstring_code: DocstringCode::default(), + docstring_code_line_width: default_line_width(), preview: PreviewMode::default(), } } @@ -119,6 +126,10 @@ impl PyFormatOptions { self.docstring_code } + pub fn docstring_code_line_width(&self) -> LineWidth { + self.docstring_code_line_width + } + pub const fn preview(&self) -> PreviewMode { self.preview } diff --git a/crates/ruff_python_formatter/tests/fixtures.rs b/crates/ruff_python_formatter/tests/fixtures.rs index 3c48027d98408..a425a1e597bd1 100644 --- a/crates/ruff_python_formatter/tests/fixtures.rs +++ b/crates/ruff_python_formatter/tests/fixtures.rs @@ -347,14 +347,15 @@ impl fmt::Display for DisplayPyOptions<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { writeln!( f, - r#"indent-style = {indent_style} -line-width = {line_width} -indent-width = {indent_width} -quote-style = {quote_style:?} -line-ending = {line_ending:?} -magic-trailing-comma = {magic_trailing_comma:?} -docstring-code = {docstring_code:?} -preview = {preview:?}"#, + r#"indent-style = {indent_style} +line-width = {line_width} +indent-width = {indent_width} +quote-style = {quote_style:?} +line-ending = {line_ending:?} +magic-trailing-comma = {magic_trailing_comma:?} +docstring-code = {docstring_code:?} +docstring-code-line-width = {docstring_code_line_width:?} +preview = {preview:?}"#, indent_style = self.0.indent_style(), indent_width = self.0.indent_width().value(), line_width = self.0.line_width().value(), @@ -362,6 +363,7 @@ preview = {preview:?}"#, line_ending = self.0.line_ending(), magic_trailing_comma = self.0.magic_trailing_comma(), docstring_code = self.0.docstring_code(), + docstring_code_line_width = self.0.docstring_code_line_width().value(), preview = self.0.preview() ) } diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap index 84e737e97a6c6..98220dcff890a 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap @@ -166,14 +166,15 @@ def single_quoted(): ## Outputs ### Output 1 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -339,14 +340,15 @@ def single_quoted(): ### Output 2 ``` -indent-style = space -line-width = 88 -indent-width = 2 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 2 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -512,14 +514,15 @@ def single_quoted(): ### Output 3 ``` -indent-style = tab -line-width = 88 -indent-width = 8 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = tab +line-width = 88 +indent-width = 8 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -685,14 +688,15 @@ def single_quoted(): ### Output 4 ``` -indent-style = tab -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = tab +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -858,14 +862,15 @@ def single_quoted(): ### Output 5 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Single -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Single +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap index ce33622b634f1..e0c672c090b0c 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap @@ -1359,14 +1359,15 @@ def markdown_skipped_rst_directive(): ## Outputs ### Output 1 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -2728,14 +2729,15 @@ def markdown_skipped_rst_directive(): ### Output 2 ``` -indent-style = space -line-width = 88 -indent-width = 2 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 2 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -4097,14 +4099,15 @@ def markdown_skipped_rst_directive(): ### Output 3 ``` -indent-style = tab -line-width = 88 -indent-width = 8 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = tab +line-width = 88 +indent-width = 8 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -5466,14 +5469,15 @@ def markdown_skipped_rst_directive(): ### Output 4 ``` -indent-style = tab -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = tab +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -6835,14 +6839,15 @@ def markdown_skipped_rst_directive(): ### Output 5 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Enabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -8199,14 +8204,15 @@ def markdown_skipped_rst_directive(): ### Output 6 ``` -indent-style = space -line-width = 88 -indent-width = 2 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Enabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 2 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -9563,14 +9569,15 @@ def markdown_skipped_rst_directive(): ### Output 7 ``` -indent-style = tab -line-width = 88 -indent-width = 8 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Enabled -preview = Disabled +indent-style = tab +line-width = 88 +indent-width = 8 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -10927,14 +10934,15 @@ def markdown_skipped_rst_directive(): ### Output 8 ``` -indent-style = tab -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Enabled -preview = Disabled +indent-style = tab +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -12289,4 +12297,1380 @@ def markdown_skipped_rst_directive(): ``` +### Output 9 +``` +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +docstring-code-line-width = 60 +preview = Disabled +``` + +```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff(1) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(f"hi {x}") + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff(x) + >>> cool_stuff(y) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff(x) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(f"hi {x}") + """ + pass + + +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. + + >>> cool_stuff(x)""" + pass + + +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. + + >>> cool_stuff(x) + ... more(y)""" + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... + ... print(x) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print(x) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print(x) + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested(x): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey + ... ) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line( + ... lion, + ... giraffe, + ... hippo, + ... zeba, + ... lemur, + ... penguin, + ... monkey, + ... spider, + ... bear, + ... leopard, + ... ) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass + + +############################################################################### +# reStructuredText CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# reStructuredText formatted code blocks. +# +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +############################################################################### + + +def rst_literal_simple(): + """ + Do cool stuff:: + + cool_stuff(1) + + Done. + """ + pass + + +def rst_literal_simple_continued(): + """ + Do cool stuff:: + + def cool_stuff(x): + print(f"hi {x}") + + Done. + """ + pass + + +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: + + cool_stuff(1) + """ + pass + + +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: + + cool_stuff(1)""" + pass + + +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: + + def cool_stuff(x): + print(f"hi {x}") + + + def other_stuff(y): + print(y) + + Done. + """ + pass + + +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: + + + + cool_stuff(1) + + + + Done. + """ + pass + + +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: + + + cool_stuff(1) + + + + """ + pass + + +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: + + cool_stuff(1) + + + cool_stuff(2) + + Done. + """ + pass + + +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( + ''' + hiya''' + ) + + Done. + """ + pass + + +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff:: + + cool_stuff(1) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff(1) + cool_stuff(2) + + Done. + """ + pass + + +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + + cool_stuff(1) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff(1) + cool_stuff(2) + + Done. + """ + pass + + +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): + """ + Do cool stuff:: + + cool_stuff(1) + cool_stuff(2) + + Done. + """ + pass + + +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. +# +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: + + cool_stuff(1) + cool_stuff(2) + + Done. + """ + pass + + +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ + Do cool stuff. + + :: + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_simple(): + """ + .. code-block:: python + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_case_insensitive(): + """ + .. cOdE-bLoCk:: python + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_sourcecode(): + """ + .. sourcecode:: python + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + + cool_stuff(1) + cool_stuff(2) + cool_stuff(3) + cool_stuff(4) + + Done. + """ + pass + + +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon + + >>> cool_stuff(1) + + Done. + """ + pass + + +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. +# +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_literal_skipped_markdown(): + """ + Do cool stuff:: + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +############################################################################### +# Markdown CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Markdown fenced code blocks. +# +# See: https://spec.commonmark.org/0.30/#fenced-code-blocks +############################################################################### + + +def markdown_simple(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ``` + + Done. + """ + pass + + +def markdown_simple_continued(): + """ + Do cool stuff. + + ```python + def cool_stuff(x): + print(f"hi {x}") + ``` + + Done. + """ + pass + + +# Tests that unlabeled Markdown fenced code blocks are assumed to be Python. +def markdown_unlabeled(): + """ + Do cool stuff. + + ``` + cool_stuff(1) + ``` + + Done. + """ + pass + + +# Tests that fenced code blocks using tildes work. +def markdown_tildes(): + """ + Do cool stuff. + + ~~~py + cool_stuff(1) + ~~~ + + Done. + """ + pass + + +# Tests that a longer closing fence is just fine and dandy. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + `````` + + Done. + """ + pass + + +# Tests that an invalid closing fence is treated as invalid. +# +# We embed it into a docstring so that the surrounding Python +# remains valid. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ''' + ```invalid + ''' + cool_stuff(2) + ``` + + Done. + """ + pass + + +# Tests that one can nest fenced code blocks by using different numbers of +# backticks. +def markdown_nested_fences(): + """ + Do cool stuff. + + `````` + do_something( + ''' + ``` + did i trick you? + ``` + ''' + ) + `````` + + Done. + """ + pass + + +# Tests that an unclosed block gobbles up everything remaining in the +# docstring. When it's only empty lines, those are passed into the formatter +# and thus stripped. +def markdown_unclosed_empty_lines(): + """ + Do cool stuff. + + ```py + cool_stuff(1)""" + pass + + +# Tests that we can end the block on the second to last line of the +# docstring. +def markdown_second_to_last(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ``` + """ + pass + + +# Tests that an unclosed block with one extra line at the end is treated +# correctly. As per the CommonMark spec, an unclosed fenced code block contains +# everything following the opening fences. Since formatting the code snippet +# trims lines, the last empty line is removed here. +def markdown_second_to_last(): + """ + Do cool stuff. + + ```py + cool_stuff(1)""" + pass + + +# Tests that we can end the block on the actual last line of the docstring. +def markdown_actually_last(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ```""" + pass + + +# Tests that an unclosed block that ends on the last line of a docstring +# is handled correctly. +def markdown_unclosed_actually_last(): + """ + Do cool stuff. + + ```py + cool_stuff(1)""" + pass + + +def markdown_with_blank_lines(): + """ + Do cool stuff. + + ```py + def cool_stuff(x): + print(f"hi {x}") + + + def other_stuff(y): + print(y) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + cool_stuff(2) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + cool_stuff(2) + ``` + + Done. + """ + pass + + +def markdown_first_line_tab_second_line_spaces(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + cool_stuff(2) + ``` + + Done. + """ + pass + + +def markdown_odd_indentation(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + cool_stuff(2) + ``` + + Done. + """ + pass + + +# Extra blanks should be *not* be preserved (unlike reST) because they are part +# of the code snippet (per CommonMark spec), and thus get trimmed as part of +# code formatting. +def markdown_extra_blanks(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ``` + + Done. + """ + pass + + +# A block can contain many empty lines within it. +def markdown_extra_blanks_in_snippet(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + + + cool_stuff(2) + ``` + + Done. + """ + pass + + +def markdown_weird_closing(): + """ + Code block with weirdly placed closing fences. + + ```python + cool_stuff(1) + ``` + # The above fences look like it shouldn't close the block, but we + # allow it to. The fences below re-open a block (until the end of + # the docstring), but it's invalid Python and thus doesn't get + # reformatted. + a = 10 + ``` + + Now the code block is closed + """ + pass + + +def markdown_over_indented(): + """ + A docstring + over intended + ```python + print(5) + ``` + """ + pass + + +# This tests that we can have additional text after the language specifier. +def markdown_additional_info_string(): + """ + Do cool stuff. + + ```python tab="plugin.py" + cool_stuff(1) + ``` + + Done. + """ + pass + + +# Tests that an unclosed block gobbles up everything remaining in the +# docstring, even if it isn't valid Python. Since it isn't valid Python, +# reformatting fails and the entire thing is skipped. +def markdown_skipped_unclosed_non_python(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + + I forgot to close the code block, and this is definitely not + Python. So nothing here gets formatted. + """ + pass + + +# This has a Python snippet with a docstring that contains a closing fence. +# This splits the embedded docstring and makes the overall snippet invalid. +def markdown_skipped_accidental_closure(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ''' + ``` + ''' + ``` + + Done. + """ + pass + + +# When a line is unindented all the way out before the standard indent of the +# docstring, the code reformatting ends up interacting poorly with the standard +# docstring whitespace normalization logic. This is probably a bug, and we +# should probably treat the Markdown block as valid, but for now, we detect +# the unindented line and declare the block as invalid and thus do no code +# reformatting. +# +# FIXME: Fixing this (if we think it's a bug) probably requires refactoring the +# docstring whitespace normalization to be aware of code snippets. Or perhaps +# plausibly, to do normalization *after* code snippets have been formatted. +def markdown_skipped_unindented_completely(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# This test is fallout from treating fenced code blocks with unindented lines +# as invalid. We probably should treat this as a valid block. Indeed, if we +# remove the logic that makes the `markdown_skipped_unindented_completely` test +# pass, then this code snippet will get reformatted correctly. +def markdown_skipped_unindented_somewhat(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# This tests that if a Markdown block contains a line that has less of an +# indent than another line. +# +# There is some judgment involved in what the right behavior is here. We +# could "normalize" the indentation so that the minimum is the indent of the +# opening fence line. If we did that here, then the code snippet would become +# valid and format as Python. But at time of writing, we don't, which leads to +# inconsistent indentation and thus invalid Python. +def markdown_skipped_unindented_with_inconsistent_indentation(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_skipped_doctest(): + """ + Do cool stuff. + + ```py + >>> cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_skipped_rst_literal(): + """ + Do cool stuff. + + ```py + And do this:: + + cool_stuff( 1 ) + + ``` + + Done. + """ + pass + + +def markdown_skipped_rst_directive(): + """ + Do cool stuff. + + ```py + .. code-block:: python + + cool_stuff( 1 ) + + ``` + + Done. + """ + pass +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap index 7391fb69387a6..347c3cc2a8388 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap @@ -18,14 +18,15 @@ def doctest_line_ending(): ## Outputs ### Output 1 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = CarriageReturnLineFeed -magic-trailing-comma = Respect -docstring-code = Enabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = CarriageReturnLineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap index ba906f5a34567..fc89a38635108 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap @@ -129,14 +129,15 @@ test_particular = [ ## Outputs ### Output 1 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -280,14 +281,15 @@ test_particular = [ ### Output 2 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Single -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Single +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap index af7a9ecb62130..0829244eb68b4 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap @@ -144,14 +144,15 @@ trailing_preferred_quote_texts = [''' "''', ''' ""''', ''' """''', ''' """"'''] ## Outputs ### Output 1 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -319,14 +320,15 @@ trailing_preferred_quote_texts = [''' "''', ''' ""''', ''' """''', ''' """"'''] ### Output 2 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Single -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Single +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python diff --git a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap index cd2da8896be2c..2080aa4a52451 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap @@ -28,14 +28,15 @@ def test(): ## Outputs ### Output 1 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -63,14 +64,15 @@ def test(): ### Output 2 ``` -indent-style = space -line-width = 88 -indent-width = 2 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 2 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python diff --git a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap index 12a58faa13871..a0c8fd1ef68e4 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap @@ -9,14 +9,15 @@ input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/fmt_on_off ## Outputs ### Output 1 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -25,14 +26,15 @@ preview = Disabled ### Output 2 ``` -indent-style = space -line-width = 88 -indent-width = 1 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 1 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -41,14 +43,15 @@ preview = Disabled ### Output 3 ``` -indent-style = tab -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = tab +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python diff --git a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap index 54e970077c352..2ff76b7092a66 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap @@ -24,14 +24,15 @@ not_fixed ## Outputs ### Output 1 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -56,14 +57,15 @@ not_fixed ### Output 2 ``` -indent-style = space -line-width = 88 -indent-width = 2 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 2 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -88,14 +90,15 @@ not_fixed ### Output 3 ``` -indent-style = tab -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = tab +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python diff --git a/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap index c3504c47f856c..eedd65bade86d 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap @@ -75,14 +75,15 @@ def f(): ## Outputs ### Output 1 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -156,14 +157,15 @@ def f(): ### Output 2 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Enabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Enabled ``` ```python diff --git a/crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap index b78c7666e9636..9bce249d23c2f 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap @@ -59,14 +59,15 @@ def docstring_single(): ## Outputs ### Output 1 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Single -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Single +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -129,14 +130,15 @@ def docstring_single(): ### Output 2 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -199,14 +201,15 @@ def docstring_single(): ### Output 3 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Preserve -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Preserve +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python diff --git a/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap index 4add8537b1d2c..b7e43061b7da2 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap @@ -42,14 +42,15 @@ with (a,): # magic trailing comma ## Outputs ### Output 1 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -97,14 +98,15 @@ with ( ### Output 2 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Ignore -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Ignore +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python diff --git a/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap index d57334c7caf6e..9f39a521a260a 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap @@ -17,14 +17,15 @@ input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/tab_width. ## Outputs ### Output 1 ``` -indent-style = space -line-width = 88 -indent-width = 2 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 2 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -41,14 +42,15 @@ preview = Disabled ### Output 2 ``` -indent-style = space -line-width = 88 -indent-width = 4 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python @@ -68,14 +70,15 @@ preview = Disabled ### Output 3 ``` -indent-style = space -line-width = 88 -indent-width = 8 -quote-style = Double -line-ending = LineFeed -magic-trailing-comma = Respect -docstring-code = Disabled -preview = Disabled +indent-style = space +line-width = 88 +indent-width = 8 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Disabled ``` ```python From f452bf8cade30fea1bb6019cb62d23cff074b9dd Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 11 Dec 2023 12:06:25 -0500 Subject: [PATCH 162/197] Allow `matplotlib.use` calls to intersperse imports (#9094) This PR allows `matplotlib.use` calls to intersperse imports without triggering `E402`. This is a pragmatic choice as it's common to require `matplotlib.use` calls prior to importing from within `matplotlib` itself. Closes https://github.com/astral-sh/ruff/issues/9091. --- .../test/fixtures/pycodestyle/E402.py | 18 +++++--- crates/ruff_linter/src/checkers/ast/mod.rs | 1 + ...les__pycodestyle__tests__E402_E402.py.snap | 44 ++++++++++++++----- ...destyle__tests__preview__E402_E402.py.snap | 24 +++++----- .../src/analyze/imports.rs | 18 ++++++++ 5 files changed, 75 insertions(+), 30 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E402.py b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E402.py index 8910ff6007e5f..fdd0e32ee29f8 100644 --- a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E402.py +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E402.py @@ -24,21 +24,27 @@ import f -__some__magic = 1 +import matplotlib + +matplotlib.use("Agg") import g +__some__magic = 1 + +import h + def foo() -> None: - import h + import i if __name__ == "__main__": - import i + import j -import j; import k +import k; import l if __name__ == "__main__": - import l; \ -import m + import m; \ +import n diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 6c347af7d1844..5d525550f5375 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -306,6 +306,7 @@ where if !(self.semantic.seen_import_boundary() || helpers::is_assignment_to_a_dunder(stmt) || helpers::in_nested_block(self.semantic.current_statements()) + || imports::is_matplotlib_activation(stmt, self.semantic()) || self.settings.preview.is_enabled() && imports::is_sys_path_modification(stmt, self.semantic())) { diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E402_E402.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E402_E402.py.snap index 44d7f5870ac56..072290ae87cf6 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E402_E402.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E402_E402.py.snap @@ -8,30 +8,50 @@ E402.py:25:1: E402 Module level import not at top of file 25 | import f | ^^^^^^^^ E402 26 | -27 | __some__magic = 1 +27 | import matplotlib | -E402.py:29:1: E402 Module level import not at top of file +E402.py:27:1: E402 Module level import not at top of file | -27 | __some__magic = 1 +25 | import f +26 | +27 | import matplotlib + | ^^^^^^^^^^^^^^^^^ E402 28 | -29 | import g +29 | matplotlib.use("Agg") + | + +E402.py:31:1: E402 Module level import not at top of file + | +29 | matplotlib.use("Agg") +30 | +31 | import g + | ^^^^^^^^ E402 +32 | +33 | __some__magic = 1 + | + +E402.py:35:1: E402 Module level import not at top of file + | +33 | __some__magic = 1 +34 | +35 | import h | ^^^^^^^^ E402 | -E402.py:39:1: E402 Module level import not at top of file +E402.py:45:1: E402 Module level import not at top of file | -37 | import i -38 | -39 | import j; import k +43 | import j +44 | +45 | import k; import l | ^^^^^^^^ E402 | -E402.py:39:11: E402 Module level import not at top of file +E402.py:45:11: E402 Module level import not at top of file | -37 | import i -38 | -39 | import j; import k +43 | import j +44 | +45 | import k; import l | ^^^^^^^^ E402 | diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__preview__E402_E402.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__preview__E402_E402.py.snap index cf3a61872dd85..7ec9e200b32e7 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__preview__E402_E402.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__preview__E402_E402.py.snap @@ -1,27 +1,27 @@ --- source: crates/ruff_linter/src/rules/pycodestyle/mod.rs --- -E402.py:29:1: E402 Module level import not at top of file +E402.py:35:1: E402 Module level import not at top of file | -27 | __some__magic = 1 -28 | -29 | import g +33 | __some__magic = 1 +34 | +35 | import h | ^^^^^^^^ E402 | -E402.py:39:1: E402 Module level import not at top of file +E402.py:45:1: E402 Module level import not at top of file | -37 | import i -38 | -39 | import j; import k +43 | import j +44 | +45 | import k; import l | ^^^^^^^^ E402 | -E402.py:39:11: E402 Module level import not at top of file +E402.py:45:11: E402 Module level import not at top of file | -37 | import i -38 | -39 | import j; import k +43 | import j +44 | +45 | import k; import l | ^^^^^^^^ E402 | diff --git a/crates/ruff_python_semantic/src/analyze/imports.rs b/crates/ruff_python_semantic/src/analyze/imports.rs index cc9d219775b2f..a4a9ddc134486 100644 --- a/crates/ruff_python_semantic/src/analyze/imports.rs +++ b/crates/ruff_python_semantic/src/analyze/imports.rs @@ -35,3 +35,21 @@ pub fn is_sys_path_modification(stmt: &Stmt, semantic: &SemanticModel) -> bool { ) }) } + +/// Returns `true` if a [`Stmt`] is a `matplotlib.use` activation, as in: +/// ```python +/// import matplotlib +/// +/// matplotlib.use("Agg") +/// ``` +pub fn is_matplotlib_activation(stmt: &Stmt, semantic: &SemanticModel) -> bool { + let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt else { + return false; + }; + let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() else { + return false; + }; + semantic + .resolve_call_path(func.as_ref()) + .is_some_and(|call_path| matches!(call_path.as_slice(), ["matplotlib", "use"])) +} From 1026ece9467b8d10aad4bbe6958eea6f176abf19 Mon Sep 17 00:00:00 2001 From: Samuel Cormier-Iijima Date: Mon, 11 Dec 2023 15:25:31 -0500 Subject: [PATCH 163/197] E274: allow tab indentation before keyword (#9099) ## Summary E274 currently flags any keyword at the start of a line indented with tabs. This turns out to be due to a bug in `Whitespace::trailing` that never considers any whitespace containing a tab as indentation. ## Test Plan Added a simple test case. --- .../resources/test/fixtures/pycodestyle/E27.py | 3 +++ .../rules/pycodestyle/rules/logical_lines/mod.rs | 14 +++++--------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E27.py b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E27.py index 576e43ae01300..7fb6fbb4f021b 100644 --- a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E27.py +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E27.py @@ -60,3 +60,6 @@ def f(): if (a and b): pass +#: Okay +def f(): + return 1 diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/mod.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/mod.rs index 8fcfca6d769ef..329116eca9b1d 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/mod.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/mod.rs @@ -381,20 +381,16 @@ impl Whitespace { } } - if has_tabs { + if len == content.text_len() { + // All whitespace up to the start of the line -> Indent + (Self::None, TextSize::default()) + } else if has_tabs { (Self::Tab, len) } else { match count { 0 => (Self::None, TextSize::default()), 1 => (Self::Single, len), - _ => { - if len == content.text_len() { - // All whitespace up to the start of the line -> Indent - (Self::None, TextSize::default()) - } else { - (Self::Many, len) - } - } + _ => (Self::Many, len), } } } From a53d59f6bdf309a9b7a0970fe2b88f5141410e69 Mon Sep 17 00:00:00 2001 From: Tuomas Siipola Date: Mon, 11 Dec 2023 22:47:37 +0200 Subject: [PATCH 164/197] Support floating-point base in FURB163 (#9100) ## Summary Check floating-point numbers similarly to integers in FURB163. For example, both `math.log(x, 10)` and `math.log(x, 10.0)` should be changed to `math.log10(x)`. ## Test Plan Added couple of test cases. --- .../resources/test/fixtures/refurb/FURB163.py | 5 ++ .../rules/refurb/rules/redundant_log_base.rs | 3 + ...es__refurb__tests__FURB163_FURB163.py.snap | 58 ++++++++++++++++--- 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/refurb/FURB163.py b/crates/ruff_linter/resources/test/fixtures/refurb/FURB163.py index 1f2255be8ef74..52b6619badb33 100644 --- a/crates/ruff_linter/resources/test/fixtures/refurb/FURB163.py +++ b/crates/ruff_linter/resources/test/fixtures/refurb/FURB163.py @@ -16,6 +16,8 @@ special_log(1, 10) special_log(1, math.e) special_log(1, special_e) +math.log(1, 2.0) +math.log(1, 10.0) # Ok. math.log2(1) @@ -45,3 +47,6 @@ def log(*args): log(1, 2) log(1, 10) log(1, math.e) + +math.log(1, 2.0001) +math.log(1, 10.0001) diff --git a/crates/ruff_linter/src/rules/refurb/rules/redundant_log_base.rs b/crates/ruff_linter/src/rules/refurb/rules/redundant_log_base.rs index a4a6e58959326..c7d6837d75699 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/redundant_log_base.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/redundant_log_base.rs @@ -130,6 +130,9 @@ fn is_number_literal(expr: &Expr, value: i8) -> bool { if let Expr::NumberLiteral(number_literal) = expr { if let Number::Int(number) = &number_literal.value { return number.as_i8().is_some_and(|number| number == value); + } else if let Number::Float(number) = number_literal.value { + #[allow(clippy::float_cmp)] + return number == f64::from(value); } } false diff --git a/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB163_FURB163.py.snap b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB163_FURB163.py.snap index e6441a4c1e3e0..aeb83174daee1 100644 --- a/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB163_FURB163.py.snap +++ b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB163_FURB163.py.snap @@ -187,7 +187,7 @@ FURB163.py:16:1: FURB163 [*] Prefer `math.log10(1)` over `math.log` with a redun 16 |+math.log10(1) 17 17 | special_log(1, math.e) 18 18 | special_log(1, special_e) -19 19 | +19 19 | math.log(1, 2.0) FURB163.py:17:1: FURB163 [*] Prefer `math.log(1)` over `math.log` with a redundant base | @@ -196,6 +196,7 @@ FURB163.py:17:1: FURB163 [*] Prefer `math.log(1)` over `math.log` with a redunda 17 | special_log(1, math.e) | ^^^^^^^^^^^^^^^^^^^^^^ FURB163 18 | special_log(1, special_e) +19 | math.log(1, 2.0) | = help: Replace with `math.log(1)` @@ -206,8 +207,8 @@ FURB163.py:17:1: FURB163 [*] Prefer `math.log(1)` over `math.log` with a redunda 17 |-special_log(1, math.e) 17 |+math.log(1) 18 18 | special_log(1, special_e) -19 19 | -20 20 | # Ok. +19 19 | math.log(1, 2.0) +20 20 | math.log(1, 10.0) FURB163.py:18:1: FURB163 [*] Prefer `math.log(1)` over `math.log` with a redundant base | @@ -215,8 +216,8 @@ FURB163.py:18:1: FURB163 [*] Prefer `math.log(1)` over `math.log` with a redunda 17 | special_log(1, math.e) 18 | special_log(1, special_e) | ^^^^^^^^^^^^^^^^^^^^^^^^^ FURB163 -19 | -20 | # Ok. +19 | math.log(1, 2.0) +20 | math.log(1, 10.0) | = help: Replace with `math.log(1)` @@ -226,8 +227,49 @@ FURB163.py:18:1: FURB163 [*] Prefer `math.log(1)` over `math.log` with a redunda 17 17 | special_log(1, math.e) 18 |-special_log(1, special_e) 18 |+math.log(1) -19 19 | -20 20 | # Ok. -21 21 | math.log2(1) +19 19 | math.log(1, 2.0) +20 20 | math.log(1, 10.0) +21 21 | + +FURB163.py:19:1: FURB163 [*] Prefer `math.log2(1)` over `math.log` with a redundant base + | +17 | special_log(1, math.e) +18 | special_log(1, special_e) +19 | math.log(1, 2.0) + | ^^^^^^^^^^^^^^^^ FURB163 +20 | math.log(1, 10.0) + | + = help: Replace with `math.log2(1)` + +ℹ Safe fix +16 16 | special_log(1, 10) +17 17 | special_log(1, math.e) +18 18 | special_log(1, special_e) +19 |-math.log(1, 2.0) + 19 |+math.log2(1) +20 20 | math.log(1, 10.0) +21 21 | +22 22 | # Ok. + +FURB163.py:20:1: FURB163 [*] Prefer `math.log10(1)` over `math.log` with a redundant base + | +18 | special_log(1, special_e) +19 | math.log(1, 2.0) +20 | math.log(1, 10.0) + | ^^^^^^^^^^^^^^^^^ FURB163 +21 | +22 | # Ok. + | + = help: Replace with `math.log10(1)` + +ℹ Safe fix +17 17 | special_log(1, math.e) +18 18 | special_log(1, special_e) +19 19 | math.log(1, 2.0) +20 |-math.log(1, 10.0) + 20 |+math.log10(1) +21 21 | +22 22 | # Ok. +23 23 | math.log2(1) From 108260298fe9079d09a3272830949e7a5d5c4bec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 15:49:32 -0500 Subject: [PATCH 165/197] Bump actions/setup-python from 4 to 5 (#9084) --- .github/workflows/ci.yaml | 10 +++++----- .github/workflows/docs.yaml | 2 +- .github/workflows/flake8-to-ruff.yaml | 16 ++++++++-------- .github/workflows/release.yaml | 16 ++++++++-------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4ab9aec9000e8..f4649c34617f0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -215,7 +215,7 @@ jobs: }} steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} @@ -338,7 +338,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} architecture: x64 @@ -362,7 +362,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: "Install Rust toolchain" @@ -392,7 +392,7 @@ jobs: MKDOCS_INSIDERS_SSH_KEY_EXISTS: ${{ secrets.MKDOCS_INSIDERS_SSH_KEY != '' }} steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 - name: "Add SSH key" if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }} uses: webfactory/ssh-agent@v0.8.0 @@ -455,7 +455,7 @@ jobs: with: repository: "astral-sh/ruff-lsp" - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 992ca27a9389f..13bf7a87598c9 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 - name: "Add SSH key" if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }} uses: webfactory/ssh-agent@v0.8.0 diff --git a/.github/workflows/flake8-to-ruff.yaml b/.github/workflows/flake8-to-ruff.yaml index feb1c2825aa9d..ebc38cb4fea56 100644 --- a/.github/workflows/flake8-to-ruff.yaml +++ b/.github/workflows/flake8-to-ruff.yaml @@ -20,7 +20,7 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} architecture: x64 @@ -43,7 +43,7 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} architecture: x64 @@ -69,7 +69,7 @@ jobs: target: [x64, x86] steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} architecture: ${{ matrix.target }} @@ -97,7 +97,7 @@ jobs: target: [x86_64, i686] steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} architecture: x64 @@ -124,7 +124,7 @@ jobs: target: [aarch64, armv7, s390x, ppc64le, ppc64] steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: "Build wheels" @@ -161,7 +161,7 @@ jobs: - i686-unknown-linux-musl steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} architecture: x64 @@ -197,7 +197,7 @@ jobs: arch: armv7 steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: "Build wheels" @@ -237,7 +237,7 @@ jobs: - uses: actions/download-artifact@v3 with: name: wheels - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 - name: "Publish to PyPi" env: TWINE_USERNAME: __token__ diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6b6ab5e9fee51..368bd3bff0641 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -36,7 +36,7 @@ jobs: - uses: actions/checkout@v4 with: ref: ${{ inputs.sha }} - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: "Prep README.md" @@ -63,7 +63,7 @@ jobs: - uses: actions/checkout@v4 with: ref: ${{ inputs.sha }} - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} architecture: x64 @@ -103,7 +103,7 @@ jobs: - uses: actions/checkout@v4 with: ref: ${{ inputs.sha }} - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} architecture: x64 @@ -151,7 +151,7 @@ jobs: - uses: actions/checkout@v4 with: ref: ${{ inputs.sha }} - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} architecture: ${{ matrix.platform.arch }} @@ -199,7 +199,7 @@ jobs: - uses: actions/checkout@v4 with: ref: ${{ inputs.sha }} - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} architecture: x64 @@ -258,7 +258,7 @@ jobs: - uses: actions/checkout@v4 with: ref: ${{ inputs.sha }} - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: "Prep README.md" @@ -313,7 +313,7 @@ jobs: - uses: actions/checkout@v4 with: ref: ${{ inputs.sha }} - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} architecture: x64 @@ -369,7 +369,7 @@ jobs: - uses: actions/checkout@v4 with: ref: ${{ inputs.sha }} - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: "Prep README.md" From 2993c342d2fecb7946ecbc1c5ad70567d62abb48 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 11 Dec 2023 15:50:01 -0500 Subject: [PATCH 166/197] Add beta note to the formatter docs (#9097) Closes https://github.com/astral-sh/ruff/issues/9092. --- docs/formatter.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/formatter.md b/docs/formatter.md index bbbc944c00f76..14d35e94a2dcd 100644 --- a/docs/formatter.md +++ b/docs/formatter.md @@ -1,7 +1,10 @@ # The Ruff Formatter The Ruff formatter is an extremely fast Python code formatter designed as a drop-in replacement for -[Black](https://pypi.org/project/black/), available as part of the `ruff` CLI (as of Ruff v0.0.289). +[Black](https://pypi.org/project/black/), available as part of the `ruff` CLI via `ruff format`. + +The Ruff formatter is available as a [production-ready Beta](https://astral.sh/blog/the-ruff-formatter) +as of Ruff v0.1.2. ## `ruff format` From 8e9bf840475c4a1bfaeb3844b082344d273fbfa9 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Mon, 11 Dec 2023 15:42:53 -0600 Subject: [PATCH 167/197] Hide unsafe fix suggestions when explicitly disabled (#9095) Hides hints about unsafe fixes when they are disabled e.g. with `--no-unsafe-fixes` or `unsafe-fixes = false`. By default, unsafe fix hints are still displayed. This seems like a nice way to remove the nag for users who have chosen not to apply unsafe fixes. Inspired by comment at https://github.com/astral-sh/ruff/issues/9063#issuecomment-1850289675 --- crates/ruff_cli/src/printer.rs | 18 +++++------ crates/ruff_cli/tests/integration_test.rs | 38 +++++++++++++++++++++++ crates/ruff_linter/src/settings/types.rs | 11 +++++-- crates/ruff_workspace/src/options.rs | 4 ++- docs/linter.md | 3 ++ ruff.schema.json | 2 +- 6 files changed, 62 insertions(+), 14 deletions(-) diff --git a/crates/ruff_cli/src/printer.rs b/crates/ruff_cli/src/printer.rs index 6f22f37d1608e..228c124d68569 100644 --- a/crates/ruff_cli/src/printer.rs +++ b/crates/ruff_cli/src/printer.rs @@ -125,15 +125,7 @@ impl Printer { if let Some(fixables) = fixables { let fix_prefix = format!("[{}]", "*".cyan()); - if self.unsafe_fixes.is_enabled() { - if fixables.applicable > 0 { - writeln!( - writer, - "{fix_prefix} {} fixable with the --fix option.", - fixables.applicable - )?; - } - } else { + if self.unsafe_fixes.is_hint() { if fixables.applicable > 0 && fixables.unapplicable_unsafe > 0 { let es = if fixables.unapplicable_unsafe == 1 { "" @@ -163,6 +155,14 @@ impl Printer { fixables.unapplicable_unsafe )?; } + } else { + if fixables.applicable > 0 { + writeln!( + writer, + "{fix_prefix} {} fixable with the --fix option.", + fixables.applicable + )?; + } } } } else { diff --git a/crates/ruff_cli/tests/integration_test.rs b/crates/ruff_cli/tests/integration_test.rs index 37c18551c2dbc..1ee634f6c09d3 100644 --- a/crates/ruff_cli/tests/integration_test.rs +++ b/crates/ruff_cli/tests/integration_test.rs @@ -1158,6 +1158,44 @@ fn check_hints_hidden_unsafe_fixes_with_no_safe_fixes() { "###); } +#[test] +fn check_no_hint_for_hidden_unsafe_fixes_when_disabled() { + let mut cmd = RuffCheck::default() + .args(["--select", "F601,UP034", "--no-unsafe-fixes"]) + .build(); + assert_cmd_snapshot!(cmd + .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"), + @r###" + success: false + exit_code: 1 + ----- stdout ----- + -:1:14: F601 Dictionary key literal `'a'` repeated + -:2:7: UP034 [*] Avoid extraneous parentheses + Found 2 errors. + [*] 1 fixable with the --fix option. + + ----- stderr ----- + "###); +} + +#[test] +fn check_no_hint_for_hidden_unsafe_fixes_with_no_safe_fixes_when_disabled() { + let mut cmd = RuffCheck::default() + .args(["--select", "F601", "--no-unsafe-fixes"]) + .build(); + assert_cmd_snapshot!(cmd + .pass_stdin("x = {'a': 1, 'a': 1}\n"), + @r###" + success: false + exit_code: 1 + ----- stdout ----- + -:1:14: F601 Dictionary key literal `'a'` repeated + Found 1 error. + + ----- stderr ----- + "###); +} + #[test] fn check_shows_unsafe_fixes_with_opt_in() { let mut cmd = RuffCheck::default() diff --git a/crates/ruff_linter/src/settings/types.rs b/crates/ruff_linter/src/settings/types.rs index 8c8d84efb7f34..70ff7a9190f3f 100644 --- a/crates/ruff_linter/src/settings/types.rs +++ b/crates/ruff_linter/src/settings/types.rs @@ -119,16 +119,21 @@ impl From for PreviewMode { } } +/// Toggle for unsafe fixes. +/// `Hint` will not apply unsafe fixes but a message will be shown when they are available. +/// `Disabled` will not apply unsafe fixes or show a message. +/// `Enabled` will apply unsafe fixes. #[derive(Debug, Copy, Clone, CacheKey, Default, PartialEq, Eq, is_macro::Is)] pub enum UnsafeFixes { #[default] + Hint, Disabled, Enabled, } impl From for UnsafeFixes { - fn from(version: bool) -> Self { - if version { + fn from(value: bool) -> Self { + if value { UnsafeFixes::Enabled } else { UnsafeFixes::Disabled @@ -140,7 +145,7 @@ impl UnsafeFixes { pub fn required_applicability(&self) -> Applicability { match self { Self::Enabled => Applicability::Unsafe, - Self::Disabled => Applicability::Safe, + Self::Disabled | Self::Hint => Applicability::Safe, } } } diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index be92ddcf1634a..10e5c6717696e 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -93,8 +93,10 @@ pub struct Options { pub fix: Option, /// Enable application of unsafe fixes. + /// If excluded, a hint will be displayed when unsafe fixes are available. + /// If set to false, the hint will be hidden. #[option( - default = "false", + default = r#"null"#, value_type = "bool", example = "unsafe-fixes = true" )] diff --git a/docs/linter.md b/docs/linter.md index 01d258d98ccc4..5594789dad49f 100644 --- a/docs/linter.md +++ b/docs/linter.md @@ -203,6 +203,9 @@ ruff check . --unsafe-fixes ruff check . --fix --unsafe-fixes ``` +By default, Ruff will display a hint when unsafe fixes are available but not enabled. The suggestion can be silenced +by setting the [`unsafe-fixes`](settings.md#unsafe-fixes) setting to `false` or using the `--no-unsafe-fixes` flag. + The safety of fixes can be adjusted per rule using the [`extend-safe-fixes`](settings.md#extend-safe-fixes) and [`extend-unsafe-fixes`](settings.md#extend-unsafe-fixes) settings. For example, the following configuration would promote unsafe fixes for `F601` to safe fixes and demote safe fixes for `UP034` to unsafe fixes: diff --git a/ruff.schema.json b/ruff.schema.json index b7ddd6e209602..cbff63adcd807 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -690,7 +690,7 @@ } }, "unsafe-fixes": { - "description": "Enable application of unsafe fixes.", + "description": "Enable application of unsafe fixes. If excluded, a hint will be displayed when unsafe fixes are available. If set to false, the hint will be hidden.", "type": [ "boolean", "null" From cb8eea64a89940fb9b7dc3620c1346d1e4da805b Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Mon, 11 Dec 2023 21:08:17 -0800 Subject: [PATCH 168/197] [`pylint`] Add fix for `subprocess-run-without-check` (`PLW1510`) (#6708) --- .../pylint/subprocess_run_without_check.py | 5 ++ .../rules/subprocess_run_without_check.rs | 37 ++++++++-- ...W1510_subprocess_run_without_check.py.snap | 73 ++++++++++++++++++- 3 files changed, 106 insertions(+), 9 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/subprocess_run_without_check.py b/crates/ruff_linter/resources/test/fixtures/pylint/subprocess_run_without_check.py index b329ba45109ab..af5dbbc4d0feb 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/subprocess_run_without_check.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/subprocess_run_without_check.py @@ -3,6 +3,11 @@ # Errors. subprocess.run("ls") subprocess.run("ls", shell=True) +subprocess.run( + ["ls"], + shell=False, +) +subprocess.run(["ls"], **kwargs) # Non-errors. subprocess.run("ls", check=True) diff --git a/crates/ruff_linter/src/rules/pylint/rules/subprocess_run_without_check.rs b/crates/ruff_linter/src/rules/pylint/rules/subprocess_run_without_check.rs index 4758de8d017b9..67b494d6bb700 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/subprocess_run_without_check.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/subprocess_run_without_check.rs @@ -1,9 +1,10 @@ -use ruff_diagnostics::{Diagnostic, Violation}; +use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast as ast; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; +use crate::fix::edits::add_argument; /// ## What it does /// Checks for uses of `subprocess.run` without an explicit `check` argument. @@ -36,16 +37,25 @@ use crate::checkers::ast::Checker; /// subprocess.run(["ls", "nonexistent"], check=False) # Explicitly no check. /// ``` /// +/// ## Fix safety +/// This rule's fix is marked as unsafe for function calls that contain +/// `**kwargs`, as adding a `check` keyword argument to such a call may lead +/// to a duplicate keyword argument error. +/// /// ## References /// - [Python documentation: `subprocess.run`](https://docs.python.org/3/library/subprocess.html#subprocess.run) #[violation] pub struct SubprocessRunWithoutCheck; -impl Violation for SubprocessRunWithoutCheck { +impl AlwaysFixableViolation for SubprocessRunWithoutCheck { #[derive_message_formats] fn message(&self) -> String { format!("`subprocess.run` without explicit `check` argument") } + + fn fix_title(&self) -> String { + "Add explicit `check=False`".to_string() + } } /// PLW1510 @@ -56,10 +66,27 @@ pub(crate) fn subprocess_run_without_check(checker: &mut Checker, call: &ast::Ex .is_some_and(|call_path| matches!(call_path.as_slice(), ["subprocess", "run"])) { if call.arguments.find_keyword("check").is_none() { - checker.diagnostics.push(Diagnostic::new( - SubprocessRunWithoutCheck, - call.func.range(), + let mut diagnostic = Diagnostic::new(SubprocessRunWithoutCheck, call.func.range()); + diagnostic.set_fix(Fix::applicable_edit( + add_argument( + "check=False", + &call.arguments, + checker.indexer().comment_ranges(), + checker.locator().contents(), + ), + // If the function call contains `**kwargs`, mark the fix as unsafe. + if call + .arguments + .keywords + .iter() + .any(|keyword| keyword.arg.is_none()) + { + Applicability::Unsafe + } else { + Applicability::Safe + }, )); + checker.diagnostics.push(diagnostic); } } } diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW1510_subprocess_run_without_check.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW1510_subprocess_run_without_check.py.snap index b0306f17a2d42..7419c16569584 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW1510_subprocess_run_without_check.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW1510_subprocess_run_without_check.py.snap @@ -1,22 +1,87 @@ --- source: crates/ruff_linter/src/rules/pylint/mod.rs --- -subprocess_run_without_check.py:4:1: PLW1510 `subprocess.run` without explicit `check` argument +subprocess_run_without_check.py:4:1: PLW1510 [*] `subprocess.run` without explicit `check` argument | 3 | # Errors. 4 | subprocess.run("ls") | ^^^^^^^^^^^^^^ PLW1510 5 | subprocess.run("ls", shell=True) +6 | subprocess.run( | + = help: Add explicit `check=False` -subprocess_run_without_check.py:5:1: PLW1510 `subprocess.run` without explicit `check` argument +ℹ Safe fix +1 1 | import subprocess +2 2 | +3 3 | # Errors. +4 |-subprocess.run("ls") + 4 |+subprocess.run("ls", check=False) +5 5 | subprocess.run("ls", shell=True) +6 6 | subprocess.run( +7 7 | ["ls"], + +subprocess_run_without_check.py:5:1: PLW1510 [*] `subprocess.run` without explicit `check` argument | 3 | # Errors. 4 | subprocess.run("ls") 5 | subprocess.run("ls", shell=True) | ^^^^^^^^^^^^^^ PLW1510 -6 | -7 | # Non-errors. +6 | subprocess.run( +7 | ["ls"], + | + = help: Add explicit `check=False` + +ℹ Safe fix +2 2 | +3 3 | # Errors. +4 4 | subprocess.run("ls") +5 |-subprocess.run("ls", shell=True) + 5 |+subprocess.run("ls", shell=True, check=False) +6 6 | subprocess.run( +7 7 | ["ls"], +8 8 | shell=False, + +subprocess_run_without_check.py:6:1: PLW1510 [*] `subprocess.run` without explicit `check` argument | +4 | subprocess.run("ls") +5 | subprocess.run("ls", shell=True) +6 | subprocess.run( + | ^^^^^^^^^^^^^^ PLW1510 +7 | ["ls"], +8 | shell=False, + | + = help: Add explicit `check=False` + +ℹ Safe fix +5 5 | subprocess.run("ls", shell=True) +6 6 | subprocess.run( +7 7 | ["ls"], +8 |- shell=False, + 8 |+ shell=False, check=False, +9 9 | ) +10 10 | subprocess.run(["ls"], **kwargs) +11 11 | + +subprocess_run_without_check.py:10:1: PLW1510 [*] `subprocess.run` without explicit `check` argument + | + 8 | shell=False, + 9 | ) +10 | subprocess.run(["ls"], **kwargs) + | ^^^^^^^^^^^^^^ PLW1510 +11 | +12 | # Non-errors. + | + = help: Add explicit `check=False` + +ℹ Unsafe fix +7 7 | ["ls"], +8 8 | shell=False, +9 9 | ) +10 |-subprocess.run(["ls"], **kwargs) + 10 |+subprocess.run(["ls"], **kwargs, check=False) +11 11 | +12 12 | # Non-errors. +13 13 | subprocess.run("ls", check=True) From 5559827a78d3aa9fcaf0179a4308f3261895f953 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Tue, 12 Dec 2023 15:32:47 +0900 Subject: [PATCH 169/197] Use the latest poetry ref in the ecosystem formatter check script (#9104) --- scripts/formatter_ecosystem_checks.sh | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/scripts/formatter_ecosystem_checks.sh b/scripts/formatter_ecosystem_checks.sh index 7acf0974a1cec..349e82077c2f5 100755 --- a/scripts/formatter_ecosystem_checks.sh +++ b/scripts/formatter_ecosystem_checks.sh @@ -67,7 +67,7 @@ git -C "$dir/home-assistant" checkout -q 88296c1998fd1943576e0167ab190d25af17525 if [ ! -d "$dir/poetry/.git" ]; then git clone --filter=tree:0 https://github.com/python-poetry/poetry "$dir/poetry" fi -git -C "$dir/poetry" checkout -q f5cb9f0fb19063cf280faf5e39c82d5691da9939 +git -C "$dir/poetry" checkout -q f310a592ad3ab41bb8d635af6bacaf044a1fefef # cpython itself if [ ! -d "$dir/cpython/.git" ]; then @@ -75,12 +75,6 @@ if [ ! -d "$dir/cpython/.git" ]; then fi git -C "$dir/cpython" checkout -q b75186f69edcf54615910a5cd707996144163ef7 -# poetry itself -if [ ! -d "$dir/poetry/.git" ]; then - git clone --filter=tree:0 https://github.com/python-poetry/poetry "$dir/poetry" -fi -git -C "$dir/poetry" checkout -q 611033a7335f3c8e2b74dd58688fb9021cf84a5b - # Uncomment if you want to update the hashes #for i in "$dir"/*/; do git -C "$i" switch main && git -C "$i" pull; done #for i in "$dir"/*/; do echo "# $(basename "$i") $(git -C "$i" rev-parse HEAD)"; done From b972455ac77e34e8da72cc7f8aa8857baa5721cb Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Tue, 12 Dec 2023 09:58:07 -0500 Subject: [PATCH 170/197] ruff_python_formatter: implement "dynamic" line width mode for docstring code formatting (#9098) ## Summary This PR changes the internal `docstring-code-line-width` setting to additionally accept a string value `dynamic`. When `dynamic` is set, the line width is dynamically adjusted when reformatting code snippets in docstrings based on the indent level of the docstring. The result is that the reformatted lines from the code snippet should not exceed the "global" line width configuration for the surrounding source. This PR does not change the default behavior, although I suspect the default should probably be `dynamic`. ## Test Plan I added a new configuration to the existing docstring code tests and also added a new set of tests dedicated to the new `dynamic` mode. --- .../ruff/docstring_code_examples.options.json | 6 + ...e_examples_dynamic_line_width.options.json | 26 + ...string_code_examples_dynamic_line_width.py | 172 ++ crates/ruff_python_formatter/src/context.rs | 124 +- .../src/expression/string/docstring.rs | 17 +- crates/ruff_python_formatter/src/lib.rs | 3 +- crates/ruff_python_formatter/src/options.rs | 54 +- .../src/statement/suite.rs | 5 +- .../ruff_python_formatter/tests/fixtures.rs | 2 +- .../format@docstring_code_examples.py.snap | 1367 ++++++++++++++ ...g_code_examples_dynamic_line_width.py.snap | 1630 +++++++++++++++++ 11 files changed, 3394 insertions(+), 12 deletions(-) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_dynamic_line_width.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_dynamic_line_width.py create mode 100644 crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_dynamic_line_width.py.snap diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.options.json b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.options.json index 75eee27329dfe..9400ae4bea230 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.options.json @@ -44,5 +44,11 @@ "docstring_code_line_width": 60, "indent_style": "space", "indent_width": 4 + }, + { + "docstring_code": "enabled", + "docstring_code_line_width": "dynamic", + "indent_style": "space", + "indent_width": 4 } ] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_dynamic_line_width.options.json b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_dynamic_line_width.options.json new file mode 100644 index 0000000000000..3367effa0051c --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_dynamic_line_width.options.json @@ -0,0 +1,26 @@ +[ + { + "docstring_code": "enabled", + "docstring_code_line_width": "dynamic", + "indent_style": "space", + "indent_width": 4 + }, + { + "docstring_code": "enabled", + "docstring_code_line_width": "dynamic", + "indent_style": "space", + "indent_width": 2 + }, + { + "docstring_code": "enabled", + "docstring_code_line_width": "dynamic", + "indent_style": "tab", + "indent_width": 4 + }, + { + "docstring_code": "enabled", + "docstring_code_line_width": "dynamic", + "indent_style": "tab", + "indent_width": 8 + } +] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_dynamic_line_width.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_dynamic_line_width.py new file mode 100644 index 0000000000000..04027909eda6e --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_dynamic_line_width.py @@ -0,0 +1,172 @@ +def simple(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz(Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5): + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + ``` + + Done. + """ + pass + + +# Like simple, but we double everything up to ensure the indent level is +# tracked correctly. +def repeated(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz(Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5): + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + + + class Abcdefghijklmopqrstuvwxyz(Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5): + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + ``` + + Done. + """ + pass + + +# Like simple, but we make one line exactly one character longer than the limit +# (for 4-space indents) and make sure it gets wrapped. +def barely_exceeds_limit(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz(Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5): + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is 89 columns, which is one + # more than the limit. Therefore, it should get wrapped for + # indent_width >= 4. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a5678) + return 5 + self.x = doit( 5 ) + ``` + + Done. + """ + pass + + +# This tests that if the code block is unindented, that it gets indented and +# the dynamic line width setting is applied correctly. +def unindented(): + """ + First line. + +```py +class Abcdefghijklmopqrstuvwxyz(Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5): + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) +``` + + Done. + """ + pass + + +# Like unindented, but contains a `print` line where it just barely exceeds the +# globally configured line width *after* its indentation has been corrected. +def unindented_barely_exceeds_limit(): + """ + First line. + +```py +class Abcdefghijklmopqrstuvwxyz(Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5): + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is 89 columns, which is one + # more than the limit. Therefore, it should get wrapped for + # indent_width >= 4. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a5678) + return 5 + self.x = doit( 5 ) +``` + + Done. + """ + pass diff --git a/crates/ruff_python_formatter/src/context.rs b/crates/ruff_python_formatter/src/context.rs index ac5dea3710017..8407e7cdc4323 100644 --- a/crates/ruff_python_formatter/src/context.rs +++ b/crates/ruff_python_formatter/src/context.rs @@ -1,7 +1,7 @@ use crate::comments::Comments; use crate::expression::string::QuoteChar; use crate::PyFormatOptions; -use ruff_formatter::{Buffer, FormatContext, GroupId, SourceCode}; +use ruff_formatter::{Buffer, FormatContext, GroupId, IndentWidth, SourceCode}; use ruff_source_file::Locator; use std::fmt::{Debug, Formatter}; use std::ops::{Deref, DerefMut}; @@ -12,6 +12,7 @@ pub struct PyFormatContext<'a> { contents: &'a str, comments: Comments<'a>, node_level: NodeLevel, + indent_level: IndentLevel, /// Set to a non-None value when the formatter is running on a code /// snippet within a docstring. The value should be the quote character of the /// docstring containing the code snippet. @@ -30,6 +31,7 @@ impl<'a> PyFormatContext<'a> { contents, comments, node_level: NodeLevel::TopLevel(TopLevelStatementPosition::Other), + indent_level: IndentLevel::new(0), docstring: None, } } @@ -51,6 +53,14 @@ impl<'a> PyFormatContext<'a> { self.node_level } + pub(crate) fn set_indent_level(&mut self, level: IndentLevel) { + self.indent_level = level; + } + + pub(crate) fn indent_level(&self) -> IndentLevel { + self.indent_level + } + pub(crate) fn comments(&self) -> &Comments<'a> { &self.comments } @@ -210,3 +220,115 @@ where .set_node_level(self.saved_level); } } + +/// The current indent level of the formatter. +/// +/// One can determine the the width of the indent itself (in number of ASCII +/// space characters) by multiplying the indent level by the configured indent +/// width. +/// +/// This is specifically used inside the docstring code formatter for +/// implementing its "dynamic" line width mode. Namely, in the nested call to +/// the formatter, when "dynamic" mode is enabled, the line width is set to +/// `min(1, line_width - indent_level * indent_width)`, where `line_width` in +/// this context is the global line width setting. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub(crate) struct IndentLevel { + /// The numeric level. It is incremented for every whole indent in Python + /// source code. + /// + /// Note that the first indentation level is actually 1, since this starts + /// at 0 and is incremented when the first top-level statement is seen. So + /// even though the first top-level statement in Python source will have no + /// indentation, its indentation level is 1. + level: u16, +} + +impl IndentLevel { + /// Returns a new indent level for the given value. + pub(crate) fn new(level: u16) -> IndentLevel { + IndentLevel { level } + } + + /// Returns the next indent level. + pub(crate) fn increment(self) -> IndentLevel { + IndentLevel { + level: self.level.saturating_add(1), + } + } + + /// Convert this indent level into a specific number of ASCII whitespace + /// characters based on the given indent width. + pub(crate) fn to_ascii_spaces(self, width: IndentWidth) -> u16 { + let width = u16::try_from(width.value()).unwrap_or(u16::MAX); + // Why the subtraction? IndentLevel starts at 0 and asks for the "next" + // indent level before seeing the first top-level statement. So it's + // always 1 more than what we expect it to be. + let level = self.level.saturating_sub(1); + width.saturating_mul(level) + } +} + +/// Change the [`IndentLevel`] of the formatter for the lifetime of this +/// struct. +pub(crate) struct WithIndentLevel<'a, B, D> +where + D: DerefMut, + B: Buffer>, +{ + buffer: D, + saved_level: IndentLevel, +} + +impl<'a, B, D> WithIndentLevel<'a, B, D> +where + D: DerefMut, + B: Buffer>, +{ + pub(crate) fn new(level: IndentLevel, mut buffer: D) -> Self { + let context = buffer.state_mut().context_mut(); + let saved_level = context.indent_level(); + + context.set_indent_level(level); + + Self { + buffer, + saved_level, + } + } +} + +impl<'a, B, D> Deref for WithIndentLevel<'a, B, D> +where + D: DerefMut, + B: Buffer>, +{ + type Target = B; + + fn deref(&self) -> &Self::Target { + &self.buffer + } +} + +impl<'a, B, D> DerefMut for WithIndentLevel<'a, B, D> +where + D: DerefMut, + B: Buffer>, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.buffer + } +} + +impl<'a, B, D> Drop for WithIndentLevel<'a, B, D> +where + D: DerefMut, + B: Buffer>, +{ + fn drop(&mut self) { + self.buffer + .state_mut() + .context_mut() + .set_indent_level(self.saved_level); + } +} diff --git a/crates/ruff_python_formatter/src/expression/string/docstring.rs b/crates/ruff_python_formatter/src/expression/string/docstring.rs index 0fb03ce07d882..e750a52641b03 100644 --- a/crates/ruff_python_formatter/src/expression/string/docstring.rs +++ b/crates/ruff_python_formatter/src/expression/string/docstring.rs @@ -7,13 +7,13 @@ use std::{borrow::Cow, collections::VecDeque}; use {once_cell::sync::Lazy, regex::Regex}; use { - ruff_formatter::{write, IndentStyle, Printed}, + ruff_formatter::{write, FormatOptions, IndentStyle, LineWidth, Printed}, ruff_python_trivia::{is_python_whitespace, PythonWhitespace}, ruff_source_file::Locator, ruff_text_size::{Ranged, TextLen, TextRange, TextSize}, }; -use crate::{prelude::*, FormatModuleError}; +use crate::{prelude::*, DocstringCodeLineWidth, FormatModuleError}; use super::{NormalizedString, QuoteChar}; @@ -460,11 +460,22 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { .map(|line| line.code) .collect::>() .join("\n"); + let line_width = match self.f.options().docstring_code_line_width() { + DocstringCodeLineWidth::Fixed(width) => width, + DocstringCodeLineWidth::Dynamic => { + let global_line_width = self.f.options().line_width().value(); + let indent_width = self.f.options().indent_width(); + let indent_level = self.f.context().indent_level(); + let current_indent = indent_level.to_ascii_spaces(indent_width); + let width = std::cmp::max(1, global_line_width.saturating_sub(current_indent)); + LineWidth::try_from(width).expect("width is capped at a minimum of 1") + } + }; let options = self .f .options() .clone() - .with_line_width(self.f.options().docstring_code_line_width()) + .with_line_width(line_width) // It's perhaps a little odd to be hard-coding the indent // style here, but I believe it is necessary as a result // of the whitespace normalization otherwise done in diff --git a/crates/ruff_python_formatter/src/lib.rs b/crates/ruff_python_formatter/src/lib.rs index ce3988dd54693..beaa4070c0c37 100644 --- a/crates/ruff_python_formatter/src/lib.rs +++ b/crates/ruff_python_formatter/src/lib.rs @@ -16,7 +16,8 @@ use crate::comments::{ }; pub use crate::context::PyFormatContext; pub use crate::options::{ - DocstringCode, MagicTrailingComma, PreviewMode, PyFormatOptions, QuoteStyle, + DocstringCode, DocstringCodeLineWidth, MagicTrailingComma, PreviewMode, PyFormatOptions, + QuoteStyle, }; pub use crate::shared_traits::{AsFormat, FormattedIter, FormattedIterExt, IntoFormat}; use crate::verbatim::suppressed_node; diff --git a/crates/ruff_python_formatter/src/options.rs b/crates/ruff_python_formatter/src/options.rs index 003cfea4bf041..8f3bc431ec815 100644 --- a/crates/ruff_python_formatter/src/options.rs +++ b/crates/ruff_python_formatter/src/options.rs @@ -52,8 +52,7 @@ pub struct PyFormatOptions { /// The preferred line width at which the formatter should wrap lines in /// docstring code examples. This only has an impact when `docstring_code` /// is enabled. - #[cfg_attr(feature = "serde", serde(default = "default_line_width"))] - docstring_code_line_width: LineWidth, + docstring_code_line_width: DocstringCodeLineWidth, /// Whether preview style formatting is enabled or not preview: PreviewMode, @@ -83,7 +82,7 @@ impl Default for PyFormatOptions { magic_trailing_comma: MagicTrailingComma::default(), source_map_generation: SourceMapGeneration::default(), docstring_code: DocstringCode::default(), - docstring_code_line_width: default_line_width(), + docstring_code_line_width: DocstringCodeLineWidth::default(), preview: PreviewMode::default(), } } @@ -126,7 +125,7 @@ impl PyFormatOptions { self.docstring_code } - pub fn docstring_code_line_width(&self) -> LineWidth { + pub fn docstring_code_line_width(&self) -> DocstringCodeLineWidth { self.docstring_code_line_width } @@ -302,3 +301,50 @@ impl DocstringCode { matches!(self, DocstringCode::Enabled) } } + +#[derive(Copy, Clone, Eq, PartialEq, CacheKey)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))] +#[cfg_attr(feature = "serde", serde(untagged))] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +pub enum DocstringCodeLineWidth { + Fixed(LineWidth), + #[cfg_attr( + feature = "serde", + serde(deserialize_with = "deserialize_docstring_code_line_width_dynamic") + )] + Dynamic, +} + +impl Default for DocstringCodeLineWidth { + fn default() -> DocstringCodeLineWidth { + DocstringCodeLineWidth::Fixed(default_line_width()) + } +} + +impl std::fmt::Debug for DocstringCodeLineWidth { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match *self { + DocstringCodeLineWidth::Fixed(v) => v.value().fmt(f), + DocstringCodeLineWidth::Dynamic => "dynamic".fmt(f), + } + } +} + +/// Responsible for deserializing the `DocstringCodeLineWidth::Dynamic` +/// variant. +fn deserialize_docstring_code_line_width_dynamic<'de, D>(d: D) -> Result<(), D::Error> +where + D: serde::Deserializer<'de>, +{ + use serde::{de::Error, Deserialize}; + + let value = String::deserialize(d)?; + match &*value { + "dynamic" => Ok(()), + s => Err(D::Error::invalid_value( + serde::de::Unexpected::Str(s), + &"dynamic", + )), + } +} diff --git a/crates/ruff_python_formatter/src/statement/suite.rs b/crates/ruff_python_formatter/src/statement/suite.rs index b60474dbd0043..1b33dbd41aa16 100644 --- a/crates/ruff_python_formatter/src/statement/suite.rs +++ b/crates/ruff_python_formatter/src/statement/suite.rs @@ -8,7 +8,7 @@ use ruff_text_size::{Ranged, TextRange}; use crate::comments::{ leading_comments, trailing_comments, Comments, LeadingDanglingTrailingComments, }; -use crate::context::{NodeLevel, TopLevelStatementPosition, WithNodeLevel}; +use crate::context::{NodeLevel, TopLevelStatementPosition, WithIndentLevel, WithNodeLevel}; use crate::expression::string::StringLayout; use crate::prelude::*; use crate::statement::stmt_expr::FormatStmtExpr; @@ -71,7 +71,8 @@ impl FormatRule> for FormatSuite { let source = f.context().source(); let source_type = f.options().source_type(); - let f = &mut WithNodeLevel::new(node_level, f); + let f = WithNodeLevel::new(node_level, f); + let f = &mut WithIndentLevel::new(f.context().indent_level().increment(), f); // Format the first statement in the body, which often has special formatting rules. let first = match self.kind { diff --git a/crates/ruff_python_formatter/tests/fixtures.rs b/crates/ruff_python_formatter/tests/fixtures.rs index a425a1e597bd1..3845385d7335f 100644 --- a/crates/ruff_python_formatter/tests/fixtures.rs +++ b/crates/ruff_python_formatter/tests/fixtures.rs @@ -363,7 +363,7 @@ preview = {preview:?}"#, line_ending = self.0.line_ending(), magic_trailing_comma = self.0.magic_trailing_comma(), docstring_code = self.0.docstring_code(), - docstring_code_line_width = self.0.docstring_code_line_width().value(), + docstring_code_line_width = self.0.docstring_code_line_width(), preview = self.0.preview() ) } diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap index e0c672c090b0c..b93825ea198e6 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap @@ -13673,4 +13673,1371 @@ def markdown_skipped_rst_directive(): ``` +### Output 10 +``` +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +docstring-code-line-width = "dynamic" +preview = Disabled +``` + +```python +############################################################################### +# DOCTEST CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Python's "doctest" format. +# +# See: https://docs.python.org/3/library/doctest.html +############################################################################### + +# The simplest doctest to ensure basic formatting works. +def doctest_simple(): + """ + Do cool stuff. + + >>> cool_stuff(1) + 2 + """ + pass + + +# Another simple test, but one where the Python code +# extends over multiple lines. +def doctest_simple_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(f"hi {x}") + hi 2 + """ + pass + + +# Test that we support multiple directly adjacent +# doctests. +def doctest_adjacent(): + """ + Do cool stuff. + + >>> cool_stuff(x) + >>> cool_stuff(y) + 2 + """ + pass + + +# Test that a doctest on the last non-whitespace line of a docstring +# reformats correctly. +def doctest_last_line(): + """ + Do cool stuff. + + >>> cool_stuff(x) + """ + pass + + +# Test that a doctest that continues to the last non-whitespace line of +# a docstring reformats correctly. +def doctest_last_line_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(f"hi {x}") + """ + pass + + +# Test that a doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line(): + """ + Do cool stuff. + + >>> cool_stuff(x)""" + pass + + +# Test that a continued doctest on the real last line of a docstring reformats +# correctly. +def doctest_really_last_line_continued(): + """ + Do cool stuff. + + >>> cool_stuff(x) + ... more(y)""" + pass + + +# Test that a doctest is correctly identified and formatted with a blank +# continuation line. +def doctest_blank_continued(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... + ... print(x) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped. +# It is treated as part of the Python snippet which will trim the +# trailing whitespace. +def doctest_blank_end(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print(x) + """ + pass + + +# Tests that a blank PS2 line at the end of a doctest can get dropped +# even when there is text following it. +def doctest_blank_end_then_some_text(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print(x) + + And say something else. + """ + pass + + +# Test that a doctest containing a triple quoted string gets formatted +# correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = '''tricksy''' + """ + pass + + +# Test that a doctest containing a triple quoted f-string gets +# formatted correctly and doesn't result in invalid syntax. +def doctest_with_triple_single(): + """ + Do cool stuff. + + >>> x = f'''tricksy''' + """ + pass + + +# Another nested multi-line string case, but with triple escaped double +# quotes inside a triple single quoted string. +def doctest_with_triple_escaped_double(): + """ + Do cool stuff. + + >>> x = '''\"\"\"''' + """ + pass + + +# Tests that inverting the triple quoting works as expected. +def doctest_with_triple_inverted(): + ''' + Do cool stuff. + + >>> x = """tricksy""" + ''' + pass + + +# Tests that inverting the triple quoting with an f-string works as +# expected. +def doctest_with_triple_inverted_fstring(): + ''' + Do cool stuff. + + >>> x = f"""tricksy""" + ''' + pass + + +# Tests nested doctests are ignored. That is, we don't format doctests +# recursively. We only recognize "top level" doctests. +# +# This restriction primarily exists to avoid needing to deal with +# nesting quotes. It also seems like a generally sensible restriction, +# although it could be lifted if necessary I believe. +def doctest_nested_doctest_not_formatted(): + ''' + Do cool stuff. + + >>> def nested(x): + ... """ + ... Do nested cool stuff. + ... >>> func_call( 5 ) + ... """ + ... pass + ''' + pass + + +# Tests that the starting column does not matter. +def doctest_varying_start_column(): + """ + Do cool stuff. + + >>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1 + """ + pass + + +# Tests that long lines get wrapped... appropriately. +# +# The docstring code formatter uses the same line width settings as for +# formatting other code. This means that a line in the docstring can +# actually extend past the configured line limit. +# +# It's not quite clear whether this is desirable or not. We could in +# theory compute the intendation length of a code snippet and then +# adjust the line-width setting on a recursive call to the formatter. +# But there are assuredly pathological cases to consider. Another path +# would be to expose another formatter option for controlling the +# line-width of code snippets independently. +def doctest_long_lines(): + """ + Do cool stuff. + + This won't get wrapped even though it exceeds our configured + line width because it doesn't exceed the line width within this + docstring. e.g, the `f` in `foo` is treated as the first column. + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey + ... ) + + But this one is long enough to get wrapped. + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard + ... ) + """ + # This demostrates a normal line that will get wrapped but won't + # get wrapped in the docstring above because of how the line-width + # setting gets reset at the first column in each code snippet. + foo, bar, quux = this_is_a_long_line( + lion, giraffe, hippo, zeba, lemur, penguin, monkey + ) + + +# Checks that a simple but invalid doctest gets skipped. +def doctest_skipped_simple(): + """ + Do cool stuff. + + >>> cool-stuff( x ): + 2 + """ + pass + + +# Checks that a simple doctest that is continued over multiple lines, +# but is invalid, gets skipped. +def doctest_skipped_simple_continued(): + """ + Do cool stuff. + + >>> def cool-stuff( x ): + ... print( f"hi {x}" ); + 2 + """ + pass + + +# Checks that a doctest with improper indentation gets skipped. +def doctest_skipped_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff( x ): + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with some proper indentation and some improper +# indentation is "partially" formatted. That is, the part that appears +# before the inconsistent indentation is formatted. This requires that +# the part before it is valid Python. +def doctest_skipped_partial_inconsistent_indent(): + """ + Do cool stuff. + + >>> def cool_stuff(x): + ... print(x) + ... print( f"hi {x}" ); + hi 2 + """ + pass + + +# Checks that a doctest with improper triple single quoted string gets +# skipped. That is, the code snippet is itself invalid Python, so it is +# left as is. +def doctest_skipped_triple_incorrect(): + """ + Do cool stuff. + + >>> foo( x ) + ... '''tri'''cksy''' + """ + pass + + +# Tests that a doctest on a single line is skipped. +def doctest_skipped_one_line(): + ">>> foo( x )" + pass + + +# f-strings are not considered docstrings[1], so any doctests +# inside of them should not be formatted. +# +# [1]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals +def doctest_skipped_fstring(): + f""" + Do cool stuff. + + >>> cool_stuff( 1 ) + 2 + """ + pass + + +# Test that a doctest containing a triple quoted string at least +# does not result in invalid Python code. Ideally this would format +# correctly, but at time of writing it does not. +def doctest_invalid_skipped_with_triple_double_in_single_quote_string(): + """ + Do cool stuff. + + >>> x = '\"\"\"' + """ + pass + + +############################################################################### +# reStructuredText CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# reStructuredText formatted code blocks. +# +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks +# See: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-30 +# See: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#toc-entry-38 +############################################################################### + + +def rst_literal_simple(): + """ + Do cool stuff:: + + cool_stuff(1) + + Done. + """ + pass + + +def rst_literal_simple_continued(): + """ + Do cool stuff:: + + def cool_stuff(x): + print(f"hi {x}") + + Done. + """ + pass + + +# Tests that we can end the literal block on the second +# to last line of the docstring. +def rst_literal_second_to_last(): + """ + Do cool stuff:: + + cool_stuff(1) + """ + pass + + +# Tests that we can end the literal block on the actual +# last line of the docstring. +def rst_literal_actually_last(): + """ + Do cool stuff:: + + cool_stuff(1)""" + pass + + +def rst_literal_with_blank_lines(): + """ + Do cool stuff:: + + def cool_stuff(x): + print(f"hi {x}") + + + def other_stuff(y): + print(y) + + Done. + """ + pass + + +# Extra blanks should be preserved. +def rst_literal_extra_blanks(): + """ + Do cool stuff:: + + + + cool_stuff(1) + + + + Done. + """ + pass + + +# If a literal block is never properly ended (via a non-empty unindented line), +# then the end of the block should be the last non-empty line. And subsequent +# empty lines should be preserved as-is. +def rst_literal_extra_blanks_at_end(): + """ + Do cool stuff:: + + + cool_stuff(1) + + + + """ + pass + + +# A literal block can contain many empty lines and it should not end the block +# if it continues. +def rst_literal_extra_blanks_in_snippet(): + """ + Do cool stuff:: + + cool_stuff(1) + + + cool_stuff(2) + + Done. + """ + pass + + +# This tests that a unindented line appearing after an indented line (but where +# the indent is still beyond the minimum) gets formatted properly. +def rst_literal_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( + ''' + hiya''' + ) + + Done. + """ + pass + + +# This checks that if the first line in a code snippet has been indented with +# tabs, then so long as its "indentation length" is considered bigger than the +# line with `::`, it is reformatted as code. +# +# (If your tabwidth is set to 4, then it looks like the code snippet +# isn't indented at all, which is perhaps counter-intuitive. Indeed, reST +# itself also seems to recognize this as a code block, although it appears +# under-specified.) +def rst_literal_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff:: + + cool_stuff(1) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff(1) + cool_stuff(2) + + Done. + """ + pass + + +# Another test with tabs, except in this case, if your tabwidth is less than +# 8, than the code snippet actually looks like its indent is *less* than the +# opening line with a `::`. One might presume this means that the code snippet +# is not treated as a literal block and thus not reformatted, but since we +# assume all tabs have tabwidth=8 when computing indentation length, the code +# snippet is actually seen as being more indented than the opening `::` line. +# As with the above example, reST seems to behave the same way here. +def rst_literal_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff:: + + cool_stuff(1) + + Done. + """ + pass + + +# Like the test above, but with multiple lines. +def rst_literal_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff:: + + cool_stuff(1) + cool_stuff(2) + + Done. + """ + pass + + +# Tests that if two lines in a literal block are indented to the same level +# but by different means (tabs versus spaces), then we correctly recognize the +# block and format it. +def rst_literal_first_line_tab_second_line_spaces(): + """ + Do cool stuff:: + + cool_stuff(1) + cool_stuff(2) + + Done. + """ + pass + + +# Tests that when two lines in a code snippet have weird and inconsistent +# indentation, the code still gets formatted so long as the indent is greater +# than the indent of the `::` line. +# +# In this case, the minimum indent is 5 spaces (from the second line) where as +# the first line has an indent of 8 spaces via a tab (by assuming tabwidth=8). +# The minimum indent is stripped from each code line. Since tabs aren't +# divisible, the entire tab is stripped, which means the first and second lines +# wind up with the same level of indentation. +# +# An alternative behavior here would be that the tab is replaced with 3 spaces +# instead of being stripped entirely. The code snippet itself would then have +# inconsistent indentation to the point of being invalid Python, and thus code +# formatting would be skipped. +# +# I decided on the former behavior because it seems a bit easier to implement, +# but we might want to switch to the alternative if cases like this show up in +# the real world. ---AG +def rst_literal_odd_indentation(): + """ + Do cool stuff:: + + cool_stuff(1) + cool_stuff(2) + + Done. + """ + pass + + +# Tests that having a line with a lone `::` works as an introduction of a +# literal block. +def rst_literal_lone_colon(): + """ + Do cool stuff. + + :: + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_simple(): + """ + .. code-block:: python + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_case_insensitive(): + """ + .. cOdE-bLoCk:: python + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_sourcecode(): + """ + .. sourcecode:: python + + cool_stuff(1) + + Done. + """ + pass + + +def rst_directive_options(): + """ + .. code-block:: python + :linenos: + :emphasize-lines: 2,3 + :name: blah blah + + cool_stuff(1) + cool_stuff(2) + cool_stuff(3) + cool_stuff(4) + + Done. + """ + pass + + +# In this case, since `pycon` isn't recognized as a Python code snippet, the +# docstring reformatter ignores it. But it then picks up the doctest and +# reformats it. +def rst_directive_doctest(): + """ + .. code-block:: pycon + + >>> cool_stuff(1) + + Done. + """ + pass + + +# This checks that if the first non-empty line after the start of a literal +# block is not indented more than the line containing the `::`, then it is not +# treated as a code snippet. +def rst_literal_skipped_first_line_not_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the test above, but inserts an indented line after the un-indented one. +# This should not cause the literal block to be resumed. +def rst_literal_skipped_first_line_not_indented_then_indented(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# This also checks that a code snippet is not reformatted when the indentation +# of the first line is not more than the line with `::`, but this uses tabs to +# make it a little more confounding. It relies on the fact that indentation +# length is computed by assuming a tabwidth equal to 8. reST also rejects this +# and doesn't treat it as a literal block. +def rst_literal_skipped_first_line_not_indented_tab(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# Like the previous test, but adds a second line. +def rst_literal_skipped_first_line_not_indented_tab_multiple(): + """ + Do cool stuff:: + + cool_stuff( 1 ) + cool_stuff( 2 ) + + Done. + """ + pass + + +# Tests that a code block with a second line that is not properly indented gets +# skipped. A valid code block needs to have an empty line separating these. +# +# One trick here is that we need to make sure the Python code in the snippet is +# valid, otherwise it would be skipped because of invalid Python. +def rst_literal_skipped_subsequent_line_not_indented(): + """ + Do cool stuff:: + + if True: + cool_stuff( ''' + hiya''' ) + + Done. + """ + pass + + +# In this test, we write what looks like a code-block, but it should be treated +# as invalid due to the missing `language` argument. +# +# It does still look like it could be a literal block according to the literal +# rules, but we currently consider the `.. ` prefix to indicate that it is not +# a literal block. +def rst_literal_skipped_not_directive(): + """ + .. code-block:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# In this test, we start a line with `.. `, which makes it look like it might +# be a directive. But instead continue it as if it was just some periods from +# the previous line, and then try to end it by starting a literal block. +# +# But because of the `.. ` in the beginning, we wind up not treating this as a +# code snippet. The reST render I was using to test things does actually treat +# this as a code block, so we may be out of conformance here. +def rst_literal_skipped_possible_false_negative(): + """ + This is a test. + .. This is a test:: + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This tests that a doctest inside of a reST literal block doesn't get +# reformatted. It's plausible this isn't the right behavior, but it also seems +# like it might be the right behavior since it is a literal block. (The doctest +# makes the Python code invalid.) +def rst_literal_skipped_doctest(): + """ + Do cool stuff:: + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_literal_skipped_markdown(): + """ + Do cool stuff:: + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def rst_directive_skipped_not_indented(): + """ + .. code-block:: python + + cool_stuff( 1 ) + + Done. + """ + pass + + +def rst_directive_skipped_wrong_language(): + """ + .. code-block:: rust + + cool_stuff( 1 ) + + Done. + """ + pass + + +# This gets skipped for the same reason that the doctest in a literal block +# gets skipped. +def rst_directive_skipped_doctest(): + """ + .. code-block:: python + + >>> cool_stuff( 1 ) + + Done. + """ + pass + + +############################################################################### +# Markdown CODE EXAMPLES +# +# This section shows examples of docstrings that contain code snippets in +# Markdown fenced code blocks. +# +# See: https://spec.commonmark.org/0.30/#fenced-code-blocks +############################################################################### + + +def markdown_simple(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ``` + + Done. + """ + pass + + +def markdown_simple_continued(): + """ + Do cool stuff. + + ```python + def cool_stuff(x): + print(f"hi {x}") + ``` + + Done. + """ + pass + + +# Tests that unlabeled Markdown fenced code blocks are assumed to be Python. +def markdown_unlabeled(): + """ + Do cool stuff. + + ``` + cool_stuff(1) + ``` + + Done. + """ + pass + + +# Tests that fenced code blocks using tildes work. +def markdown_tildes(): + """ + Do cool stuff. + + ~~~py + cool_stuff(1) + ~~~ + + Done. + """ + pass + + +# Tests that a longer closing fence is just fine and dandy. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + `````` + + Done. + """ + pass + + +# Tests that an invalid closing fence is treated as invalid. +# +# We embed it into a docstring so that the surrounding Python +# remains valid. +def markdown_longer_closing_fence(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ''' + ```invalid + ''' + cool_stuff(2) + ``` + + Done. + """ + pass + + +# Tests that one can nest fenced code blocks by using different numbers of +# backticks. +def markdown_nested_fences(): + """ + Do cool stuff. + + `````` + do_something( + ''' + ``` + did i trick you? + ``` + ''' + ) + `````` + + Done. + """ + pass + + +# Tests that an unclosed block gobbles up everything remaining in the +# docstring. When it's only empty lines, those are passed into the formatter +# and thus stripped. +def markdown_unclosed_empty_lines(): + """ + Do cool stuff. + + ```py + cool_stuff(1)""" + pass + + +# Tests that we can end the block on the second to last line of the +# docstring. +def markdown_second_to_last(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ``` + """ + pass + + +# Tests that an unclosed block with one extra line at the end is treated +# correctly. As per the CommonMark spec, an unclosed fenced code block contains +# everything following the opening fences. Since formatting the code snippet +# trims lines, the last empty line is removed here. +def markdown_second_to_last(): + """ + Do cool stuff. + + ```py + cool_stuff(1)""" + pass + + +# Tests that we can end the block on the actual last line of the docstring. +def markdown_actually_last(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ```""" + pass + + +# Tests that an unclosed block that ends on the last line of a docstring +# is handled correctly. +def markdown_unclosed_actually_last(): + """ + Do cool stuff. + + ```py + cool_stuff(1)""" + pass + + +def markdown_with_blank_lines(): + """ + Do cool stuff. + + ```py + def cool_stuff(x): + print(f"hi {x}") + + + def other_stuff(y): + print(y) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_4spaces(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_4spaces_multiple(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + cool_stuff(2) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_8spaces(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ``` + + Done. + """ + pass + + +def markdown_first_line_indent_uses_tabs_8spaces_multiple(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + cool_stuff(2) + ``` + + Done. + """ + pass + + +def markdown_first_line_tab_second_line_spaces(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + cool_stuff(2) + ``` + + Done. + """ + pass + + +def markdown_odd_indentation(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + cool_stuff(2) + ``` + + Done. + """ + pass + + +# Extra blanks should be *not* be preserved (unlike reST) because they are part +# of the code snippet (per CommonMark spec), and thus get trimmed as part of +# code formatting. +def markdown_extra_blanks(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + ``` + + Done. + """ + pass + + +# A block can contain many empty lines within it. +def markdown_extra_blanks_in_snippet(): + """ + Do cool stuff. + + ```py + cool_stuff(1) + + + cool_stuff(2) + ``` + + Done. + """ + pass + + +def markdown_weird_closing(): + """ + Code block with weirdly placed closing fences. + + ```python + cool_stuff(1) + ``` + # The above fences look like it shouldn't close the block, but we + # allow it to. The fences below re-open a block (until the end of + # the docstring), but it's invalid Python and thus doesn't get + # reformatted. + a = 10 + ``` + + Now the code block is closed + """ + pass + + +def markdown_over_indented(): + """ + A docstring + over intended + ```python + print(5) + ``` + """ + pass + + +# This tests that we can have additional text after the language specifier. +def markdown_additional_info_string(): + """ + Do cool stuff. + + ```python tab="plugin.py" + cool_stuff(1) + ``` + + Done. + """ + pass + + +# Tests that an unclosed block gobbles up everything remaining in the +# docstring, even if it isn't valid Python. Since it isn't valid Python, +# reformatting fails and the entire thing is skipped. +def markdown_skipped_unclosed_non_python(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + + I forgot to close the code block, and this is definitely not + Python. So nothing here gets formatted. + """ + pass + + +# This has a Python snippet with a docstring that contains a closing fence. +# This splits the embedded docstring and makes the overall snippet invalid. +def markdown_skipped_accidental_closure(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ''' + ``` + ''' + ``` + + Done. + """ + pass + + +# When a line is unindented all the way out before the standard indent of the +# docstring, the code reformatting ends up interacting poorly with the standard +# docstring whitespace normalization logic. This is probably a bug, and we +# should probably treat the Markdown block as valid, but for now, we detect +# the unindented line and declare the block as invalid and thus do no code +# reformatting. +# +# FIXME: Fixing this (if we think it's a bug) probably requires refactoring the +# docstring whitespace normalization to be aware of code snippets. Or perhaps +# plausibly, to do normalization *after* code snippets have been formatted. +def markdown_skipped_unindented_completely(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# This test is fallout from treating fenced code blocks with unindented lines +# as invalid. We probably should treat this as a valid block. Indeed, if we +# remove the logic that makes the `markdown_skipped_unindented_completely` test +# pass, then this code snippet will get reformatted correctly. +def markdown_skipped_unindented_somewhat(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +# This tests that if a Markdown block contains a line that has less of an +# indent than another line. +# +# There is some judgment involved in what the right behavior is here. We +# could "normalize" the indentation so that the minimum is the indent of the +# opening fence line. If we did that here, then the code snippet would become +# valid and format as Python. But at time of writing, we don't, which leads to +# inconsistent indentation and thus invalid Python. +def markdown_skipped_unindented_with_inconsistent_indentation(): + """ + Do cool stuff. + + ```py + cool_stuff( 1 ) + cool_stuff( 2 ) + ``` + + Done. + """ + pass + + +def markdown_skipped_doctest(): + """ + Do cool stuff. + + ```py + >>> cool_stuff( 1 ) + ``` + + Done. + """ + pass + + +def markdown_skipped_rst_literal(): + """ + Do cool stuff. + + ```py + And do this:: + + cool_stuff( 1 ) + + ``` + + Done. + """ + pass + + +def markdown_skipped_rst_directive(): + """ + Do cool stuff. + + ```py + .. code-block:: python + + cool_stuff( 1 ) + + ``` + + Done. + """ + pass +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_dynamic_line_width.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_dynamic_line_width.py.snap new file mode 100644 index 0000000000000..91c1984124c9d --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_dynamic_line_width.py.snap @@ -0,0 +1,1630 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_dynamic_line_width.py +--- +## Input +```python +def simple(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz(Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5): + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + ``` + + Done. + """ + pass + + +# Like simple, but we double everything up to ensure the indent level is +# tracked correctly. +def repeated(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz(Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5): + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + + + class Abcdefghijklmopqrstuvwxyz(Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5): + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) + ``` + + Done. + """ + pass + + +# Like simple, but we make one line exactly one character longer than the limit +# (for 4-space indents) and make sure it gets wrapped. +def barely_exceeds_limit(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz(Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5): + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is 89 columns, which is one + # more than the limit. Therefore, it should get wrapped for + # indent_width >= 4. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a5678) + return 5 + self.x = doit( 5 ) + ``` + + Done. + """ + pass + + +# This tests that if the code block is unindented, that it gets indented and +# the dynamic line width setting is applied correctly. +def unindented(): + """ + First line. + +```py +class Abcdefghijklmopqrstuvwxyz(Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5): + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + self.x = doit( 5 ) +``` + + Done. + """ + pass + + +# Like unindented, but contains a `print` line where it just barely exceeds the +# globally configured line width *after* its indentation has been corrected. +def unindented_barely_exceeds_limit(): + """ + First line. + +```py +class Abcdefghijklmopqrstuvwxyz(Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5): + def abcdefghijklmnopqrstuvwxyz(self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4): + # For 4 space indents, this is 89 columns, which is one + # more than the limit. Therefore, it should get wrapped for + # indent_width >= 4. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a5678) + return 5 + self.x = doit( 5 ) +``` + + Done. + """ + pass +``` + +## Outputs +### Output 1 +``` +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +docstring-code-line-width = "dynamic" +preview = Disabled +``` + +```python +def simple(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# Like simple, but we double everything up to ensure the indent level is +# tracked correctly. +def repeated(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# Like simple, but we make one line exactly one character longer than the limit +# (for 4-space indents) and make sure it gets wrapped. +def barely_exceeds_limit(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is 89 columns, which is one + # more than the limit. Therefore, it should get wrapped for + # indent_width >= 4. + print( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a5678 + ) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# This tests that if the code block is unindented, that it gets indented and +# the dynamic line width setting is applied correctly. +def unindented(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# Like unindented, but contains a `print` line where it just barely exceeds the +# globally configured line width *after* its indentation has been corrected. +def unindented_barely_exceeds_limit(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is 89 columns, which is one + # more than the limit. Therefore, it should get wrapped for + # indent_width >= 4. + print( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a5678 + ) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass +``` + + +### Output 2 +``` +indent-style = space +line-width = 88 +indent-width = 2 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +docstring-code-line-width = "dynamic" +preview = Disabled +``` + +```python +def simple(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# Like simple, but we double everything up to ensure the indent level is +# tracked correctly. +def repeated(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# Like simple, but we make one line exactly one character longer than the limit +# (for 4-space indents) and make sure it gets wrapped. +def barely_exceeds_limit(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is 89 columns, which is one + # more than the limit. Therefore, it should get wrapped for + # indent_width >= 4. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a5678) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# This tests that if the code block is unindented, that it gets indented and +# the dynamic line width setting is applied correctly. +def unindented(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# Like unindented, but contains a `print` line where it just barely exceeds the +# globally configured line width *after* its indentation has been corrected. +def unindented_barely_exceeds_limit(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is 89 columns, which is one + # more than the limit. Therefore, it should get wrapped for + # indent_width >= 4. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a5678) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass +``` + + +### Output 3 +``` +indent-style = tab +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +docstring-code-line-width = "dynamic" +preview = Disabled +``` + +```python +def simple(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# Like simple, but we double everything up to ensure the indent level is +# tracked correctly. +def repeated(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# Like simple, but we make one line exactly one character longer than the limit +# (for 4-space indents) and make sure it gets wrapped. +def barely_exceeds_limit(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is 89 columns, which is one + # more than the limit. Therefore, it should get wrapped for + # indent_width >= 4. + print( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a5678 + ) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# This tests that if the code block is unindented, that it gets indented and +# the dynamic line width setting is applied correctly. +def unindented(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a567) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# Like unindented, but contains a `print` line where it just barely exceeds the +# globally configured line width *after* its indentation has been corrected. +def unindented_barely_exceeds_limit(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + def abcdefghijklmnopqrstuvwxyz( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4 + ): + # For 4 space indents, this is 89 columns, which is one + # more than the limit. Therefore, it should get wrapped for + # indent_width >= 4. + print( + abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, a2, a3, a4, a5678 + ) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass +``` + + +### Output 4 +``` +indent-style = tab +line-width = 88 +indent-width = 8 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Enabled +docstring-code-line-width = "dynamic" +preview = Disabled +``` + +```python +def simple(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + def abcdefghijklmnopqrstuvwxyz( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + a567, + ) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# Like simple, but we double everything up to ensure the indent level is +# tracked correctly. +def repeated(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + def abcdefghijklmnopqrstuvwxyz( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + a567, + ) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + a567, + ) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + self, + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + def abcdefghijklmnopqrstuvwxyz( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + a567, + ) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + a567, + ) + return 5 + + self.x = doit(5) + + + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + def abcdefghijklmnopqrstuvwxyz( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + a567, + ) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + a567, + ) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + self, + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + def abcdefghijklmnopqrstuvwxyz( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + a567, + ) + return 5 + + self.x = doit(5) + + def abcdefghijklmnopqrstuvwxyz( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + a567, + ) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# Like simple, but we make one line exactly one character longer than the limit +# (for 4-space indents) and make sure it gets wrapped. +def barely_exceeds_limit(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + def abcdefghijklmnopqrstuvwxyz( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + # For 4 space indents, this is 89 columns, which is one + # more than the limit. Therefore, it should get wrapped for + # indent_width >= 4. + print( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + a5678, + ) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# This tests that if the code block is unindented, that it gets indented and +# the dynamic line width setting is applied correctly. +def unindented(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + def abcdefghijklmnopqrstuvwxyz( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + # For 4 space indents, this is just one character shy of + # tripping the default line width of 88. So it should not be + # wrapped. + print( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + a567, + ) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass + + +# Like unindented, but contains a `print` line where it just barely exceeds the +# globally configured line width *after* its indentation has been corrected. +def unindented_barely_exceeds_limit(): + """ + First line. + + ```py + class Abcdefghijklmopqrstuvwxyz( + Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, A2, A3, A4, A5 + ): + def abcdefghijklmnopqrstuvwxyz( + self, + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + def abcdefghijklmnopqrstuvwxyz( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + ): + # For 4 space indents, this is 89 columns, which is one + # more than the limit. Therefore, it should get wrapped for + # indent_width >= 4. + print( + abc, + ddef, + ghi, + jkl, + mno, + pqr, + stu, + vwx, + yz, + a1, + a2, + a3, + a4, + a5678, + ) + return 5 + + self.x = doit(5) + ``` + + Done. + """ + pass +``` + + + From c306f85691ef64284138c46e312c3f99dbbffb3a Mon Sep 17 00:00:00 2001 From: Samuel Cormier-Iijima Date: Tue, 12 Dec 2023 13:23:46 -0500 Subject: [PATCH 171/197] F841: support fixing unused assignments in tuples by renaming variables (#9107) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary A fairly common pattern which triggers F841 is unused variables from tuple assignments, e.g.: user, created = User.objects.get_or_create(...) ^ F841: Local variable `created` is assigned to but never used This error is currently not auto-fixable. This PR adds support for fixing the error automatically by renaming the unused variable to have a leading underscore (i.e. `_created`) **iff** the `dummy-variable-rgx` setting would match it. I considered using `renamers::Renamer` here, but because by the nature of the error there should be no references to it, that seemed like overkill. Also note that the fix might break by shadowing the new name if it is already used elsewhere in the scope. I left it as is because 1. the renamed variable matches the "unused" regex, so it should hopefully not already be used, 2. the fix is marked as unsafe so it should be reviewed manually anyways, and 3. I'm not actually sure how to check the scope for the new variable name 😅 --- .../rules/pyflakes/rules/unused_variable.rs | 8 +++ ...ules__pyflakes__tests__F841_F841_0.py.snap | 24 +++++++- ...ules__pyflakes__tests__F841_F841_1.py.snap | 60 +++++++++++++++++-- ...ules__pyflakes__tests__F841_F841_3.py.snap | 24 +++++++- ...lakes__tests__preview__F841_F841_4.py.snap | 24 +++++++- 5 files changed, 128 insertions(+), 12 deletions(-) diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs b/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs index f5eb694483617..e099c15f3110d 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs @@ -247,6 +247,14 @@ fn remove_unused_variable(binding: &Binding, checker: &Checker) -> Option { Some(Fix::unsafe_edit(edit).isolate(isolation)) }; } + } else { + let name = binding.name(checker.locator()); + let renamed = format!("_{name}"); + if checker.settings.dummy_variable_rgx.is_match(&renamed) { + let edit = Edit::range_replacement(renamed, binding.range()); + + return Some(Fix::unsafe_edit(edit).isolate(isolation)); + } } } diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_0.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_0.py.snap index 3fc06720a716c..7e1b2458bfa3f 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_0.py.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_0.py.snap @@ -57,7 +57,7 @@ F841_0.py:20:5: F841 [*] Local variable `foo` is assigned to but never used 22 21 | 23 22 | bar = (1, 2) -F841_0.py:21:6: F841 Local variable `a` is assigned to but never used +F841_0.py:21:6: F841 [*] Local variable `a` is assigned to but never used | 19 | def f(): 20 | foo = (1, 2) @@ -68,7 +68,17 @@ F841_0.py:21:6: F841 Local variable `a` is assigned to but never used | = help: Remove assignment to unused variable `a` -F841_0.py:21:9: F841 Local variable `b` is assigned to but never used +ℹ Unsafe fix +18 18 | +19 19 | def f(): +20 20 | foo = (1, 2) +21 |- (a, b) = (1, 2) + 21 |+ (_a, b) = (1, 2) +22 22 | +23 23 | bar = (1, 2) +24 24 | (c, d) = bar + +F841_0.py:21:9: F841 [*] Local variable `b` is assigned to but never used | 19 | def f(): 20 | foo = (1, 2) @@ -79,6 +89,16 @@ F841_0.py:21:9: F841 Local variable `b` is assigned to but never used | = help: Remove assignment to unused variable `b` +ℹ Unsafe fix +18 18 | +19 19 | def f(): +20 20 | foo = (1, 2) +21 |- (a, b) = (1, 2) + 21 |+ (a, _b) = (1, 2) +22 22 | +23 23 | bar = (1, 2) +24 24 | (c, d) = bar + F841_0.py:26:14: F841 [*] Local variable `baz` is assigned to but never used | 24 | (c, d) = bar diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_1.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_1.py.snap index 7985de9913f88..9cb0b013fd00e 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_1.py.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_1.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/pyflakes/mod.rs --- -F841_1.py:6:5: F841 Local variable `x` is assigned to but never used +F841_1.py:6:5: F841 [*] Local variable `x` is assigned to but never used | 5 | def f(): 6 | x, y = 1, 2 # this triggers F841 as it's just a simple assignment where unpacking isn't needed @@ -9,7 +9,17 @@ F841_1.py:6:5: F841 Local variable `x` is assigned to but never used | = help: Remove assignment to unused variable `x` -F841_1.py:6:8: F841 Local variable `y` is assigned to but never used +ℹ Unsafe fix +3 3 | +4 4 | +5 5 | def f(): +6 |- x, y = 1, 2 # this triggers F841 as it's just a simple assignment where unpacking isn't needed + 6 |+ _x, y = 1, 2 # this triggers F841 as it's just a simple assignment where unpacking isn't needed +7 7 | +8 8 | +9 9 | def f(): + +F841_1.py:6:8: F841 [*] Local variable `y` is assigned to but never used | 5 | def f(): 6 | x, y = 1, 2 # this triggers F841 as it's just a simple assignment where unpacking isn't needed @@ -17,6 +27,16 @@ F841_1.py:6:8: F841 Local variable `y` is assigned to but never used | = help: Remove assignment to unused variable `y` +ℹ Unsafe fix +3 3 | +4 4 | +5 5 | def f(): +6 |- x, y = 1, 2 # this triggers F841 as it's just a simple assignment where unpacking isn't needed + 6 |+ x, _y = 1, 2 # this triggers F841 as it's just a simple assignment where unpacking isn't needed +7 7 | +8 8 | +9 9 | def f(): + F841_1.py:16:14: F841 [*] Local variable `coords` is assigned to but never used | 15 | def f(): @@ -53,7 +73,7 @@ F841_1.py:20:5: F841 [*] Local variable `coords` is assigned to but never used 22 22 | 23 23 | def f(): -F841_1.py:24:6: F841 Local variable `a` is assigned to but never used +F841_1.py:24:6: F841 [*] Local variable `a` is assigned to but never used | 23 | def f(): 24 | (a, b) = (x, y) = 1, 2 # this triggers F841 on everything @@ -61,7 +81,14 @@ F841_1.py:24:6: F841 Local variable `a` is assigned to but never used | = help: Remove assignment to unused variable `a` -F841_1.py:24:9: F841 Local variable `b` is assigned to but never used +ℹ Unsafe fix +21 21 | +22 22 | +23 23 | def f(): +24 |- (a, b) = (x, y) = 1, 2 # this triggers F841 on everything + 24 |+ (_a, b) = (x, y) = 1, 2 # this triggers F841 on everything + +F841_1.py:24:9: F841 [*] Local variable `b` is assigned to but never used | 23 | def f(): 24 | (a, b) = (x, y) = 1, 2 # this triggers F841 on everything @@ -69,7 +96,14 @@ F841_1.py:24:9: F841 Local variable `b` is assigned to but never used | = help: Remove assignment to unused variable `b` -F841_1.py:24:15: F841 Local variable `x` is assigned to but never used +ℹ Unsafe fix +21 21 | +22 22 | +23 23 | def f(): +24 |- (a, b) = (x, y) = 1, 2 # this triggers F841 on everything + 24 |+ (a, _b) = (x, y) = 1, 2 # this triggers F841 on everything + +F841_1.py:24:15: F841 [*] Local variable `x` is assigned to but never used | 23 | def f(): 24 | (a, b) = (x, y) = 1, 2 # this triggers F841 on everything @@ -77,7 +111,14 @@ F841_1.py:24:15: F841 Local variable `x` is assigned to but never used | = help: Remove assignment to unused variable `x` -F841_1.py:24:18: F841 Local variable `y` is assigned to but never used +ℹ Unsafe fix +21 21 | +22 22 | +23 23 | def f(): +24 |- (a, b) = (x, y) = 1, 2 # this triggers F841 on everything + 24 |+ (a, b) = (_x, y) = 1, 2 # this triggers F841 on everything + +F841_1.py:24:18: F841 [*] Local variable `y` is assigned to but never used | 23 | def f(): 24 | (a, b) = (x, y) = 1, 2 # this triggers F841 on everything @@ -85,4 +126,11 @@ F841_1.py:24:18: F841 Local variable `y` is assigned to but never used | = help: Remove assignment to unused variable `y` +ℹ Unsafe fix +21 21 | +22 22 | +23 23 | def f(): +24 |- (a, b) = (x, y) = 1, 2 # this triggers F841 on everything + 24 |+ (a, b) = (x, _y) = 1, 2 # this triggers F841 on everything + diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_3.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_3.py.snap index 9a29ab4098df2..8b60f4da8a24c 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_3.py.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_3.py.snap @@ -156,7 +156,7 @@ F841_3.py:27:46: F841 [*] Local variable `z3` is assigned to but never used 29 29 | 30 30 | -F841_3.py:32:6: F841 Local variable `x1` is assigned to but never used +F841_3.py:32:6: F841 [*] Local variable `x1` is assigned to but never used | 31 | def f(): 32 | (x1, y1) = (1, 2) @@ -166,7 +166,17 @@ F841_3.py:32:6: F841 Local variable `x1` is assigned to but never used | = help: Remove assignment to unused variable `x1` -F841_3.py:32:10: F841 Local variable `y1` is assigned to but never used +ℹ Unsafe fix +29 29 | +30 30 | +31 31 | def f(): +32 |- (x1, y1) = (1, 2) + 32 |+ (_x1, y1) = (1, 2) +33 33 | (x2, y2) = coords2 = (1, 2) +34 34 | coords3 = (x3, y3) = (1, 2) +35 35 | + +F841_3.py:32:10: F841 [*] Local variable `y1` is assigned to but never used | 31 | def f(): 32 | (x1, y1) = (1, 2) @@ -176,6 +186,16 @@ F841_3.py:32:10: F841 Local variable `y1` is assigned to but never used | = help: Remove assignment to unused variable `y1` +ℹ Unsafe fix +29 29 | +30 30 | +31 31 | def f(): +32 |- (x1, y1) = (1, 2) + 32 |+ (x1, _y1) = (1, 2) +33 33 | (x2, y2) = coords2 = (1, 2) +34 34 | coords3 = (x3, y3) = (1, 2) +35 35 | + F841_3.py:33:16: F841 [*] Local variable `coords2` is assigned to but never used | 31 | def f(): diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__F841_F841_4.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__F841_F841_4.py.snap index f781c31d82e2d..661343dd141da 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__F841_F841_4.py.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__F841_F841_4.py.snap @@ -20,7 +20,7 @@ F841_4.py:12:5: F841 [*] Local variable `a` is assigned to but never used 14 14 | 15 15 | -F841_4.py:13:5: F841 Local variable `b` is assigned to but never used +F841_4.py:13:5: F841 [*] Local variable `b` is assigned to but never used | 11 | def bar(): 12 | a = foo() @@ -29,7 +29,17 @@ F841_4.py:13:5: F841 Local variable `b` is assigned to but never used | = help: Remove assignment to unused variable `b` -F841_4.py:13:8: F841 Local variable `c` is assigned to but never used +ℹ Unsafe fix +10 10 | +11 11 | def bar(): +12 12 | a = foo() +13 |- b, c = foo() + 13 |+ _b, c = foo() +14 14 | +15 15 | +16 16 | def baz(): + +F841_4.py:13:8: F841 [*] Local variable `c` is assigned to but never used | 11 | def bar(): 12 | a = foo() @@ -38,4 +48,14 @@ F841_4.py:13:8: F841 Local variable `c` is assigned to but never used | = help: Remove assignment to unused variable `c` +ℹ Unsafe fix +10 10 | +11 11 | def bar(): +12 12 | a = foo() +13 |- b, c = foo() + 13 |+ b, _c = foo() +14 14 | +15 15 | +16 16 | def baz(): + From 6c0068eeecbd5ea64e4286e7866b3b7ba25bd338 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Tue, 12 Dec 2023 15:16:01 -0600 Subject: [PATCH 172/197] Remove `ExprFormattedValue` formatting impl (#9108) --- .../src/expression/expr_formatted_value.rs | 24 ------------------- 1 file changed, 24 deletions(-) delete mode 100644 crates/ruff_python_formatter/src/expression/expr_formatted_value.rs diff --git a/crates/ruff_python_formatter/src/expression/expr_formatted_value.rs b/crates/ruff_python_formatter/src/expression/expr_formatted_value.rs deleted file mode 100644 index a1939891a30a1..0000000000000 --- a/crates/ruff_python_formatter/src/expression/expr_formatted_value.rs +++ /dev/null @@ -1,24 +0,0 @@ -use ruff_python_ast::AnyNodeRef; -use ruff_python_ast::ExprFormattedValue; - -use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses}; -use crate::prelude::*; - -#[derive(Default)] -pub struct FormatExprFormattedValue; - -impl FormatNodeRule for FormatExprFormattedValue { - fn fmt_fields(&self, _item: &ExprFormattedValue, _f: &mut PyFormatter) -> FormatResult<()> { - unreachable!("Handled inside of `FormatExprFString"); - } -} - -impl NeedsParentheses for ExprFormattedValue { - fn needs_parentheses( - &self, - _parent: AnyNodeRef, - _context: &PyFormatContext, - ) -> OptionalParentheses { - OptionalParentheses::Multiline - } -} From cb201bc4a5ab1a6e312b375f820d48bdcc4bf9a3 Mon Sep 17 00:00:00 2001 From: T-256 <132141463+T-256@users.noreply.github.com> Date: Wed, 13 Dec 2023 02:49:55 +0330 Subject: [PATCH 173/197] `PIE804`: Prevent keyword arguments duplication (#8450) --- .../test/fixtures/flake8_pie/PIE804.py | 5 +- .../rules/unnecessary_dict_kwargs.rs | 95 ++++++++++++++----- ...__flake8_pie__tests__PIE804_PIE804.py.snap | 86 +++++++++++++---- 3 files changed, 142 insertions(+), 44 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE804.py b/crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE804.py index 03d88e0ef8e22..a5b3674422e1a 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE804.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE804.py @@ -19,5 +19,8 @@ foo(**{"": True}) foo(**{f"buzz__{bar}": True}) abc(**{"for": 3}) - foo(**{},) + +# Duplicated key names won't be fixed, to avoid syntax errors. +abc(**{'a': b}, **{'a': c}) # PIE804 +abc(a=1, **{'a': c}, **{'b': c}) # PIE804 diff --git a/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs b/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs index ab4c7ceb9ddcc..5f0bf0abb48d0 100644 --- a/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs +++ b/crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_dict_kwargs.rs @@ -1,11 +1,13 @@ +use std::hash::BuildHasherDefault; + use itertools::Itertools; -use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; -use ruff_python_ast::{self as ast, Expr}; +use rustc_hash::FxHashSet; +use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_text_size::Ranged; - +use ruff_python_ast::{self as ast, Expr}; use ruff_python_stdlib::identifiers::is_identifier; +use ruff_text_size::Ranged; use crate::checkers::ast::Checker; use crate::fix::edits::{remove_argument, Parentheses}; @@ -41,36 +43,39 @@ use crate::fix::edits::{remove_argument, Parentheses}; #[violation] pub struct UnnecessaryDictKwargs; -impl AlwaysFixableViolation for UnnecessaryDictKwargs { +impl Violation for UnnecessaryDictKwargs { + const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes; + #[derive_message_formats] fn message(&self) -> String { format!("Unnecessary `dict` kwargs") } - fn fix_title(&self) -> String { - format!("Remove unnecessary kwargs") + fn fix_title(&self) -> Option { + Some(format!("Remove unnecessary kwargs")) } } /// PIE804 pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, call: &ast::ExprCall) { - for kw in &call.arguments.keywords { - // keyword is a spread operator (indicated by None) - if kw.arg.is_some() { + let mut duplicate_keywords = None; + for keyword in &call.arguments.keywords { + // keyword is a spread operator (indicated by None). + if keyword.arg.is_some() { continue; } - let Expr::Dict(ast::ExprDict { keys, values, .. }) = &kw.value else { + let Expr::Dict(ast::ExprDict { keys, values, .. }) = &keyword.value else { continue; }; // Ex) `foo(**{**bar})` if matches!(keys.as_slice(), [None]) { - let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, call.range()); + let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, keyword.range()); diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( format!("**{}", checker.locator().slice(values[0].range())), - kw.range(), + keyword.range(), ))); checker.diagnostics.push(diagnostic); @@ -87,12 +92,12 @@ pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, call: &ast::ExprCal continue; } - let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, call.range()); + let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, keyword.range()); if values.is_empty() { diagnostic.try_set_fix(|| { remove_argument( - kw, + keyword, &call.arguments, Parentheses::Preserve, checker.locator().contents(), @@ -100,22 +105,64 @@ pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, call: &ast::ExprCal .map(Fix::safe_edit) }); } else { - diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - kwargs + // Compute the set of duplicate keywords (lazily). + if duplicate_keywords.is_none() { + duplicate_keywords = Some(duplicates(call)); + } + + // Avoid fixing if doing so could introduce a duplicate keyword argument. + if let Some(duplicate_keywords) = duplicate_keywords.as_ref() { + if kwargs .iter() - .zip(values.iter()) - .map(|(kwarg, value)| { - format!("{}={}", kwarg, checker.locator().slice(value.range())) - }) - .join(", "), - kw.range(), - ))); + .all(|kwarg| !duplicate_keywords.contains(kwarg)) + { + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + kwargs + .iter() + .zip(values.iter()) + .map(|(kwarg, value)| { + format!("{}={}", kwarg, checker.locator().slice(value.range())) + }) + .join(", "), + keyword.range(), + ))); + } + } } checker.diagnostics.push(diagnostic); } } +/// Determine the set of keywords that appear in multiple positions (either directly, as in +/// `func(x=1)`, or indirectly, as in `func(**{"x": 1})`). +fn duplicates(call: &ast::ExprCall) -> FxHashSet<&str> { + let mut seen = FxHashSet::with_capacity_and_hasher( + call.arguments.keywords.len(), + BuildHasherDefault::default(), + ); + let mut duplicates = FxHashSet::with_capacity_and_hasher( + call.arguments.keywords.len(), + BuildHasherDefault::default(), + ); + for keyword in &call.arguments.keywords { + if let Some(name) = &keyword.arg { + if !seen.insert(name.as_str()) { + duplicates.insert(name.as_str()); + } + } else if let Expr::Dict(ast::ExprDict { keys, .. }) = &keyword.value { + for key in keys { + if let Some(name) = key.as_ref().and_then(as_kwarg) { + if !seen.insert(name) { + duplicates.insert(name); + } + } + } + } + } + duplicates +} + /// Return `Some` if a key is a valid keyword argument name, or `None` otherwise. fn as_kwarg(key: &Expr) -> Option<&str> { if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = key { diff --git a/crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE804_PIE804.py.snap b/crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE804_PIE804.py.snap index 0f608fbedb040..15d993a0befee 100644 --- a/crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE804_PIE804.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pie/snapshots/ruff_linter__rules__flake8_pie__tests__PIE804_PIE804.py.snap @@ -1,10 +1,10 @@ --- source: crates/ruff_linter/src/rules/flake8_pie/mod.rs --- -PIE804.py:1:1: PIE804 [*] Unnecessary `dict` kwargs +PIE804.py:1:5: PIE804 [*] Unnecessary `dict` kwargs | 1 | foo(**{"bar": True}) # PIE804 - | ^^^^^^^^^^^^^^^^^^^^ PIE804 + | ^^^^^^^^^^^^^^^ PIE804 2 | 3 | foo(**{"r2d2": True}) # PIE804 | @@ -17,12 +17,12 @@ PIE804.py:1:1: PIE804 [*] Unnecessary `dict` kwargs 3 3 | foo(**{"r2d2": True}) # PIE804 4 4 | -PIE804.py:3:1: PIE804 [*] Unnecessary `dict` kwargs +PIE804.py:3:5: PIE804 [*] Unnecessary `dict` kwargs | 1 | foo(**{"bar": True}) # PIE804 2 | 3 | foo(**{"r2d2": True}) # PIE804 - | ^^^^^^^^^^^^^^^^^^^^^ PIE804 + | ^^^^^^^^^^^^^^^^ PIE804 4 | 5 | Foo.objects.create(**{"bar": True}) # PIE804 | @@ -37,12 +37,12 @@ PIE804.py:3:1: PIE804 [*] Unnecessary `dict` kwargs 5 5 | Foo.objects.create(**{"bar": True}) # PIE804 6 6 | -PIE804.py:5:1: PIE804 [*] Unnecessary `dict` kwargs +PIE804.py:5:20: PIE804 [*] Unnecessary `dict` kwargs | 3 | foo(**{"r2d2": True}) # PIE804 4 | 5 | Foo.objects.create(**{"bar": True}) # PIE804 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PIE804 + | ^^^^^^^^^^^^^^^ PIE804 6 | 7 | Foo.objects.create(**{"_id": some_id}) # PIE804 | @@ -58,12 +58,12 @@ PIE804.py:5:1: PIE804 [*] Unnecessary `dict` kwargs 7 7 | Foo.objects.create(**{"_id": some_id}) # PIE804 8 8 | -PIE804.py:7:1: PIE804 [*] Unnecessary `dict` kwargs +PIE804.py:7:20: PIE804 [*] Unnecessary `dict` kwargs | 5 | Foo.objects.create(**{"bar": True}) # PIE804 6 | 7 | Foo.objects.create(**{"_id": some_id}) # PIE804 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PIE804 + | ^^^^^^^^^^^^^^^^^^ PIE804 8 | 9 | Foo.objects.create(**{**bar}) # PIE804 | @@ -79,12 +79,12 @@ PIE804.py:7:1: PIE804 [*] Unnecessary `dict` kwargs 9 9 | Foo.objects.create(**{**bar}) # PIE804 10 10 | -PIE804.py:9:1: PIE804 [*] Unnecessary `dict` kwargs +PIE804.py:9:20: PIE804 [*] Unnecessary `dict` kwargs | 7 | Foo.objects.create(**{"_id": some_id}) # PIE804 8 | 9 | Foo.objects.create(**{**bar}) # PIE804 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PIE804 + | ^^^^^^^^^ PIE804 10 | 11 | foo(**{}) | @@ -100,12 +100,12 @@ PIE804.py:9:1: PIE804 [*] Unnecessary `dict` kwargs 11 11 | foo(**{}) 12 12 | -PIE804.py:11:1: PIE804 [*] Unnecessary `dict` kwargs +PIE804.py:11:5: PIE804 [*] Unnecessary `dict` kwargs | 9 | Foo.objects.create(**{**bar}) # PIE804 10 | 11 | foo(**{}) - | ^^^^^^^^^ PIE804 + | ^^^^ PIE804 12 | 13 | foo(**{**data, "foo": "buzz"}) | @@ -121,20 +121,68 @@ PIE804.py:11:1: PIE804 [*] Unnecessary `dict` kwargs 13 13 | foo(**{**data, "foo": "buzz"}) 14 14 | foo(**buzz) -PIE804.py:23:1: PIE804 [*] Unnecessary `dict` kwargs +PIE804.py:22:5: PIE804 [*] Unnecessary `dict` kwargs | +20 | foo(**{f"buzz__{bar}": True}) 21 | abc(**{"for": 3}) -22 | -23 | foo(**{},) - | ^^^^^^^^^^ PIE804 +22 | foo(**{},) + | ^^^^ PIE804 +23 | +24 | # Duplicated key names won't be fixed, to avoid syntax errors. | = help: Remove unnecessary kwargs ℹ Safe fix +19 19 | foo(**{"": True}) 20 20 | foo(**{f"buzz__{bar}": True}) 21 21 | abc(**{"for": 3}) -22 22 | -23 |-foo(**{},) - 23 |+foo() +22 |-foo(**{},) + 22 |+foo() +23 23 | +24 24 | # Duplicated key names won't be fixed, to avoid syntax errors. +25 25 | abc(**{'a': b}, **{'a': c}) # PIE804 + +PIE804.py:25:5: PIE804 Unnecessary `dict` kwargs + | +24 | # Duplicated key names won't be fixed, to avoid syntax errors. +25 | abc(**{'a': b}, **{'a': c}) # PIE804 + | ^^^^^^^^^^ PIE804 +26 | abc(a=1, **{'a': c}, **{'b': c}) # PIE804 + | + = help: Remove unnecessary kwargs + +PIE804.py:25:17: PIE804 Unnecessary `dict` kwargs + | +24 | # Duplicated key names won't be fixed, to avoid syntax errors. +25 | abc(**{'a': b}, **{'a': c}) # PIE804 + | ^^^^^^^^^^ PIE804 +26 | abc(a=1, **{'a': c}, **{'b': c}) # PIE804 + | + = help: Remove unnecessary kwargs + +PIE804.py:26:10: PIE804 Unnecessary `dict` kwargs + | +24 | # Duplicated key names won't be fixed, to avoid syntax errors. +25 | abc(**{'a': b}, **{'a': c}) # PIE804 +26 | abc(a=1, **{'a': c}, **{'b': c}) # PIE804 + | ^^^^^^^^^^ PIE804 + | + = help: Remove unnecessary kwargs + +PIE804.py:26:22: PIE804 [*] Unnecessary `dict` kwargs + | +24 | # Duplicated key names won't be fixed, to avoid syntax errors. +25 | abc(**{'a': b}, **{'a': c}) # PIE804 +26 | abc(a=1, **{'a': c}, **{'b': c}) # PIE804 + | ^^^^^^^^^^ PIE804 + | + = help: Remove unnecessary kwargs + +ℹ Safe fix +23 23 | +24 24 | # Duplicated key names won't be fixed, to avoid syntax errors. +25 25 | abc(**{'a': b}, **{'a': c}) # PIE804 +26 |-abc(a=1, **{'a': c}, **{'b': c}) # PIE804 + 26 |+abc(a=1, **{'a': c}, b=c) # PIE804 From 8314c8bb056507cd2af064004b73f783b761e2bb Mon Sep 17 00:00:00 2001 From: qdegraaf <34540841+qdegraaf@users.noreply.github.com> Date: Wed, 13 Dec 2023 01:24:47 +0100 Subject: [PATCH 174/197] [`typing`] Add `find_assigned_value` helper func to `typing.rs` to retrieve value of a given variable `id` (#8583) ## Summary Adds `find_assigned_value` a function which gets the `&Expr` assigned to a given `id` if one exists in the semantic model. Open TODOs: - [ ] Handle `binding.kind.is_unpacked_assignment()`: I am bit confused by this one. The snippet from its documentation does not appear to be counted as an unpacked assignment and the only ones I could find for which that was true were invalid Python like: ```python x, y = 1 ``` - [ ] How to handle AugAssign. Can we combine statements like: ```python (a, b) = [(1, 2, 3), (4,)] a += (6, 7) ``` to get the full value for a? Code currently just returns `None` for these assign types - [ ] Multi target assigns ```python m_c = (m_d, m_e) = (0, 0) trio.sleep(m_c) # OK trio.sleep(m_d) # TRIO115 trio.sleep(m_e) # TRIO115 ``` ## Test Plan Used the function in two rules: - `TRIO115` - `PERF101` Expanded both their fixtures for explicit multi target check --- .../test/fixtures/flake8_trio/TRIO115.py | 22 ++ .../test/fixtures/perflint/PERF101.py | 5 + .../flake8_trio/rules/zero_sleep_call.rs | 35 +-- ...lake8_trio__tests__TRIO115_TRIO115.py.snap | 247 +++++++++++++++--- .../perflint/rules/unnecessary_list_cast.rs | 35 +-- ...__perflint__tests__PERF101_PERF101.py.snap | 18 ++ .../src/analyze/typing.rs | 105 ++++++++ 7 files changed, 382 insertions(+), 85 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO115.py b/crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO115.py index aa25cb8e5a3ae..d7466beb0f5d3 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO115.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO115.py @@ -19,6 +19,28 @@ async def func(): bar = "bar" trio.sleep(bar) + x, y = 0, 2000 + trio.sleep(x) # TRIO115 + trio.sleep(y) # OK + + (a, b, [c, (d, e)]) = (1, 2, (0, [4, 0])) + trio.sleep(c) # TRIO115 + trio.sleep(d) # OK + trio.sleep(e) # TRIO115 + + m_x, m_y = 0 + trio.sleep(m_y) # TRIO115 + trio.sleep(m_x) # TRIO115 + + m_a = m_b = 0 + trio.sleep(m_a) # TRIO115 + trio.sleep(m_b) # TRIO115 + + m_c = (m_d, m_e) = (0, 0) + trio.sleep(m_c) # OK + trio.sleep(m_d) # TRIO115 + trio.sleep(m_e) # TRIO115 + def func(): trio.run(trio.sleep(0)) # TRIO115 diff --git a/crates/ruff_linter/resources/test/fixtures/perflint/PERF101.py b/crates/ruff_linter/resources/test/fixtures/perflint/PERF101.py index fbef6a7b2a709..e6ae0b8f25d75 100644 --- a/crates/ruff_linter/resources/test/fixtures/perflint/PERF101.py +++ b/crates/ruff_linter/resources/test/fixtures/perflint/PERF101.py @@ -63,3 +63,8 @@ for i in list(foo_set): # Ok foo_set.append(i + 1) + +x, y, nested_tuple = (1, 2, (3, 4, 5)) + +for i in list(nested_tuple): # PERF101 + pass diff --git a/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs b/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs index 6b0e57569c443..57caec4eec68c 100644 --- a/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs +++ b/crates/ruff_linter/src/rules/flake8_trio/rules/zero_sleep_call.rs @@ -1,7 +1,7 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::Stmt; use ruff_python_ast::{self as ast, Expr, ExprCall, Int}; +use ruff_python_semantic::analyze::typing::find_assigned_value; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -71,30 +71,15 @@ pub(crate) fn zero_sleep_call(checker: &mut Checker, call: &ExprCall) { } } Expr::Name(ast::ExprName { id, .. }) => { - let scope = checker.semantic().current_scope(); - if let Some(binding_id) = scope.get(id) { - let binding = checker.semantic().binding(binding_id); - if binding.kind.is_assignment() || binding.kind.is_named_expr_assignment() { - if let Some(parent_id) = binding.source { - let parent = checker.semantic().statement(parent_id); - if let Stmt::Assign(ast::StmtAssign { value, .. }) - | Stmt::AnnAssign(ast::StmtAnnAssign { - value: Some(value), .. - }) - | Stmt::AugAssign(ast::StmtAugAssign { value, .. }) = parent - { - let Expr::NumberLiteral(ast::ExprNumberLiteral { value: num, .. }) = - value.as_ref() - else { - return; - }; - let Some(int) = num.as_int() else { return }; - if *int != Int::ZERO { - return; - } - } - } - } + let Some(value) = find_assigned_value(id, checker.semantic()) else { + return; + }; + let Expr::NumberLiteral(ast::ExprNumberLiteral { value: num, .. }) = value else { + return; + }; + let Some(int) = num.as_int() else { return }; + if *int != Int::ZERO { + return; } } _ => return, diff --git a/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap b/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap index 0dfeef7c653fb..1ade9f757bbaa 100644 --- a/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap +++ b/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap @@ -85,51 +85,230 @@ TRIO115.py:17:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.s 19 19 | bar = "bar" 20 20 | trio.sleep(bar) -TRIO115.py:31:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` +TRIO115.py:23:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` | -30 | def func(): -31 | sleep(0) # TRIO115 - | ^^^^^^^^ TRIO115 +22 | x, y = 0, 2000 +23 | trio.sleep(x) # TRIO115 + | ^^^^^^^^^^^^^ TRIO115 +24 | trio.sleep(y) # OK | = help: Replace with `trio.lowlevel.checkpoint()` ℹ Safe fix -24 24 | trio.run(trio.sleep(0)) # TRIO115 +20 20 | trio.sleep(bar) +21 21 | +22 22 | x, y = 0, 2000 +23 |- trio.sleep(x) # TRIO115 + 23 |+ trio.lowlevel.checkpoint() # TRIO115 +24 24 | trio.sleep(y) # OK 25 25 | -26 26 | -27 |-from trio import Event, sleep - 27 |+from trio import Event, sleep, lowlevel -28 28 | -29 29 | -30 30 | def func(): -31 |- sleep(0) # TRIO115 - 31 |+ lowlevel.checkpoint() # TRIO115 -32 32 | -33 33 | -34 34 | async def func(): - -TRIO115.py:35:11: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` - | -34 | async def func(): -35 | await sleep(seconds=0) # TRIO115 - | ^^^^^^^^^^^^^^^^ TRIO115 +26 26 | (a, b, [c, (d, e)]) = (1, 2, (0, [4, 0])) + +TRIO115.py:27:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` + | +26 | (a, b, [c, (d, e)]) = (1, 2, (0, [4, 0])) +27 | trio.sleep(c) # TRIO115 + | ^^^^^^^^^^^^^ TRIO115 +28 | trio.sleep(d) # OK +29 | trio.sleep(e) # TRIO115 | = help: Replace with `trio.lowlevel.checkpoint()` ℹ Safe fix -24 24 | trio.run(trio.sleep(0)) # TRIO115 +24 24 | trio.sleep(y) # OK 25 25 | -26 26 | -27 |-from trio import Event, sleep - 27 |+from trio import Event, sleep, lowlevel -28 28 | -29 29 | -30 30 | def func(): +26 26 | (a, b, [c, (d, e)]) = (1, 2, (0, [4, 0])) +27 |- trio.sleep(c) # TRIO115 + 27 |+ trio.lowlevel.checkpoint() # TRIO115 +28 28 | trio.sleep(d) # OK +29 29 | trio.sleep(e) # TRIO115 +30 30 | + +TRIO115.py:29:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` + | +27 | trio.sleep(c) # TRIO115 +28 | trio.sleep(d) # OK +29 | trio.sleep(e) # TRIO115 + | ^^^^^^^^^^^^^ TRIO115 +30 | +31 | m_x, m_y = 0 + | + = help: Replace with `trio.lowlevel.checkpoint()` + +ℹ Safe fix +26 26 | (a, b, [c, (d, e)]) = (1, 2, (0, [4, 0])) +27 27 | trio.sleep(c) # TRIO115 +28 28 | trio.sleep(d) # OK +29 |- trio.sleep(e) # TRIO115 + 29 |+ trio.lowlevel.checkpoint() # TRIO115 +30 30 | +31 31 | m_x, m_y = 0 +32 32 | trio.sleep(m_y) # TRIO115 + +TRIO115.py:32:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` + | +31 | m_x, m_y = 0 +32 | trio.sleep(m_y) # TRIO115 + | ^^^^^^^^^^^^^^^ TRIO115 +33 | trio.sleep(m_x) # TRIO115 + | + = help: Replace with `trio.lowlevel.checkpoint()` + +ℹ Safe fix +29 29 | trio.sleep(e) # TRIO115 +30 30 | +31 31 | m_x, m_y = 0 +32 |- trio.sleep(m_y) # TRIO115 + 32 |+ trio.lowlevel.checkpoint() # TRIO115 +33 33 | trio.sleep(m_x) # TRIO115 +34 34 | +35 35 | m_a = m_b = 0 + +TRIO115.py:33:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` + | +31 | m_x, m_y = 0 +32 | trio.sleep(m_y) # TRIO115 +33 | trio.sleep(m_x) # TRIO115 + | ^^^^^^^^^^^^^^^ TRIO115 +34 | +35 | m_a = m_b = 0 + | + = help: Replace with `trio.lowlevel.checkpoint()` + +ℹ Safe fix +30 30 | +31 31 | m_x, m_y = 0 +32 32 | trio.sleep(m_y) # TRIO115 +33 |- trio.sleep(m_x) # TRIO115 + 33 |+ trio.lowlevel.checkpoint() # TRIO115 +34 34 | +35 35 | m_a = m_b = 0 +36 36 | trio.sleep(m_a) # TRIO115 + +TRIO115.py:36:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` + | +35 | m_a = m_b = 0 +36 | trio.sleep(m_a) # TRIO115 + | ^^^^^^^^^^^^^^^ TRIO115 +37 | trio.sleep(m_b) # TRIO115 + | + = help: Replace with `trio.lowlevel.checkpoint()` + +ℹ Safe fix +33 33 | trio.sleep(m_x) # TRIO115 +34 34 | +35 35 | m_a = m_b = 0 +36 |- trio.sleep(m_a) # TRIO115 + 36 |+ trio.lowlevel.checkpoint() # TRIO115 +37 37 | trio.sleep(m_b) # TRIO115 +38 38 | +39 39 | m_c = (m_d, m_e) = (0, 0) + +TRIO115.py:37:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` + | +35 | m_a = m_b = 0 +36 | trio.sleep(m_a) # TRIO115 +37 | trio.sleep(m_b) # TRIO115 + | ^^^^^^^^^^^^^^^ TRIO115 +38 | +39 | m_c = (m_d, m_e) = (0, 0) + | + = help: Replace with `trio.lowlevel.checkpoint()` + +ℹ Safe fix +34 34 | +35 35 | m_a = m_b = 0 +36 36 | trio.sleep(m_a) # TRIO115 +37 |- trio.sleep(m_b) # TRIO115 + 37 |+ trio.lowlevel.checkpoint() # TRIO115 +38 38 | +39 39 | m_c = (m_d, m_e) = (0, 0) +40 40 | trio.sleep(m_c) # OK + +TRIO115.py:41:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` + | +39 | m_c = (m_d, m_e) = (0, 0) +40 | trio.sleep(m_c) # OK +41 | trio.sleep(m_d) # TRIO115 + | ^^^^^^^^^^^^^^^ TRIO115 +42 | trio.sleep(m_e) # TRIO115 + | + = help: Replace with `trio.lowlevel.checkpoint()` + +ℹ Safe fix +38 38 | +39 39 | m_c = (m_d, m_e) = (0, 0) +40 40 | trio.sleep(m_c) # OK +41 |- trio.sleep(m_d) # TRIO115 + 41 |+ trio.lowlevel.checkpoint() # TRIO115 +42 42 | trio.sleep(m_e) # TRIO115 +43 43 | +44 44 | + +TRIO115.py:42:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` + | +40 | trio.sleep(m_c) # OK +41 | trio.sleep(m_d) # TRIO115 +42 | trio.sleep(m_e) # TRIO115 + | ^^^^^^^^^^^^^^^ TRIO115 + | + = help: Replace with `trio.lowlevel.checkpoint()` + +ℹ Safe fix +39 39 | m_c = (m_d, m_e) = (0, 0) +40 40 | trio.sleep(m_c) # OK +41 41 | trio.sleep(m_d) # TRIO115 +42 |- trio.sleep(m_e) # TRIO115 + 42 |+ trio.lowlevel.checkpoint() # TRIO115 +43 43 | +44 44 | +45 45 | def func(): + +TRIO115.py:53:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` + | +52 | def func(): +53 | sleep(0) # TRIO115 + | ^^^^^^^^ TRIO115 + | + = help: Replace with `trio.lowlevel.checkpoint()` + +ℹ Safe fix +46 46 | trio.run(trio.sleep(0)) # TRIO115 +47 47 | +48 48 | +49 |-from trio import Event, sleep + 49 |+from trio import Event, sleep, lowlevel +50 50 | +51 51 | +52 52 | def func(): +53 |- sleep(0) # TRIO115 + 53 |+ lowlevel.checkpoint() # TRIO115 +54 54 | +55 55 | +56 56 | async def func(): + +TRIO115.py:57:11: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` + | +56 | async def func(): +57 | await sleep(seconds=0) # TRIO115 + | ^^^^^^^^^^^^^^^^ TRIO115 + | + = help: Replace with `trio.lowlevel.checkpoint()` + +ℹ Safe fix +46 46 | trio.run(trio.sleep(0)) # TRIO115 +47 47 | +48 48 | +49 |-from trio import Event, sleep + 49 |+from trio import Event, sleep, lowlevel +50 50 | +51 51 | +52 52 | def func(): -------------------------------------------------------------------------------- -32 32 | -33 33 | -34 34 | async def func(): -35 |- await sleep(seconds=0) # TRIO115 - 35 |+ await lowlevel.checkpoint() # TRIO115 +54 54 | +55 55 | +56 56 | async def func(): +57 |- await sleep(seconds=0) # TRIO115 + 57 |+ await lowlevel.checkpoint() # TRIO115 diff --git a/crates/ruff_linter/src/rules/perflint/rules/unnecessary_list_cast.rs b/crates/ruff_linter/src/rules/perflint/rules/unnecessary_list_cast.rs index 93321cf6b070c..4c73fd4800ecb 100644 --- a/crates/ruff_linter/src/rules/perflint/rules/unnecessary_list_cast.rs +++ b/crates/ruff_linter/src/rules/perflint/rules/unnecessary_list_cast.rs @@ -1,7 +1,7 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::Stmt; -use ruff_python_ast::{self as ast, Arguments, Expr}; +use ruff_python_ast::{self as ast, Arguments, Expr, Stmt}; +use ruff_python_semantic::analyze::typing::find_assigned_value; use ruff_text_size::TextRange; use crate::checkers::ast::Checker; @@ -110,30 +110,13 @@ pub(crate) fn unnecessary_list_cast(checker: &mut Checker, iter: &Expr, body: &[ if body.iter().any(|stmt| match_append(stmt, id)) { return; } - let scope = checker.semantic().current_scope(); - if let Some(binding_id) = scope.get(id) { - let binding = checker.semantic().binding(binding_id); - if binding.kind.is_assignment() || binding.kind.is_named_expr_assignment() { - if let Some(parent_id) = binding.source { - let parent = checker.semantic().statement(parent_id); - if let Stmt::Assign(ast::StmtAssign { value, .. }) - | Stmt::AnnAssign(ast::StmtAnnAssign { - value: Some(value), .. - }) - | Stmt::AugAssign(ast::StmtAugAssign { value, .. }) = parent - { - if matches!( - value.as_ref(), - Expr::Tuple(_) | Expr::List(_) | Expr::Set(_) - ) { - let mut diagnostic = - Diagnostic::new(UnnecessaryListCast, *list_range); - diagnostic.set_fix(remove_cast(*list_range, *iterable_range)); - checker.diagnostics.push(diagnostic); - } - } - } - } + let Some(value) = find_assigned_value(id, checker.semantic()) else { + return; + }; + if matches!(value, Expr::Tuple(_) | Expr::List(_) | Expr::Set(_)) { + let mut diagnostic = Diagnostic::new(UnnecessaryListCast, *list_range); + diagnostic.set_fix(remove_cast(*list_range, *iterable_range)); + checker.diagnostics.push(diagnostic); } } _ => {} diff --git a/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF101_PERF101.py.snap b/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF101_PERF101.py.snap index 1b4b456af3f15..11dafc4dd2565 100644 --- a/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF101_PERF101.py.snap +++ b/crates/ruff_linter/src/rules/perflint/snapshots/ruff_linter__rules__perflint__tests__PERF101_PERF101.py.snap @@ -201,4 +201,22 @@ PERF101.py:57:10: PERF101 [*] Do not cast an iterable to `list` before iterating 59 59 | other_list.append(i + 1) 60 60 | +PERF101.py:69:10: PERF101 [*] Do not cast an iterable to `list` before iterating over it + | +67 | x, y, nested_tuple = (1, 2, (3, 4, 5)) +68 | +69 | for i in list(nested_tuple): # PERF101 + | ^^^^^^^^^^^^^^^^^^ PERF101 +70 | pass + | + = help: Remove `list()` cast + +ℹ Safe fix +66 66 | +67 67 | x, y, nested_tuple = (1, 2, (3, 4, 5)) +68 68 | +69 |-for i in list(nested_tuple): # PERF101 + 69 |+for i in nested_tuple: # PERF101 +70 70 | pass + diff --git a/crates/ruff_python_semantic/src/analyze/typing.rs b/crates/ruff_python_semantic/src/analyze/typing.rs index bd18f70ba8aae..4ff2e27e3221c 100644 --- a/crates/ruff_python_semantic/src/analyze/typing.rs +++ b/crates/ruff_python_semantic/src/analyze/typing.rs @@ -568,3 +568,108 @@ pub fn resolve_assignment<'a>( _ => None, } } + +/// Find the assigned [`Expr`] for a given symbol, if any. +/// +/// For example given: +/// ```python +/// foo = 42 +/// (bar, bla) = 1, "str" +/// ``` +/// +/// This function will return a `NumberLiteral` with value `Int(42)` when called with `foo` and a +/// `StringLiteral` with value `"str"` when called with `bla`. +pub fn find_assigned_value<'a>(symbol: &str, semantic: &'a SemanticModel<'a>) -> Option<&'a Expr> { + let binding_id = semantic.lookup_symbol(symbol)?; + let binding = semantic.binding(binding_id); + if binding.kind.is_assignment() || binding.kind.is_named_expr_assignment() { + let parent_id = binding.source?; + let parent = semantic.statement(parent_id); + match parent { + Stmt::Assign(ast::StmtAssign { value, targets, .. }) => match value.as_ref() { + Expr::Tuple(ast::ExprTuple { elts, .. }) + | Expr::List(ast::ExprList { elts, .. }) => { + if let Some(target) = targets.iter().find(|target| defines(symbol, target)) { + return match target { + Expr::Tuple(ast::ExprTuple { + elts: target_elts, .. + }) + | Expr::List(ast::ExprList { + elts: target_elts, .. + }) + | Expr::Set(ast::ExprSet { + elts: target_elts, .. + }) => get_value_by_id(symbol, target_elts, elts), + _ => Some(value.as_ref()), + }; + } + } + _ => return Some(value.as_ref()), + }, + Stmt::AnnAssign(ast::StmtAnnAssign { + value: Some(value), .. + }) => { + return Some(value.as_ref()); + } + Stmt::AugAssign(_) => return None, + _ => return None, + } + } + None +} + +/// Returns `true` if the [`Expr`] defines the symbol. +fn defines(symbol: &str, expr: &Expr) -> bool { + match expr { + Expr::Name(ast::ExprName { id, .. }) => id == symbol, + Expr::Tuple(ast::ExprTuple { elts, .. }) + | Expr::List(ast::ExprList { elts, .. }) + | Expr::Set(ast::ExprSet { elts, .. }) => elts.iter().any(|elt| defines(symbol, elt)), + _ => false, + } +} + +fn get_value_by_id<'a>( + target_id: &str, + targets: &'a [Expr], + values: &'a [Expr], +) -> Option<&'a Expr> { + for (target, value) in targets.iter().zip(values.iter()) { + match target { + Expr::Tuple(ast::ExprTuple { + elts: target_elts, .. + }) + | Expr::List(ast::ExprList { + elts: target_elts, .. + }) + | Expr::Set(ast::ExprSet { + elts: target_elts, .. + }) => { + // Collection types can be mismatched like in: (a, b, [c, d]) = [1, 2, {3, 4}] + match value { + Expr::Tuple(ast::ExprTuple { + elts: value_elts, .. + }) + | Expr::List(ast::ExprList { + elts: value_elts, .. + }) + | Expr::Set(ast::ExprSet { + elts: value_elts, .. + }) => { + if let Some(result) = get_value_by_id(target_id, target_elts, value_elts) { + return Some(result); + } + } + _ => (), + }; + } + Expr::Name(ast::ExprName { id, .. }) => { + if *id == target_id { + return Some(value); + } + } + _ => (), + } + } + None +} From 4d2ee5bf986c62e47ac5c70a9ce145e4ef8c0138 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 12 Dec 2023 20:07:33 -0500 Subject: [PATCH 175/197] Add named expression handling to `find_assigned_value` (#9109) --- .../test/fixtures/flake8_trio/TRIO115.py | 13 +- ...lake8_trio__tests__TRIO115_TRIO115.py.snap | 141 +++++++++--------- .../src/analyze/typing.rs | 82 ++++++---- crates/ruff_python_semantic/src/model.rs | 17 +++ 4 files changed, 147 insertions(+), 106 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO115.py b/crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO115.py index d7466beb0f5d3..764b5c1d6e9f5 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO115.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO115.py @@ -29,8 +29,8 @@ async def func(): trio.sleep(e) # TRIO115 m_x, m_y = 0 - trio.sleep(m_y) # TRIO115 - trio.sleep(m_x) # TRIO115 + trio.sleep(m_y) # OK + trio.sleep(m_x) # OK m_a = m_b = 0 trio.sleep(m_a) # TRIO115 @@ -43,6 +43,8 @@ async def func(): def func(): + import trio + trio.run(trio.sleep(0)) # TRIO115 @@ -55,3 +57,10 @@ def func(): async def func(): await sleep(seconds=0) # TRIO115 + + +def func(): + import trio + + if (walrus := 0) == 0: + trio.sleep(walrus) # TRIO115 diff --git a/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap b/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap index 1ade9f757bbaa..7710be928504a 100644 --- a/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap +++ b/crates/ruff_linter/src/rules/flake8_trio/snapshots/ruff_linter__rules__flake8_trio__tests__TRIO115_TRIO115.py.snap @@ -143,47 +143,7 @@ TRIO115.py:29:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.s 29 |+ trio.lowlevel.checkpoint() # TRIO115 30 30 | 31 31 | m_x, m_y = 0 -32 32 | trio.sleep(m_y) # TRIO115 - -TRIO115.py:32:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` - | -31 | m_x, m_y = 0 -32 | trio.sleep(m_y) # TRIO115 - | ^^^^^^^^^^^^^^^ TRIO115 -33 | trio.sleep(m_x) # TRIO115 - | - = help: Replace with `trio.lowlevel.checkpoint()` - -ℹ Safe fix -29 29 | trio.sleep(e) # TRIO115 -30 30 | -31 31 | m_x, m_y = 0 -32 |- trio.sleep(m_y) # TRIO115 - 32 |+ trio.lowlevel.checkpoint() # TRIO115 -33 33 | trio.sleep(m_x) # TRIO115 -34 34 | -35 35 | m_a = m_b = 0 - -TRIO115.py:33:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` - | -31 | m_x, m_y = 0 -32 | trio.sleep(m_y) # TRIO115 -33 | trio.sleep(m_x) # TRIO115 - | ^^^^^^^^^^^^^^^ TRIO115 -34 | -35 | m_a = m_b = 0 - | - = help: Replace with `trio.lowlevel.checkpoint()` - -ℹ Safe fix -30 30 | -31 31 | m_x, m_y = 0 -32 32 | trio.sleep(m_y) # TRIO115 -33 |- trio.sleep(m_x) # TRIO115 - 33 |+ trio.lowlevel.checkpoint() # TRIO115 -34 34 | -35 35 | m_a = m_b = 0 -36 36 | trio.sleep(m_a) # TRIO115 +32 32 | trio.sleep(m_y) # OK TRIO115.py:36:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` | @@ -195,7 +155,7 @@ TRIO115.py:36:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.s = help: Replace with `trio.lowlevel.checkpoint()` ℹ Safe fix -33 33 | trio.sleep(m_x) # TRIO115 +33 33 | trio.sleep(m_x) # OK 34 34 | 35 35 | m_a = m_b = 0 36 |- trio.sleep(m_a) # TRIO115 @@ -264,51 +224,88 @@ TRIO115.py:42:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.s 44 44 | 45 45 | def func(): -TRIO115.py:53:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` +TRIO115.py:48:14: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` | -52 | def func(): -53 | sleep(0) # TRIO115 - | ^^^^^^^^ TRIO115 +46 | import trio +47 | +48 | trio.run(trio.sleep(0)) # TRIO115 + | ^^^^^^^^^^^^^ TRIO115 | = help: Replace with `trio.lowlevel.checkpoint()` ℹ Safe fix -46 46 | trio.run(trio.sleep(0)) # TRIO115 +45 45 | def func(): +46 46 | import trio 47 47 | -48 48 | -49 |-from trio import Event, sleep - 49 |+from trio import Event, sleep, lowlevel +48 |- trio.run(trio.sleep(0)) # TRIO115 + 48 |+ trio.run(trio.lowlevel.checkpoint()) # TRIO115 +49 49 | +50 50 | +51 51 | from trio import Event, sleep + +TRIO115.py:55:5: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` + | +54 | def func(): +55 | sleep(0) # TRIO115 + | ^^^^^^^^ TRIO115 + | + = help: Replace with `trio.lowlevel.checkpoint()` + +ℹ Safe fix +48 48 | trio.run(trio.sleep(0)) # TRIO115 +49 49 | 50 50 | -51 51 | -52 52 | def func(): -53 |- sleep(0) # TRIO115 - 53 |+ lowlevel.checkpoint() # TRIO115 -54 54 | -55 55 | -56 56 | async def func(): +51 |-from trio import Event, sleep + 51 |+from trio import Event, sleep, lowlevel +52 52 | +53 53 | +54 54 | def func(): +55 |- sleep(0) # TRIO115 + 55 |+ lowlevel.checkpoint() # TRIO115 +56 56 | +57 57 | +58 58 | async def func(): -TRIO115.py:57:11: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` +TRIO115.py:59:11: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` | -56 | async def func(): -57 | await sleep(seconds=0) # TRIO115 +58 | async def func(): +59 | await sleep(seconds=0) # TRIO115 | ^^^^^^^^^^^^^^^^ TRIO115 | = help: Replace with `trio.lowlevel.checkpoint()` ℹ Safe fix -46 46 | trio.run(trio.sleep(0)) # TRIO115 -47 47 | -48 48 | -49 |-from trio import Event, sleep - 49 |+from trio import Event, sleep, lowlevel +48 48 | trio.run(trio.sleep(0)) # TRIO115 +49 49 | 50 50 | -51 51 | -52 52 | def func(): +51 |-from trio import Event, sleep + 51 |+from trio import Event, sleep, lowlevel +52 52 | +53 53 | +54 54 | def func(): -------------------------------------------------------------------------------- -54 54 | -55 55 | -56 56 | async def func(): -57 |- await sleep(seconds=0) # TRIO115 - 57 |+ await lowlevel.checkpoint() # TRIO115 +56 56 | +57 57 | +58 58 | async def func(): +59 |- await sleep(seconds=0) # TRIO115 + 59 |+ await lowlevel.checkpoint() # TRIO115 +60 60 | +61 61 | +62 62 | def func(): + +TRIO115.py:66:9: TRIO115 [*] Use `trio.lowlevel.checkpoint()` instead of `trio.sleep(0)` + | +65 | if (walrus := 0) == 0: +66 | trio.sleep(walrus) # TRIO115 + | ^^^^^^^^^^^^^^^^^^ TRIO115 + | + = help: Replace with `trio.lowlevel.checkpoint()` + +ℹ Safe fix +63 63 | import trio +64 64 | +65 65 | if (walrus := 0) == 0: +66 |- trio.sleep(walrus) # TRIO115 + 66 |+ trio.lowlevel.checkpoint() # TRIO115 diff --git a/crates/ruff_python_semantic/src/analyze/typing.rs b/crates/ruff_python_semantic/src/analyze/typing.rs index 4ff2e27e3221c..2dd7f1003e398 100644 --- a/crates/ruff_python_semantic/src/analyze/typing.rs +++ b/crates/ruff_python_semantic/src/analyze/typing.rs @@ -582,42 +582,64 @@ pub fn resolve_assignment<'a>( pub fn find_assigned_value<'a>(symbol: &str, semantic: &'a SemanticModel<'a>) -> Option<&'a Expr> { let binding_id = semantic.lookup_symbol(symbol)?; let binding = semantic.binding(binding_id); - if binding.kind.is_assignment() || binding.kind.is_named_expr_assignment() { - let parent_id = binding.source?; - let parent = semantic.statement(parent_id); - match parent { - Stmt::Assign(ast::StmtAssign { value, targets, .. }) => match value.as_ref() { - Expr::Tuple(ast::ExprTuple { elts, .. }) - | Expr::List(ast::ExprList { elts, .. }) => { + match binding.kind { + // Ex) `x := 1` + BindingKind::NamedExprAssignment => { + let parent_id = binding.source?; + let parent = semantic + .expressions(parent_id) + .find_map(|expr| expr.as_named_expr_expr()); + if let Some(ast::ExprNamedExpr { target, value, .. }) = parent { + return match_value(symbol, target.as_ref(), value.as_ref()); + } + } + // Ex) `x = 1` + BindingKind::Assignment => { + let parent_id = binding.source?; + let parent = semantic.statement(parent_id); + match parent { + Stmt::Assign(ast::StmtAssign { value, targets, .. }) => { if let Some(target) = targets.iter().find(|target| defines(symbol, target)) { - return match target { - Expr::Tuple(ast::ExprTuple { - elts: target_elts, .. - }) - | Expr::List(ast::ExprList { - elts: target_elts, .. - }) - | Expr::Set(ast::ExprSet { - elts: target_elts, .. - }) => get_value_by_id(symbol, target_elts, elts), - _ => Some(value.as_ref()), - }; + return match_value(symbol, target, value.as_ref()); } } - _ => return Some(value.as_ref()), - }, - Stmt::AnnAssign(ast::StmtAnnAssign { - value: Some(value), .. - }) => { - return Some(value.as_ref()); + Stmt::AnnAssign(ast::StmtAnnAssign { + value: Some(value), + target, + .. + }) => { + return match_value(symbol, target, value.as_ref()); + } + _ => {} } - Stmt::AugAssign(_) => return None, - _ => return None, } + _ => {} } None } +/// Given a target and value, find the value that's assigned to the given symbol. +fn match_value<'a>(symbol: &str, target: &Expr, value: &'a Expr) -> Option<&'a Expr> { + match target { + Expr::Name(ast::ExprName { id, .. }) if id.as_str() == symbol => Some(value), + Expr::Tuple(ast::ExprTuple { elts, .. }) | Expr::List(ast::ExprList { elts, .. }) => { + match value { + Expr::Tuple(ast::ExprTuple { + elts: value_elts, .. + }) + | Expr::List(ast::ExprList { + elts: value_elts, .. + }) + | Expr::Set(ast::ExprSet { + elts: value_elts, .. + }) => get_value_by_id(symbol, elts, value_elts), + _ => None, + } + } + _ => None, + } +} + /// Returns `true` if the [`Expr`] defines the symbol. fn defines(symbol: &str, expr: &Expr) -> bool { match expr { @@ -629,11 +651,7 @@ fn defines(symbol: &str, expr: &Expr) -> bool { } } -fn get_value_by_id<'a>( - target_id: &str, - targets: &'a [Expr], - values: &'a [Expr], -) -> Option<&'a Expr> { +fn get_value_by_id<'a>(target_id: &str, targets: &[Expr], values: &'a [Expr]) -> Option<&'a Expr> { for (target, value) in targets.iter().zip(values.iter()) { match target { Expr::Tuple(ast::ExprTuple { diff --git a/crates/ruff_python_semantic/src/model.rs b/crates/ruff_python_semantic/src/model.rs index 9cb3cebaa07ff..82221f0f85dc8 100644 --- a/crates/ruff_python_semantic/src/model.rs +++ b/crates/ruff_python_semantic/src/model.rs @@ -1005,6 +1005,23 @@ impl<'a> SemanticModel<'a> { .nth(1) } + /// Return the [`Expr`] corresponding to the given [`NodeId`]. + #[inline] + pub fn expression(&self, node_id: NodeId) -> &'a Expr { + self.nodes + .ancestor_ids(node_id) + .find_map(|id| self.nodes[id].as_expression()) + .expect("No expression found") + } + + /// Returns an [`Iterator`] over the expressions, starting from the given [`NodeId`]. + /// through to any parents. + pub fn expressions(&self, node_id: NodeId) -> impl Iterator + '_ { + self.nodes + .ancestor_ids(node_id) + .filter_map(move |id| self.nodes[id].as_expression()) + } + /// Set the [`Globals`] for the current [`Scope`]. pub fn set_globals(&mut self, globals: Globals<'a>) { // If any global bindings don't already exist in the global scope, add them. From 1a65e544c5896634a00c05bc463d0e60ec737001 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 12 Dec 2023 22:12:38 -0500 Subject: [PATCH 176/197] Allow `flake8-type-checking` rules to automatically quote runtime-evaluated references (#6001) ## Summary This allows us to fix usages like: ```python from pandas import DataFrame def baz() -> DataFrame: ... ``` By quoting the `DataFrame` in `-> DataFrame`. Without quotes, moving `from pandas import DataFrame` into an `if TYPE_CHECKING:` block will fail at runtime, since Python tries to evaluate the annotation to add it to the function's `__annotations__`. Unfortunately, this does require us to split our "annotation kind" flags into three categories, rather than two: - `typing-only`: The annotation is only evaluated at type-checking-time. - `runtime-evaluated`: Python will evaluate the annotation at runtime (like above) -- but we're willing to quote it. - `runtime-required`: Python will evaluate the annotation at runtime (like above), and some library (like Pydantic) needs it to be available at runtime, so we _can't_ quote it. This functionality is gated behind a setting (`flake8-type-checking.quote-annotations`). Closes https://github.com/astral-sh/ruff/issues/5559. --- .../fixtures/flake8_type_checking/quote.py | 67 +++++ .../checkers/ast/analyze/deferred_scopes.rs | 1 + .../src/checkers/ast/annotation.rs | 66 +++++ crates/ruff_linter/src/checkers/ast/mod.rs | 68 ++--- .../src/rules/flake8_type_checking/helpers.rs | 120 +++++++- .../src/rules/flake8_type_checking/imports.rs | 22 ++ .../src/rules/flake8_type_checking/mod.rs | 27 +- .../runtime_import_in_type_checking_block.rs | 258 +++++++++++++----- .../rules/typing_only_runtime_import.rs | 86 +++--- .../rules/flake8_type_checking/settings.rs | 12 +- ...mport-in-type-checking-block_quote.py.snap | 22 ++ ...ping-only-third-party-import_quote.py.snap | 199 ++++++++++++++ ...mport-in-type-checking-block_quote.py.snap | 29 ++ ...ping-only-third-party-import_quote.py.snap | 4 + crates/ruff_python_semantic/src/model.rs | 142 +++++++--- crates/ruff_python_semantic/src/reference.rs | 54 +++- crates/ruff_workspace/src/options.rs | 56 +++- ruff.schema.json | 7 + 18 files changed, 1033 insertions(+), 207 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_type_checking/quote.py create mode 100644 crates/ruff_linter/src/checkers/ast/annotation.rs create mode 100644 crates/ruff_linter/src/rules/flake8_type_checking/imports.rs create mode 100644 crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_runtime-import-in-type-checking-block_quote.py.snap create mode 100644 crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_typing-only-third-party-import_quote.py.snap create mode 100644 crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__runtime-import-in-type-checking-block_quote.py.snap create mode 100644 crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__typing-only-third-party-import_quote.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/quote.py b/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/quote.py new file mode 100644 index 0000000000000..67332e3010f24 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/quote.py @@ -0,0 +1,67 @@ +def f(): + from pandas import DataFrame + + def baz() -> DataFrame: + ... + + +def f(): + from pandas import DataFrame + + def baz() -> DataFrame[int]: + ... + + +def f(): + from pandas import DataFrame + + def baz() -> DataFrame["int"]: + ... + + +def f(): + import pandas as pd + + def baz() -> pd.DataFrame: + ... + + +def f(): + import pandas as pd + + def baz() -> pd.DataFrame.Extra: + ... + + +def f(): + import pandas as pd + + def baz() -> pd.DataFrame | int: + ... + + + +def f(): + from pandas import DataFrame + + def baz() -> DataFrame(): + ... + + +def f(): + from typing import Literal + + from pandas import DataFrame + + def baz() -> DataFrame[Literal["int"]]: + ... + + +def f(): + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + from pandas import DataFrame + + def func(value: DataFrame): + ... diff --git a/crates/ruff_linter/src/checkers/ast/analyze/deferred_scopes.rs b/crates/ruff_linter/src/checkers/ast/analyze/deferred_scopes.rs index 27c9a6b7c79e2..66d0ad25273e9 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/deferred_scopes.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/deferred_scopes.rs @@ -59,6 +59,7 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) { flake8_type_checking::helpers::is_valid_runtime_import( binding, &checker.semantic, + &checker.settings.flake8_type_checking, ) }) .collect() diff --git a/crates/ruff_linter/src/checkers/ast/annotation.rs b/crates/ruff_linter/src/checkers/ast/annotation.rs new file mode 100644 index 0000000000000..aca5fc6c629ff --- /dev/null +++ b/crates/ruff_linter/src/checkers/ast/annotation.rs @@ -0,0 +1,66 @@ +use ruff_python_semantic::{ScopeKind, SemanticModel}; + +use crate::rules::flake8_type_checking; +use crate::settings::LinterSettings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(super) enum AnnotationContext { + /// Python will evaluate the annotation at runtime, but it's not _required_ and, as such, could + /// be quoted to convert it into a typing-only annotation. + /// + /// For example: + /// ```python + /// from pandas import DataFrame + /// + /// def foo() -> DataFrame: + /// ... + /// ``` + /// + /// Above, Python will evaluate `DataFrame` at runtime in order to add it to `__annotations__`. + RuntimeEvaluated, + /// Python will evaluate the annotation at runtime, and it's required to be available at + /// runtime, as a library (like Pydantic) needs access to it. + RuntimeRequired, + /// The annotation is only evaluated at type-checking time. + TypingOnly, +} + +impl AnnotationContext { + pub(super) fn from_model(semantic: &SemanticModel, settings: &LinterSettings) -> Self { + // If the annotation is in a class scope (e.g., an annotated assignment for a + // class field), and that class is marked as annotation as runtime-required. + if semantic + .current_scope() + .kind + .as_class() + .is_some_and(|class_def| { + flake8_type_checking::helpers::runtime_required_class( + class_def, + &settings.flake8_type_checking.runtime_required_base_classes, + &settings.flake8_type_checking.runtime_required_decorators, + semantic, + ) + }) + { + return Self::RuntimeRequired; + } + + // If `__future__` annotations are enabled, then annotations are never evaluated + // at runtime, so we can treat them as typing-only. + if semantic.future_annotations() { + return Self::TypingOnly; + } + + // Otherwise, if we're in a class or module scope, then the annotation needs to + // be available at runtime. + // See: https://docs.python.org/3/reference/simple_stmts.html#annotated-assignment-statements + if matches!( + semantic.current_scope().kind, + ScopeKind::Class(_) | ScopeKind::Module + ) { + return Self::RuntimeEvaluated; + } + + Self::TypingOnly + } +} diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 5d525550f5375..1c510f1cbb8d9 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -58,6 +58,7 @@ use ruff_python_semantic::{ use ruff_python_stdlib::builtins::{IPYTHON_BUILTINS, MAGIC_GLOBALS, PYTHON_BUILTINS}; use ruff_source_file::Locator; +use crate::checkers::ast::annotation::AnnotationContext; use crate::checkers::ast::deferred::Deferred; use crate::docstrings::extraction::ExtractionTarget; use crate::importer::Importer; @@ -68,6 +69,7 @@ use crate::settings::{flags, LinterSettings}; use crate::{docstrings, noqa}; mod analyze; +mod annotation; mod deferred; pub(crate) struct Checker<'a> { @@ -515,8 +517,10 @@ where .chain(¶meters.kwonlyargs) { if let Some(expr) = ¶meter_with_default.parameter.annotation { - if runtime_annotation || singledispatch { - self.visit_runtime_annotation(expr); + if singledispatch { + self.visit_runtime_required_annotation(expr); + } else if runtime_annotation { + self.visit_runtime_evaluated_annotation(expr); } else { self.visit_annotation(expr); }; @@ -529,7 +533,7 @@ where if let Some(arg) = ¶meters.vararg { if let Some(expr) = &arg.annotation { if runtime_annotation { - self.visit_runtime_annotation(expr); + self.visit_runtime_evaluated_annotation(expr); } else { self.visit_annotation(expr); }; @@ -538,7 +542,7 @@ where if let Some(arg) = ¶meters.kwarg { if let Some(expr) = &arg.annotation { if runtime_annotation { - self.visit_runtime_annotation(expr); + self.visit_runtime_evaluated_annotation(expr); } else { self.visit_annotation(expr); }; @@ -546,7 +550,7 @@ where } for expr in returns { if runtime_annotation { - self.visit_runtime_annotation(expr); + self.visit_runtime_evaluated_annotation(expr); } else { self.visit_annotation(expr); }; @@ -677,40 +681,16 @@ where value, .. }) => { - // If we're in a class or module scope, then the annotation needs to be - // available at runtime. - // See: https://docs.python.org/3/reference/simple_stmts.html#annotated-assignment-statements - let runtime_annotation = if self.semantic.future_annotations() { - self.semantic - .current_scope() - .kind - .as_class() - .is_some_and(|class_def| { - flake8_type_checking::helpers::runtime_evaluated_class( - class_def, - &self - .settings - .flake8_type_checking - .runtime_evaluated_base_classes, - &self - .settings - .flake8_type_checking - .runtime_evaluated_decorators, - &self.semantic, - ) - }) - } else { - matches!( - self.semantic.current_scope().kind, - ScopeKind::Class(_) | ScopeKind::Module - ) - }; - - if runtime_annotation { - self.visit_runtime_annotation(annotation); - } else { - self.visit_annotation(annotation); + match AnnotationContext::from_model(&self.semantic, self.settings) { + AnnotationContext::RuntimeRequired => { + self.visit_runtime_required_annotation(annotation); + } + AnnotationContext::RuntimeEvaluated => { + self.visit_runtime_evaluated_annotation(annotation); + } + AnnotationContext::TypingOnly => self.visit_annotation(annotation), } + if let Some(expr) = value { if self.semantic.match_typing_expr(annotation, "TypeAlias") { self.visit_type_definition(expr); @@ -1527,10 +1507,18 @@ impl<'a> Checker<'a> { self.semantic.flags = snapshot; } + /// Visit an [`Expr`], and treat it as a runtime-evaluated type annotation. + fn visit_runtime_evaluated_annotation(&mut self, expr: &'a Expr) { + let snapshot = self.semantic.flags; + self.semantic.flags |= SemanticModelFlags::RUNTIME_EVALUATED_ANNOTATION; + self.visit_type_definition(expr); + self.semantic.flags = snapshot; + } + /// Visit an [`Expr`], and treat it as a runtime-required type annotation. - fn visit_runtime_annotation(&mut self, expr: &'a Expr) { + fn visit_runtime_required_annotation(&mut self, expr: &'a Expr) { let snapshot = self.semantic.flags; - self.semantic.flags |= SemanticModelFlags::RUNTIME_ANNOTATION; + self.semantic.flags |= SemanticModelFlags::RUNTIME_REQUIRED_ANNOTATION; self.visit_type_definition(expr); self.semantic.flags = snapshot; } diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs b/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs index 0a51e151f4703..1fc4ade6fda9a 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs @@ -1,10 +1,35 @@ +use anyhow::Result; +use rustc_hash::FxHashSet; + +use ruff_diagnostics::Edit; use ruff_python_ast::call_path::from_qualified_name; use ruff_python_ast::helpers::{map_callable, map_subscript}; use ruff_python_ast::{self as ast, Expr}; -use ruff_python_semantic::{Binding, BindingId, BindingKind, SemanticModel}; -use rustc_hash::FxHashSet; +use ruff_python_codegen::Stylist; +use ruff_python_semantic::{ + Binding, BindingId, BindingKind, NodeId, ResolvedReference, SemanticModel, +}; +use ruff_source_file::Locator; +use ruff_text_size::Ranged; + +use crate::rules::flake8_type_checking::settings::Settings; -pub(crate) fn is_valid_runtime_import(binding: &Binding, semantic: &SemanticModel) -> bool { +/// Returns `true` if the [`ResolvedReference`] is in a typing-only context _or_ a runtime-evaluated +/// context (with quoting enabled). +pub(crate) fn is_typing_reference(reference: &ResolvedReference, settings: &Settings) -> bool { + reference.in_type_checking_block() + || reference.in_typing_only_annotation() + || reference.in_complex_string_type_definition() + || reference.in_simple_string_type_definition() + || (settings.quote_annotations && reference.in_runtime_evaluated_annotation()) +} + +/// Returns `true` if the [`Binding`] represents a runtime-required import. +pub(crate) fn is_valid_runtime_import( + binding: &Binding, + semantic: &SemanticModel, + settings: &Settings, +) -> bool { if matches!( binding.kind, BindingKind::Import(..) | BindingKind::FromImport(..) | BindingKind::SubmoduleImport(..) @@ -12,28 +37,29 @@ pub(crate) fn is_valid_runtime_import(binding: &Binding, semantic: &SemanticMode binding.context.is_runtime() && binding .references() - .any(|reference_id| semantic.reference(reference_id).context().is_runtime()) + .map(|reference_id| semantic.reference(reference_id)) + .any(|reference| !is_typing_reference(reference, settings)) } else { false } } -pub(crate) fn runtime_evaluated_class( +pub(crate) fn runtime_required_class( class_def: &ast::StmtClassDef, base_classes: &[String], decorators: &[String], semantic: &SemanticModel, ) -> bool { - if runtime_evaluated_base_class(class_def, base_classes, semantic) { + if runtime_required_base_class(class_def, base_classes, semantic) { return true; } - if runtime_evaluated_decorators(class_def, decorators, semantic) { + if runtime_required_decorators(class_def, decorators, semantic) { return true; } false } -fn runtime_evaluated_base_class( +fn runtime_required_base_class( class_def: &ast::StmtClassDef, base_classes: &[String], semantic: &SemanticModel, @@ -45,7 +71,7 @@ fn runtime_evaluated_base_class( seen: &mut FxHashSet, ) -> bool { class_def.bases().iter().any(|expr| { - // If the base class is itself runtime-evaluated, then this is too. + // If the base class is itself runtime-required, then this is too. // Ex) `class Foo(BaseModel): ...` if semantic .resolve_call_path(map_subscript(expr)) @@ -58,7 +84,7 @@ fn runtime_evaluated_base_class( return true; } - // If the base class extends a runtime-evaluated class, then this does too. + // If the base class extends a runtime-required class, then this does too. // Ex) `class Bar(BaseModel): ...; class Foo(Bar): ...` if let Some(id) = semantic.lookup_attribute(map_subscript(expr)) { if seen.insert(id) { @@ -86,7 +112,7 @@ fn runtime_evaluated_base_class( inner(class_def, base_classes, semantic, &mut FxHashSet::default()) } -fn runtime_evaluated_decorators( +fn runtime_required_decorators( class_def: &ast::StmtClassDef, decorators: &[String], semantic: &SemanticModel, @@ -174,3 +200,75 @@ pub(crate) fn is_singledispatch_implementation( is_singledispatch_interface(function_def, semantic) }) } + +/// Wrap a type annotation in quotes. +/// +/// This requires more than just wrapping the reference itself in quotes. For example: +/// - When quoting `Series` in `Series[pd.Timestamp]`, we want `"Series[pd.Timestamp]"`. +/// - When quoting `kubernetes` in `kubernetes.SecurityContext`, we want `"kubernetes.SecurityContext"`. +/// - When quoting `Series` in `Series["pd.Timestamp"]`, we want `"Series[pd.Timestamp]"`. (This is currently unsupported.) +/// - When quoting `Series` in `Series[Literal["pd.Timestamp"]]`, we want `"Series[Literal['pd.Timestamp']]"`. (This is currently unsupported.) +/// +/// In general, when expanding a component of a call chain, we want to quote the entire call chain. +pub(crate) fn quote_annotation( + node_id: NodeId, + semantic: &SemanticModel, + locator: &Locator, + stylist: &Stylist, +) -> Result { + let expr = semantic.expression(node_id).expect("Expression not found"); + if let Some(parent_id) = semantic.parent_expression_id(node_id) { + match semantic.expression(parent_id) { + Some(Expr::Subscript(parent)) => { + if expr == parent.value.as_ref() { + // If we're quoting the value of a subscript, we need to quote the entire + // expression. For example, when quoting `DataFrame` in `DataFrame[int]`, we + // should generate `"DataFrame[int]"`. + return quote_annotation(parent_id, semantic, locator, stylist); + } + } + Some(Expr::Attribute(parent)) => { + if expr == parent.value.as_ref() { + // If we're quoting the value of an attribute, we need to quote the entire + // expression. For example, when quoting `DataFrame` in `pd.DataFrame`, we + // should generate `"pd.DataFrame"`. + return quote_annotation(parent_id, semantic, locator, stylist); + } + } + Some(Expr::Call(parent)) => { + if expr == parent.func.as_ref() { + // If we're quoting the function of a call, we need to quote the entire + // expression. For example, when quoting `DataFrame` in `DataFrame()`, we + // should generate `"DataFrame()"`. + return quote_annotation(parent_id, semantic, locator, stylist); + } + } + Some(Expr::BinOp(parent)) => { + if parent.op.is_bit_or() { + // If we're quoting the left or right side of a binary operation, we need to + // quote the entire expression. For example, when quoting `DataFrame` in + // `DataFrame | Series`, we should generate `"DataFrame | Series"`. + return quote_annotation(parent_id, semantic, locator, stylist); + } + } + _ => {} + } + } + + let annotation = locator.slice(expr); + + // If the annotation already contains a quote, avoid attempting to re-quote it. For example: + // ```python + // from typing import Literal + // + // Set[Literal["Foo"]] + // ``` + if annotation.contains('\'') || annotation.contains('"') { + return Err(anyhow::anyhow!("Annotation already contains a quote")); + } + + // If we're quoting a name, we need to quote the entire expression. + let quote = stylist.quote(); + let annotation = format!("{quote}{annotation}{quote}"); + Ok(Edit::range_replacement(annotation, expr.range())) +} diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/imports.rs b/crates/ruff_linter/src/rules/flake8_type_checking/imports.rs new file mode 100644 index 0000000000000..92c65cf275e1c --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_type_checking/imports.rs @@ -0,0 +1,22 @@ +use ruff_python_semantic::{AnyImport, Binding, ResolvedReferenceId}; +use ruff_text_size::{Ranged, TextRange}; + +/// An import with its surrounding context. +pub(crate) struct ImportBinding<'a> { + /// The qualified name of the import (e.g., `typing.List` for `from typing import List`). + pub(crate) import: AnyImport<'a>, + /// The binding for the imported symbol. + pub(crate) binding: &'a Binding<'a>, + /// The first reference to the imported symbol. + pub(crate) reference_id: ResolvedReferenceId, + /// The trimmed range of the import (e.g., `List` in `from typing import List`). + pub(crate) range: TextRange, + /// The range of the import's parent statement. + pub(crate) parent_range: Option, +} + +impl Ranged for ImportBinding<'_> { + fn range(&self) -> TextRange { + self.range + } +} diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/mod.rs b/crates/ruff_linter/src/rules/flake8_type_checking/mod.rs index 82b24755f4277..5e5a05cb6ff0e 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/mod.rs @@ -1,5 +1,6 @@ //! Rules from [flake8-type-checking](https://pypi.org/project/flake8-type-checking/). pub(crate) mod helpers; +mod imports; pub(crate) mod rules; pub mod settings; @@ -33,10 +34,12 @@ mod tests { #[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_7.py"))] #[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_8.py"))] #[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_9.py"))] + #[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("quote.py"))] #[test_case(Rule::TypingOnlyFirstPartyImport, Path::new("TCH001.py"))] #[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("TCH003.py"))] #[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("snapshot.py"))] #[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("TCH002.py"))] + #[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("quote.py"))] #[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("singledispatch.py"))] #[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("strict.py"))] #[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("typing_modules_1.py"))] @@ -51,6 +54,24 @@ mod tests { Ok(()) } + #[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("quote.py"))] + #[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("quote.py"))] + fn quote(rule_code: Rule, path: &Path) -> Result<()> { + let snapshot = format!("quote_{}_{}", rule_code.as_ref(), path.to_string_lossy()); + let diagnostics = test_path( + Path::new("flake8_type_checking").join(path).as_path(), + &settings::LinterSettings { + flake8_type_checking: super::settings::Settings { + quote_annotations: true, + ..Default::default() + }, + ..settings::LinterSettings::for_rule(rule_code) + }, + )?; + assert_messages!(snapshot, diagnostics); + Ok(()) + } + #[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("strict.py"))] fn strict(rule_code: Rule, path: &Path) -> Result<()> { let diagnostics = test_path( @@ -109,7 +130,7 @@ mod tests { Path::new("flake8_type_checking").join(path).as_path(), &settings::LinterSettings { flake8_type_checking: super::settings::Settings { - runtime_evaluated_base_classes: vec![ + runtime_required_base_classes: vec![ "pydantic.BaseModel".to_string(), "sqlalchemy.orm.DeclarativeBase".to_string(), ], @@ -140,7 +161,7 @@ mod tests { Path::new("flake8_type_checking").join(path).as_path(), &settings::LinterSettings { flake8_type_checking: super::settings::Settings { - runtime_evaluated_decorators: vec![ + runtime_required_decorators: vec![ "attrs.define".to_string(), "attrs.frozen".to_string(), ], @@ -165,7 +186,7 @@ mod tests { Path::new("flake8_type_checking").join(path).as_path(), &settings::LinterSettings { flake8_type_checking: super::settings::Settings { - runtime_evaluated_base_classes: vec!["module.direct.MyBaseClass".to_string()], + runtime_required_base_classes: vec!["module.direct.MyBaseClass".to_string()], ..Default::default() }, ..settings::LinterSettings::for_rule(rule_code) diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs b/crates/ruff_linter/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs index dea0f4007e0cd..5eee0365e12fa 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs @@ -5,13 +5,15 @@ use rustc_hash::FxHashMap; use ruff_diagnostics::{Diagnostic, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_semantic::{AnyImport, Imported, NodeId, ResolvedReferenceId, Scope}; -use ruff_text_size::{Ranged, TextRange}; +use ruff_python_semantic::{Imported, NodeId, Scope}; +use ruff_text_size::Ranged; use crate::checkers::ast::Checker; use crate::codes::Rule; use crate::fix; use crate::importer::ImportedMembers; +use crate::rules::flake8_type_checking::helpers::quote_annotation; +use crate::rules::flake8_type_checking::imports::ImportBinding; /// ## What it does /// Checks for runtime imports defined in a type-checking block. @@ -20,6 +22,10 @@ use crate::importer::ImportedMembers; /// The type-checking block is not executed at runtime, so the import will not /// be available at runtime. /// +/// If [`flake8-type-checking.quote-annotations`] is set to `true`, +/// annotations will be wrapped in quotes if doing so would enable the +/// corresponding import to remain in the type-checking block. +/// /// ## Example /// ```python /// from typing import TYPE_CHECKING @@ -41,11 +47,15 @@ use crate::importer::ImportedMembers; /// foo.bar() /// ``` /// +/// ## Options +/// - `flake8-type-checking.quote-annotations` +/// /// ## References /// - [PEP 535](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking) #[violation] pub struct RuntimeImportInTypeCheckingBlock { qualified_name: String, + strategy: Strategy, } impl Violation for RuntimeImportInTypeCheckingBlock { @@ -53,17 +63,39 @@ impl Violation for RuntimeImportInTypeCheckingBlock { #[derive_message_formats] fn message(&self) -> String { - let RuntimeImportInTypeCheckingBlock { qualified_name } = self; - format!( - "Move import `{qualified_name}` out of type-checking block. Import is used for more than type hinting." - ) + let Self { + qualified_name, + strategy, + } = self; + match strategy { + Strategy::MoveImport => format!( + "Move import `{qualified_name}` out of type-checking block. Import is used for more than type hinting." + ), + Strategy::QuoteUsages => format!( + "Quote references to `{qualified_name}`. Import is in a type-checking block." + ), + } } fn fix_title(&self) -> Option { - Some("Move out of type-checking block".to_string()) + let Self { strategy, .. } = self; + match strategy { + Strategy::MoveImport => Some("Move out of type-checking block".to_string()), + Strategy::QuoteUsages => Some("Quote references".to_string()), + } } } +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +enum Action { + /// The import should be moved out of the type-checking block. + Move, + /// All usages of the import should be wrapped in quotes. + Quote, + /// The import should be ignored. + Ignore, +} + /// TCH004 pub(crate) fn runtime_import_in_type_checking_block( checker: &Checker, @@ -71,8 +103,7 @@ pub(crate) fn runtime_import_in_type_checking_block( diagnostics: &mut Vec, ) { // Collect all runtime imports by statement. - let mut errors_by_statement: FxHashMap> = FxHashMap::default(); - let mut ignores_by_statement: FxHashMap> = FxHashMap::default(); + let mut actions: FxHashMap<(NodeId, Action), Vec> = FxHashMap::default(); for binding_id in scope.binding_ids() { let binding = checker.semantic().binding(binding_id); @@ -101,6 +132,7 @@ pub(crate) fn runtime_import_in_type_checking_block( let import = ImportBinding { import, reference_id, + binding, range: binding.range(), parent_range: binding.parent_range(checker.semantic()), }; @@ -113,86 +145,153 @@ pub(crate) fn runtime_import_in_type_checking_block( ) }) { - ignores_by_statement - .entry(node_id) + actions + .entry((node_id, Action::Ignore)) .or_default() .push(import); } else { - errors_by_statement.entry(node_id).or_default().push(import); + // Determine whether the member should be fixed by moving the import out of the + // type-checking block, or by quoting its references. + if checker.settings.flake8_type_checking.quote_annotations + && binding.references().all(|reference_id| { + let reference = checker.semantic().reference(reference_id); + reference.context().is_typing() + || reference.in_runtime_evaluated_annotation() + }) + { + actions + .entry((node_id, Action::Quote)) + .or_default() + .push(import); + } else { + actions + .entry((node_id, Action::Move)) + .or_default() + .push(import); + } } } } - // Generate a diagnostic for every import, but share a fix across all imports within the same - // statement (excluding those that are ignored). - for (node_id, imports) in errors_by_statement { - let fix = fix_imports(checker, node_id, &imports).ok(); - - for ImportBinding { - import, - range, - parent_range, - .. - } in imports - { - let mut diagnostic = Diagnostic::new( - RuntimeImportInTypeCheckingBlock { - qualified_name: import.qualified_name(), - }, - range, - ); - if let Some(range) = parent_range { - diagnostic.set_parent(range.start()); + for ((node_id, action), imports) in actions { + match action { + // Generate a diagnostic for every import, but share a fix across all imports within the same + // statement (excluding those that are ignored). + Action::Move => { + let fix = move_imports(checker, node_id, &imports).ok(); + + for ImportBinding { + import, + range, + parent_range, + .. + } in imports + { + let mut diagnostic = Diagnostic::new( + RuntimeImportInTypeCheckingBlock { + qualified_name: import.qualified_name(), + strategy: Strategy::MoveImport, + }, + range, + ); + if let Some(range) = parent_range { + diagnostic.set_parent(range.start()); + } + if let Some(fix) = fix.as_ref() { + diagnostic.set_fix(fix.clone()); + } + diagnostics.push(diagnostic); + } } - if let Some(fix) = fix.as_ref() { - diagnostic.set_fix(fix.clone()); + + // Generate a diagnostic for every import, but share a fix across all imports within the same + // statement (excluding those that are ignored). + Action::Quote => { + let fix = quote_imports(checker, node_id, &imports).ok(); + + for ImportBinding { + import, + range, + parent_range, + .. + } in imports + { + let mut diagnostic = Diagnostic::new( + RuntimeImportInTypeCheckingBlock { + qualified_name: import.qualified_name(), + strategy: Strategy::QuoteUsages, + }, + range, + ); + if let Some(range) = parent_range { + diagnostic.set_parent(range.start()); + } + if let Some(fix) = fix.as_ref() { + diagnostic.set_fix(fix.clone()); + } + diagnostics.push(diagnostic); + } } - diagnostics.push(diagnostic); - } - } - // Separately, generate a diagnostic for every _ignored_ import, to ensure that the - // suppression comments aren't marked as unused. - for ImportBinding { - import, - range, - parent_range, - .. - } in ignores_by_statement.into_values().flatten() - { - let mut diagnostic = Diagnostic::new( - RuntimeImportInTypeCheckingBlock { - qualified_name: import.qualified_name(), - }, - range, - ); - if let Some(range) = parent_range { - diagnostic.set_parent(range.start()); + // Separately, generate a diagnostic for every _ignored_ import, to ensure that the + // suppression comments aren't marked as unused. + Action::Ignore => { + for ImportBinding { + import, + range, + parent_range, + .. + } in imports + { + let mut diagnostic = Diagnostic::new( + RuntimeImportInTypeCheckingBlock { + qualified_name: import.qualified_name(), + strategy: Strategy::MoveImport, + }, + range, + ); + if let Some(range) = parent_range { + diagnostic.set_parent(range.start()); + } + diagnostics.push(diagnostic); + } + } } - diagnostics.push(diagnostic); } } -/// A runtime-required import with its surrounding context. -struct ImportBinding<'a> { - /// The qualified name of the import (e.g., `typing.List` for `from typing import List`). - import: AnyImport<'a>, - /// The first reference to the imported symbol. - reference_id: ResolvedReferenceId, - /// The trimmed range of the import (e.g., `List` in `from typing import List`). - range: TextRange, - /// The range of the import's parent statement. - parent_range: Option, -} - -impl Ranged for ImportBinding<'_> { - fn range(&self) -> TextRange { - self.range - } +/// Generate a [`Fix`] to quote runtime usages for imports in a type-checking block. +fn quote_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) -> Result { + let mut quote_reference_edits = imports + .iter() + .flat_map(|ImportBinding { binding, .. }| { + binding.references.iter().filter_map(|reference_id| { + let reference = checker.semantic().reference(*reference_id); + if reference.context().is_runtime() { + Some(quote_annotation( + reference.expression_id()?, + checker.semantic(), + checker.locator(), + checker.stylist(), + )) + } else { + None + } + }) + }) + .collect::>>()?; + let quote_reference_edit = quote_reference_edits + .pop() + .expect("Expected at least one reference"); + Ok( + Fix::unsafe_edits(quote_reference_edit, quote_reference_edits).isolate(Checker::isolation( + checker.semantic().parent_statement_id(node_id), + )), + ) } /// Generate a [`Fix`] to remove runtime imports from a type-checking block. -fn fix_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) -> Result { +fn move_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) -> Result { let statement = checker.semantic().statement(node_id); let parent = checker.semantic().parent_statement(node_id); @@ -236,3 +335,18 @@ fn fix_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) -> ), ) } + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Strategy { + /// The import should be moved out of the type-checking block. + /// + /// This is required when at least one reference to the symbol is in a runtime-required context. + /// For example, given `from foo import Bar`, `x = Bar()` would be runtime-required. + MoveImport, + /// All usages of the import should be wrapped in quotes. + /// + /// This is acceptable when all references to the symbol are in a runtime-evaluated, but not + /// runtime-required context. For example, given `from foo import Bar`, `x: Bar` would be + /// runtime-evaluated, but not runtime-required. + QuoteUsages, +} diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs b/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs index 1ce6336d3b158..cb3adaed08368 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs @@ -5,13 +5,15 @@ use rustc_hash::FxHashMap; use ruff_diagnostics::{Diagnostic, DiagnosticKind, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_semantic::{AnyImport, Binding, Imported, NodeId, ResolvedReferenceId, Scope}; -use ruff_text_size::{Ranged, TextRange}; +use ruff_python_semantic::{Binding, Imported, NodeId, Scope}; +use ruff_text_size::Ranged; use crate::checkers::ast::Checker; use crate::codes::Rule; use crate::fix; use crate::importer::ImportedMembers; +use crate::rules::flake8_type_checking::helpers::{is_typing_reference, quote_annotation}; +use crate::rules::flake8_type_checking::imports::ImportBinding; use crate::rules::isort::{categorize, ImportSection, ImportType}; /// ## What it does @@ -24,6 +26,10 @@ use crate::rules::isort::{categorize, ImportSection, ImportType}; /// instead be imported conditionally under an `if TYPE_CHECKING:` block to /// minimize runtime overhead. /// +/// If [`flake8-type-checking.quote-annotations`] is set to `true`, +/// annotations will be wrapped in quotes if doing so would enable the +/// corresponding import to be moved into an `if TYPE_CHECKING:` block. +/// /// If a class _requires_ that type annotations be available at runtime (as is /// the case for Pydantic, SQLAlchemy, and other libraries), consider using /// the [`flake8-type-checking.runtime-evaluated-base-classes`] and @@ -56,6 +62,7 @@ use crate::rules::isort::{categorize, ImportSection, ImportType}; /// ``` /// /// ## Options +/// - `flake8-type-checking.quote-annotations` /// - `flake8-type-checking.runtime-evaluated-base-classes` /// - `flake8-type-checking.runtime-evaluated-decorators` /// @@ -92,6 +99,10 @@ impl Violation for TypingOnlyFirstPartyImport { /// instead be imported conditionally under an `if TYPE_CHECKING:` block to /// minimize runtime overhead. /// +/// If [`flake8-type-checking.quote-annotations`] is set to `true`, +/// annotations will be wrapped in quotes if doing so would enable the +/// corresponding import to be moved into an `if TYPE_CHECKING:` block. +/// /// If a class _requires_ that type annotations be available at runtime (as is /// the case for Pydantic, SQLAlchemy, and other libraries), consider using /// the [`flake8-type-checking.runtime-evaluated-base-classes`] and @@ -124,6 +135,7 @@ impl Violation for TypingOnlyFirstPartyImport { /// ``` /// /// ## Options +/// - `flake8-type-checking.quote-annotations` /// - `flake8-type-checking.runtime-evaluated-base-classes` /// - `flake8-type-checking.runtime-evaluated-decorators` /// @@ -160,6 +172,10 @@ impl Violation for TypingOnlyThirdPartyImport { /// instead be imported conditionally under an `if TYPE_CHECKING:` block to /// minimize runtime overhead. /// +/// If [`flake8-type-checking.quote-annotations`] is set to `true`, +/// annotations will be wrapped in quotes if doing so would enable the +/// corresponding import to be moved into an `if TYPE_CHECKING:` block. +/// /// If a class _requires_ that type annotations be available at runtime (as is /// the case for Pydantic, SQLAlchemy, and other libraries), consider using /// the [`flake8-type-checking.runtime-evaluated-base-classes`] and @@ -192,6 +208,7 @@ impl Violation for TypingOnlyThirdPartyImport { /// ``` /// /// ## Options +/// - `flake8-type-checking.quote-annotations` /// - `flake8-type-checking.runtime-evaluated-base-classes` /// - `flake8-type-checking.runtime-evaluated-decorators` /// @@ -253,13 +270,12 @@ pub(crate) fn typing_only_runtime_import( }; if binding.context.is_runtime() - && binding.references().all(|reference_id| { - checker - .semantic() - .reference(reference_id) - .context() - .is_typing() - }) + && binding + .references() + .map(|reference_id| checker.semantic().reference(reference_id)) + .all(|reference| { + is_typing_reference(reference, &checker.settings.flake8_type_checking) + }) { let qualified_name = import.qualified_name(); @@ -310,6 +326,7 @@ pub(crate) fn typing_only_runtime_import( let import = ImportBinding { import, reference_id, + binding, range: binding.range(), parent_range: binding.parent_range(checker.semantic()), }; @@ -376,24 +393,6 @@ pub(crate) fn typing_only_runtime_import( } } -/// A runtime-required import with its surrounding context. -struct ImportBinding<'a> { - /// The qualified name of the import (e.g., `typing.List` for `from typing import List`). - import: AnyImport<'a>, - /// The first reference to the imported symbol. - reference_id: ResolvedReferenceId, - /// The trimmed range of the import (e.g., `List` in `from typing import List`). - range: TextRange, - /// The range of the import's parent statement. - parent_range: Option, -} - -impl Ranged for ImportBinding<'_> { - fn range(&self) -> TextRange { - self.range - } -} - /// Return the [`Rule`] for the given import type. fn rule_for(import_type: ImportType) -> Rule { match import_type { @@ -482,9 +481,34 @@ fn fix_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) -> checker.source_type, )?; - Ok( - Fix::unsafe_edits(remove_import_edit, add_import_edit.into_edits()).isolate( - Checker::isolation(checker.semantic().parent_statement_id(node_id)), - ), + // Step 3) Quote any runtime usages of the referenced symbol. + let quote_reference_edits = imports + .iter() + .flat_map(|ImportBinding { binding, .. }| { + binding.references.iter().filter_map(|reference_id| { + let reference = checker.semantic().reference(*reference_id); + if reference.context().is_runtime() { + Some(quote_annotation( + reference.expression_id()?, + checker.semantic(), + checker.locator(), + checker.stylist(), + )) + } else { + None + } + }) + }) + .collect::>>()?; + + Ok(Fix::unsafe_edits( + remove_import_edit, + add_import_edit + .into_edits() + .into_iter() + .chain(quote_reference_edits), ) + .isolate(Checker::isolation( + checker.semantic().parent_statement_id(node_id), + ))) } diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/settings.rs b/crates/ruff_linter/src/rules/flake8_type_checking/settings.rs index 425f02fe550a4..16baf1b91edbe 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/settings.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/settings.rs @@ -6,17 +6,19 @@ use ruff_macros::CacheKey; pub struct Settings { pub strict: bool, pub exempt_modules: Vec, - pub runtime_evaluated_base_classes: Vec, - pub runtime_evaluated_decorators: Vec, + pub runtime_required_base_classes: Vec, + pub runtime_required_decorators: Vec, + pub quote_annotations: bool, } impl Default for Settings { fn default() -> Self { Self { strict: false, - exempt_modules: vec!["typing".to_string()], - runtime_evaluated_base_classes: vec![], - runtime_evaluated_decorators: vec![], + exempt_modules: vec!["typing".to_string(), "typing_extensions".to_string()], + runtime_required_base_classes: vec![], + runtime_required_decorators: vec![], + quote_annotations: false, } } } diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_runtime-import-in-type-checking-block_quote.py.snap b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_runtime-import-in-type-checking-block_quote.py.snap new file mode 100644 index 0000000000000..0baeba9f62ec1 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_runtime-import-in-type-checking-block_quote.py.snap @@ -0,0 +1,22 @@ +--- +source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs +--- +quote.py:64:28: TCH004 [*] Quote references to `pandas.DataFrame`. Import is in a type-checking block. + | +63 | if TYPE_CHECKING: +64 | from pandas import DataFrame + | ^^^^^^^^^ TCH004 +65 | +66 | def func(value: DataFrame): + | + = help: Quote references + +ℹ Unsafe fix +63 63 | if TYPE_CHECKING: +64 64 | from pandas import DataFrame +65 65 | +66 |- def func(value: DataFrame): + 66 |+ def func(value: "DataFrame"): +67 67 | ... + + diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_typing-only-third-party-import_quote.py.snap b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_typing-only-third-party-import_quote.py.snap new file mode 100644 index 0000000000000..9c43070c0f5b8 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_typing-only-third-party-import_quote.py.snap @@ -0,0 +1,199 @@ +--- +source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs +--- +quote.py:2:24: TCH002 [*] Move third-party import `pandas.DataFrame` into a type-checking block + | +1 | def f(): +2 | from pandas import DataFrame + | ^^^^^^^^^ TCH002 +3 | +4 | def baz() -> DataFrame: + | + = help: Move into type-checking block + +ℹ Unsafe fix +1 |-def f(): + 1 |+from typing import TYPE_CHECKING + 2 |+ + 3 |+if TYPE_CHECKING: +2 4 | from pandas import DataFrame + 5 |+def f(): +3 6 | +4 |- def baz() -> DataFrame: + 7 |+ def baz() -> "DataFrame": +5 8 | ... +6 9 | +7 10 | + +quote.py:9:24: TCH002 [*] Move third-party import `pandas.DataFrame` into a type-checking block + | + 8 | def f(): + 9 | from pandas import DataFrame + | ^^^^^^^^^ TCH002 +10 | +11 | def baz() -> DataFrame[int]: + | + = help: Move into type-checking block + +ℹ Unsafe fix + 1 |+from typing import TYPE_CHECKING + 2 |+ + 3 |+if TYPE_CHECKING: + 4 |+ from pandas import DataFrame +1 5 | def f(): +2 6 | from pandas import DataFrame +3 7 | +-------------------------------------------------------------------------------- +6 10 | +7 11 | +8 12 | def f(): +9 |- from pandas import DataFrame +10 13 | +11 |- def baz() -> DataFrame[int]: + 14 |+ def baz() -> "DataFrame[int]": +12 15 | ... +13 16 | +14 17 | + +quote.py:16:24: TCH002 Move third-party import `pandas.DataFrame` into a type-checking block + | +15 | def f(): +16 | from pandas import DataFrame + | ^^^^^^^^^ TCH002 +17 | +18 | def baz() -> DataFrame["int"]: + | + = help: Move into type-checking block + +quote.py:23:22: TCH002 [*] Move third-party import `pandas` into a type-checking block + | +22 | def f(): +23 | import pandas as pd + | ^^ TCH002 +24 | +25 | def baz() -> pd.DataFrame: + | + = help: Move into type-checking block + +ℹ Unsafe fix + 1 |+from typing import TYPE_CHECKING + 2 |+ + 3 |+if TYPE_CHECKING: + 4 |+ import pandas as pd +1 5 | def f(): +2 6 | from pandas import DataFrame +3 7 | +-------------------------------------------------------------------------------- +20 24 | +21 25 | +22 26 | def f(): +23 |- import pandas as pd +24 27 | +25 |- def baz() -> pd.DataFrame: + 28 |+ def baz() -> "pd.DataFrame": +26 29 | ... +27 30 | +28 31 | + +quote.py:30:22: TCH002 [*] Move third-party import `pandas` into a type-checking block + | +29 | def f(): +30 | import pandas as pd + | ^^ TCH002 +31 | +32 | def baz() -> pd.DataFrame.Extra: + | + = help: Move into type-checking block + +ℹ Unsafe fix + 1 |+from typing import TYPE_CHECKING + 2 |+ + 3 |+if TYPE_CHECKING: + 4 |+ import pandas as pd +1 5 | def f(): +2 6 | from pandas import DataFrame +3 7 | +-------------------------------------------------------------------------------- +27 31 | +28 32 | +29 33 | def f(): +30 |- import pandas as pd +31 34 | +32 |- def baz() -> pd.DataFrame.Extra: + 35 |+ def baz() -> "pd.DataFrame.Extra": +33 36 | ... +34 37 | +35 38 | + +quote.py:37:22: TCH002 [*] Move third-party import `pandas` into a type-checking block + | +36 | def f(): +37 | import pandas as pd + | ^^ TCH002 +38 | +39 | def baz() -> pd.DataFrame | int: + | + = help: Move into type-checking block + +ℹ Unsafe fix + 1 |+from typing import TYPE_CHECKING + 2 |+ + 3 |+if TYPE_CHECKING: + 4 |+ import pandas as pd +1 5 | def f(): +2 6 | from pandas import DataFrame +3 7 | +-------------------------------------------------------------------------------- +34 38 | +35 39 | +36 40 | def f(): +37 |- import pandas as pd +38 41 | +39 |- def baz() -> pd.DataFrame | int: + 42 |+ def baz() -> "pd.DataFrame | int": +40 43 | ... +41 44 | +42 45 | + +quote.py:45:24: TCH002 [*] Move third-party import `pandas.DataFrame` into a type-checking block + | +44 | def f(): +45 | from pandas import DataFrame + | ^^^^^^^^^ TCH002 +46 | +47 | def baz() -> DataFrame(): + | + = help: Move into type-checking block + +ℹ Unsafe fix + 1 |+from typing import TYPE_CHECKING + 2 |+ + 3 |+if TYPE_CHECKING: + 4 |+ from pandas import DataFrame +1 5 | def f(): +2 6 | from pandas import DataFrame +3 7 | +-------------------------------------------------------------------------------- +42 46 | +43 47 | +44 48 | def f(): +45 |- from pandas import DataFrame +46 49 | +47 |- def baz() -> DataFrame(): + 50 |+ def baz() -> "DataFrame()": +48 51 | ... +49 52 | +50 53 | + +quote.py:54:24: TCH002 Move third-party import `pandas.DataFrame` into a type-checking block + | +52 | from typing import Literal +53 | +54 | from pandas import DataFrame + | ^^^^^^^^^ TCH002 +55 | +56 | def baz() -> DataFrame[Literal["int"]]: + | + = help: Move into type-checking block + + diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__runtime-import-in-type-checking-block_quote.py.snap b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__runtime-import-in-type-checking-block_quote.py.snap new file mode 100644 index 0000000000000..c09777853b97a --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__runtime-import-in-type-checking-block_quote.py.snap @@ -0,0 +1,29 @@ +--- +source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs +--- +quote.py:64:28: TCH004 [*] Move import `pandas.DataFrame` out of type-checking block. Import is used for more than type hinting. + | +63 | if TYPE_CHECKING: +64 | from pandas import DataFrame + | ^^^^^^^^^ TCH004 +65 | +66 | def func(value: DataFrame): + | + = help: Move out of type-checking block + +ℹ Unsafe fix + 1 |+from pandas import DataFrame +1 2 | def f(): +2 3 | from pandas import DataFrame +3 4 | +-------------------------------------------------------------------------------- +61 62 | from typing import TYPE_CHECKING +62 63 | +63 64 | if TYPE_CHECKING: +64 |- from pandas import DataFrame + 65 |+ pass +65 66 | +66 67 | def func(value: DataFrame): +67 68 | ... + + diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__typing-only-third-party-import_quote.py.snap b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__typing-only-third-party-import_quote.py.snap new file mode 100644 index 0000000000000..6c5ead27428ce --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__typing-only-third-party-import_quote.py.snap @@ -0,0 +1,4 @@ +--- +source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs +--- + diff --git a/crates/ruff_python_semantic/src/model.rs b/crates/ruff_python_semantic/src/model.rs index 82221f0f85dc8..d92dab84d0f5c 100644 --- a/crates/ruff_python_semantic/src/model.rs +++ b/crates/ruff_python_semantic/src/model.rs @@ -291,9 +291,12 @@ impl<'a> SemanticModel<'a> { if let Some(binding_id) = self.scopes.global().get(name.id.as_str()) { if !self.bindings[binding_id].is_unbound() { // Mark the binding as used. - let reference_id = - self.resolved_references - .push(ScopeId::global(), name.range, self.flags); + let reference_id = self.resolved_references.push( + ScopeId::global(), + self.node_id, + name.range, + self.flags, + ); self.bindings[binding_id].references.push(reference_id); // Mark any submodule aliases as used. @@ -302,6 +305,7 @@ impl<'a> SemanticModel<'a> { { let reference_id = self.resolved_references.push( ScopeId::global(), + self.node_id, name.range, self.flags, ); @@ -356,18 +360,24 @@ impl<'a> SemanticModel<'a> { if let Some(binding_id) = scope.get(name.id.as_str()) { // Mark the binding as used. - let reference_id = - self.resolved_references - .push(self.scope_id, name.range, self.flags); + let reference_id = self.resolved_references.push( + self.scope_id, + self.node_id, + name.range, + self.flags, + ); self.bindings[binding_id].references.push(reference_id); // Mark any submodule aliases as used. if let Some(binding_id) = self.resolve_submodule(name.id.as_str(), scope_id, binding_id) { - let reference_id = - self.resolved_references - .push(self.scope_id, name.range, self.flags); + let reference_id = self.resolved_references.push( + self.scope_id, + self.node_id, + name.range, + self.flags, + ); self.bindings[binding_id].references.push(reference_id); } @@ -431,9 +441,12 @@ impl<'a> SemanticModel<'a> { // The `x` in `print(x)` should resolve to the `x` in `x = 1`. BindingKind::UnboundException(Some(binding_id)) => { // Mark the binding as used. - let reference_id = - self.resolved_references - .push(self.scope_id, name.range, self.flags); + let reference_id = self.resolved_references.push( + self.scope_id, + self.node_id, + name.range, + self.flags, + ); self.bindings[binding_id].references.push(reference_id); // Mark any submodule aliases as used. @@ -442,6 +455,7 @@ impl<'a> SemanticModel<'a> { { let reference_id = self.resolved_references.push( self.scope_id, + self.node_id, name.range, self.flags, ); @@ -979,6 +993,23 @@ impl<'a> SemanticModel<'a> { &self.nodes[node_id] } + /// Given a [`Expr`], return its parent, if any. + #[inline] + pub fn parent_expression(&self, node_id: NodeId) -> Option<&'a Expr> { + self.nodes + .ancestor_ids(node_id) + .filter_map(|id| self.nodes[id].as_expression()) + .nth(1) + } + + /// Given a [`NodeId`], return the [`NodeId`] of the parent expression, if any. + pub fn parent_expression_id(&self, node_id: NodeId) -> Option { + self.nodes + .ancestor_ids(node_id) + .filter(|id| self.nodes[*id].is_expression()) + .nth(1) + } + /// Return the [`Stmt`] corresponding to the given [`NodeId`]. #[inline] pub fn statement(&self, node_id: NodeId) -> &'a Stmt { @@ -1007,11 +1038,10 @@ impl<'a> SemanticModel<'a> { /// Return the [`Expr`] corresponding to the given [`NodeId`]. #[inline] - pub fn expression(&self, node_id: NodeId) -> &'a Expr { + pub fn expression(&self, node_id: NodeId) -> Option<&'a Expr> { self.nodes .ancestor_ids(node_id) .find_map(|id| self.nodes[id].as_expression()) - .expect("No expression found") } /// Returns an [`Iterator`] over the expressions, starting from the given [`NodeId`]. @@ -1186,17 +1216,17 @@ impl<'a> SemanticModel<'a> { /// Add a reference to the given [`BindingId`] in the local scope. pub fn add_local_reference(&mut self, binding_id: BindingId, range: TextRange) { - let reference_id = self - .resolved_references - .push(self.scope_id, range, self.flags); + let reference_id = + self.resolved_references + .push(self.scope_id, self.node_id, range, self.flags); self.bindings[binding_id].references.push(reference_id); } /// Add a reference to the given [`BindingId`] in the global scope. pub fn add_global_reference(&mut self, binding_id: BindingId, range: TextRange) { - let reference_id = self - .resolved_references - .push(ScopeId::global(), range, self.flags); + let reference_id = + self.resolved_references + .push(ScopeId::global(), self.node_id, range, self.flags); self.bindings[binding_id].references.push(reference_id); } @@ -1299,10 +1329,16 @@ impl<'a> SemanticModel<'a> { .intersects(SemanticModelFlags::TYPING_ONLY_ANNOTATION) } - /// Return `true` if the model is in a runtime-required type annotation. - pub const fn in_runtime_annotation(&self) -> bool { + /// Return `true` if the context is in a runtime-evaluated type annotation. + pub const fn in_runtime_evaluated_annotation(&self) -> bool { + self.flags + .intersects(SemanticModelFlags::RUNTIME_EVALUATED_ANNOTATION) + } + + /// Return `true` if the context is in a runtime-required type annotation. + pub const fn in_runtime_required_annotation(&self) -> bool { self.flags - .intersects(SemanticModelFlags::RUNTIME_ANNOTATION) + .intersects(SemanticModelFlags::RUNTIME_REQUIRED_ANNOTATION) } /// Return `true` if the model is in a type definition. @@ -1474,8 +1510,9 @@ impl ShadowedBinding { bitflags! { /// Flags indicating the current model state. #[derive(Debug, Default, Copy, Clone, Eq, PartialEq)] - pub struct SemanticModelFlags: u16 { - /// The model is in a typing-time-only type annotation. + pub struct SemanticModelFlags: u32 { + /// The model is in a type annotation that will only be evaluated when running a type + /// checker. /// /// For example, the model could be visiting `int` in: /// ```python @@ -1490,7 +1527,7 @@ bitflags! { /// are any annotated assignments in module or class scopes. const TYPING_ONLY_ANNOTATION = 1 << 0; - /// The model is in a runtime type annotation. + /// The model is in a type annotation that will be evaluated at runtime. /// /// For example, the model could be visiting `int` in: /// ```python @@ -1504,7 +1541,27 @@ bitflags! { /// If `from __future__ import annotations` is used, all annotations are evaluated at /// typing time. Otherwise, all function argument annotations are evaluated at runtime, as /// are any annotated assignments in module or class scopes. - const RUNTIME_ANNOTATION = 1 << 1; + const RUNTIME_EVALUATED_ANNOTATION = 1 << 1; + + /// The model is in a type annotation that is _required_ to be available at runtime. + /// + /// For example, the context could be visiting `int` in: + /// ```python + /// from pydantic import BaseModel + /// + /// class Foo(BaseModel): + /// x: int + /// ``` + /// + /// In this case, Pydantic requires that the type annotation be available at runtime + /// in order to perform runtime type-checking. + /// + /// Unlike [`RUNTIME_EVALUATED_ANNOTATION`], annotations that are marked as + /// [`RUNTIME_REQUIRED_ANNOTATION`] cannot be deferred to typing time via conversion to a + /// forward reference (e.g., by wrapping the type in quotes), as the annotations are not + /// only required by the Python interpreter, but by runtime type checkers too. + const RUNTIME_REQUIRED_ANNOTATION = 1 << 2; + /// The model is in a type definition. /// @@ -1518,7 +1575,7 @@ bitflags! { /// All type annotations are also type definitions, but the converse is not true. /// In our example, `int` is a type definition but not a type annotation, as it /// doesn't appear in a type annotation context, but rather in a type definition. - const TYPE_DEFINITION = 1 << 2; + const TYPE_DEFINITION = 1 << 3; /// The model is in a (deferred) "simple" string type definition. /// @@ -1529,7 +1586,7 @@ bitflags! { /// /// "Simple" string type definitions are those that consist of a single string literal, /// as opposed to an implicitly concatenated string literal. - const SIMPLE_STRING_TYPE_DEFINITION = 1 << 3; + const SIMPLE_STRING_TYPE_DEFINITION = 1 << 4; /// The model is in a (deferred) "complex" string type definition. /// @@ -1540,7 +1597,7 @@ bitflags! { /// /// "Complex" string type definitions are those that consist of a implicitly concatenated /// string literals. These are uncommon but valid. - const COMPLEX_STRING_TYPE_DEFINITION = 1 << 4; + const COMPLEX_STRING_TYPE_DEFINITION = 1 << 5; /// The model is in a (deferred) `__future__` type definition. /// @@ -1553,7 +1610,7 @@ bitflags! { /// /// `__future__`-style type annotations are only enabled if the `annotations` feature /// is enabled via `from __future__ import annotations`. - const FUTURE_TYPE_DEFINITION = 1 << 5; + const FUTURE_TYPE_DEFINITION = 1 << 6; /// The model is in an exception handler. /// @@ -1564,7 +1621,7 @@ bitflags! { /// except Exception: /// x: int = 1 /// ``` - const EXCEPTION_HANDLER = 1 << 6; + const EXCEPTION_HANDLER = 1 << 7; /// The model is in an f-string. /// @@ -1572,7 +1629,7 @@ bitflags! { /// ```python /// f'{x}' /// ``` - const F_STRING = 1 << 7; + const F_STRING = 1 << 8; /// The model is in a boolean test. /// @@ -1584,7 +1641,7 @@ bitflags! { /// /// The implication is that the actual value returned by the current expression is /// not used, only its truthiness. - const BOOLEAN_TEST = 1 << 8; + const BOOLEAN_TEST = 1 << 9; /// The model is in a `typing::Literal` annotation. /// @@ -1593,7 +1650,7 @@ bitflags! { /// def f(x: Literal["A", "B", "C"]): /// ... /// ``` - const TYPING_LITERAL = 1 << 9; + const TYPING_LITERAL = 1 << 10; /// The model is in a subscript expression. /// @@ -1601,7 +1658,7 @@ bitflags! { /// ```python /// x["a"]["b"] /// ``` - const SUBSCRIPT = 1 << 10; + const SUBSCRIPT = 1 << 11; /// The model is in a type-checking block. /// @@ -1613,7 +1670,7 @@ bitflags! { /// if TYPE_CHECKING: /// x: int = 1 /// ``` - const TYPE_CHECKING_BLOCK = 1 << 11; + const TYPE_CHECKING_BLOCK = 1 << 12; /// The model has traversed past the "top-of-file" import boundary. /// @@ -1626,7 +1683,7 @@ bitflags! { /// /// x: int = 1 /// ``` - const IMPORT_BOUNDARY = 1 << 12; + const IMPORT_BOUNDARY = 1 << 13; /// The model has traversed past the `__future__` import boundary. /// @@ -1641,7 +1698,7 @@ bitflags! { /// /// Python considers it a syntax error to import from `__future__` after /// any other non-`__future__`-importing statements. - const FUTURES_BOUNDARY = 1 << 13; + const FUTURES_BOUNDARY = 1 << 14; /// `__future__`-style type annotations are enabled in this model. /// @@ -1653,7 +1710,7 @@ bitflags! { /// def f(x: int) -> int: /// ... /// ``` - const FUTURE_ANNOTATIONS = 1 << 14; + const FUTURE_ANNOTATIONS = 1 << 15; /// The model is in a type parameter definition. /// @@ -1663,10 +1720,11 @@ bitflags! { /// /// Record = TypeVar("Record") /// - const TYPE_PARAM_DEFINITION = 1 << 15; + const TYPE_PARAM_DEFINITION = 1 << 16; /// The context is in any type annotation. - const ANNOTATION = Self::TYPING_ONLY_ANNOTATION.bits() | Self::RUNTIME_ANNOTATION.bits(); + const ANNOTATION = Self::TYPING_ONLY_ANNOTATION.bits() | Self::RUNTIME_EVALUATED_ANNOTATION.bits() | Self::RUNTIME_REQUIRED_ANNOTATION.bits(); + /// The context is in any string type definition. const STRING_TYPE_DEFINITION = Self::SIMPLE_STRING_TYPE_DEFINITION.bits() diff --git a/crates/ruff_python_semantic/src/reference.rs b/crates/ruff_python_semantic/src/reference.rs index a963895b21e69..6bb807e1c8523 100644 --- a/crates/ruff_python_semantic/src/reference.rs +++ b/crates/ruff_python_semantic/src/reference.rs @@ -8,11 +8,14 @@ use ruff_text_size::{Ranged, TextRange}; use crate::context::ExecutionContext; use crate::scope::ScopeId; -use crate::{Exceptions, SemanticModelFlags}; +use crate::{Exceptions, NodeId, SemanticModelFlags}; /// A resolved read reference to a name in a program. #[derive(Debug, Clone)] pub struct ResolvedReference { + /// The expression that the reference occurs in. `None` if the reference is a global + /// reference or a reference via an augmented assignment. + node_id: Option, /// The scope in which the reference is defined. scope_id: ScopeId, /// The range of the reference in the source code. @@ -22,6 +25,11 @@ pub struct ResolvedReference { } impl ResolvedReference { + /// The expression that the reference occurs in. + pub const fn expression_id(&self) -> Option { + self.node_id + } + /// The scope in which the reference is defined. pub const fn scope_id(&self) -> ScopeId { self.scope_id @@ -35,6 +43,48 @@ impl ResolvedReference { ExecutionContext::Runtime } } + + /// Return `true` if the context is in a typing-only type annotation. + pub const fn in_typing_only_annotation(&self) -> bool { + self.flags + .intersects(SemanticModelFlags::TYPING_ONLY_ANNOTATION) + } + + /// Return `true` if the context is in a runtime-required type annotation. + pub const fn in_runtime_evaluated_annotation(&self) -> bool { + self.flags + .intersects(SemanticModelFlags::RUNTIME_EVALUATED_ANNOTATION) + } + + /// Return `true` if the context is in a "simple" string type definition. + pub const fn in_simple_string_type_definition(&self) -> bool { + self.flags + .intersects(SemanticModelFlags::SIMPLE_STRING_TYPE_DEFINITION) + } + + /// Return `true` if the context is in a "complex" string type definition. + pub const fn in_complex_string_type_definition(&self) -> bool { + self.flags + .intersects(SemanticModelFlags::COMPLEX_STRING_TYPE_DEFINITION) + } + + /// Return `true` if the context is in a `__future__` type definition. + pub const fn in_future_type_definition(&self) -> bool { + self.flags + .intersects(SemanticModelFlags::FUTURE_TYPE_DEFINITION) + } + + /// Return `true` if the context is in any kind of deferred type definition. + pub const fn in_deferred_type_definition(&self) -> bool { + self.flags + .intersects(SemanticModelFlags::DEFERRED_TYPE_DEFINITION) + } + + /// Return `true` if the context is in a type-checking block. + pub const fn in_type_checking_block(&self) -> bool { + self.flags + .intersects(SemanticModelFlags::TYPE_CHECKING_BLOCK) + } } impl Ranged for ResolvedReference { @@ -57,10 +107,12 @@ impl ResolvedReferences { pub(crate) fn push( &mut self, scope_id: ScopeId, + node_id: Option, range: TextRange, flags: SemanticModelFlags, ) -> ResolvedReferenceId { self.0.push(ResolvedReference { + node_id, scope_id, range, flags, diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index 10e5c6717696e..c0ce2c2e79f98 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -1642,6 +1642,57 @@ pub struct Flake8TypeCheckingOptions { "# )] pub runtime_evaluated_decorators: Option>, + + /// Whether to add quotes around type annotations, if doing so would allow + /// the corresponding import to be moved into a type-checking block. + /// + /// For example, in the following, Python requires that `Sequence` be + /// available at runtime, despite the fact that it's only used in a type + /// annotation: + /// + /// ```python + /// from collections.abc import Sequence + /// + /// + /// def func(value: Sequence[int]) -> None: + /// ... + /// ``` + /// + /// In other words, moving `from collections.abc import Sequence` into an + /// `if TYPE_CHECKING:` block above would cause a runtime error, as the + /// type would no longer be available at runtime. + /// + /// By default, Ruff will respect such runtime semantics and avoid moving + /// the import to prevent such runtime errors. + /// + /// Setting `quote-annotations` to `true` will instruct Ruff to add quotes + /// around the annotation (e.g., `"Sequence[int]"`), which in turn enables + /// Ruff to move the import into an `if TYPE_CHECKING:` block, like so: + /// + /// ```python + /// from typing import TYPE_CHECKING + /// + /// if TYPE_CHECKING: + /// from collections.abc import Sequence + /// + /// + /// def func(value: "Sequence[int]") -> None: + /// ... + /// ``` + /// + /// Note that this setting has no effect when `from __future__ import annotations` + /// is present, as `__future__` annotations are always treated equivalently + /// to quoted annotations. + #[option( + default = "false", + value_type = "bool", + example = r#" + # Add quotes around type annotations, if doing so would allow + # an import to be moved into a type-checking block. + quote-annotations = true + "# + )] + pub quote_annotations: Option, } impl Flake8TypeCheckingOptions { @@ -1651,8 +1702,9 @@ impl Flake8TypeCheckingOptions { exempt_modules: self .exempt_modules .unwrap_or_else(|| vec!["typing".to_string()]), - runtime_evaluated_base_classes: self.runtime_evaluated_base_classes.unwrap_or_default(), - runtime_evaluated_decorators: self.runtime_evaluated_decorators.unwrap_or_default(), + runtime_required_base_classes: self.runtime_evaluated_base_classes.unwrap_or_default(), + runtime_required_decorators: self.runtime_evaluated_decorators.unwrap_or_default(), + quote_annotations: self.quote_annotations.unwrap_or_default(), } } } diff --git a/ruff.schema.json b/ruff.schema.json index cbff63adcd807..8f67f9a12d787 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -1194,6 +1194,13 @@ "type": "string" } }, + "quote-annotations": { + "description": "Whether to add quotes around type annotations, if doing so would allow the corresponding import to be moved into a type-checking block.\n\nFor example, in the following, Python requires that `Sequence` be available at runtime, despite the fact that it's only used in a type annotation:\n\n```python from collections.abc import Sequence\n\ndef func(value: Sequence[int]) -> None: ... ```\n\nIn other words, moving `from collections.abc import Sequence` into an `if TYPE_CHECKING:` block above would cause a runtime error, as the type would no longer be available at runtime.\n\nBy default, Ruff will respect such runtime semantics and avoid moving the import to prevent such runtime errors.\n\nSetting `quote-annotations` to `true` will instruct Ruff to add quotes around the annotation (e.g., `\"Sequence[int]\"`), which in turn enables Ruff to move the import into an `if TYPE_CHECKING:` block, like so:\n\n```python from typing import TYPE_CHECKING\n\nif TYPE_CHECKING: from collections.abc import Sequence\n\ndef func(value: \"Sequence[int]\") -> None: ... ```\n\nNote that this setting has no effect when `from __future__ import annotations` is present, as `__future__` annotations are always treated equivalently to quoted annotations.", + "type": [ + "boolean", + "null" + ] + }, "runtime-evaluated-base-classes": { "description": "Exempt classes that list any of the enumerated classes as a base class from needing to be moved into type-checking blocks.\n\nCommon examples include Pydantic's `pydantic.BaseModel` and SQLAlchemy's `sqlalchemy.orm.DeclarativeBase`, but can also support user-defined classes that inherit from those base classes. For example, if you define a common `DeclarativeBase` subclass that's used throughout your project (e.g., `class Base(DeclarativeBase) ...` in `base.py`), you can add it to this list (`runtime-evaluated-base-classes = [\"base.Base\"]`) to exempt models from being moved into type-checking blocks.", "type": [ From 45f603000dc19d0d5fb67ba63e5aa0c0e83869a2 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Wed, 13 Dec 2023 12:43:23 +0900 Subject: [PATCH 177/197] `prefer_splitting_right_hand_side_of_assignments` preview style (#8943) --- .../assignment_split_value_first.options.json | 5 + .../statement/assignment_split_value_first.py | 218 ++++++ .../src/expression/mod.rs | 2 +- crates/ruff_python_formatter/src/preview.rs | 7 + .../src/statement/stmt_ann_assign.rs | 44 +- .../src/statement/stmt_assign.rs | 638 +++++++++++++++--- .../src/statement/stmt_aug_assign.rs | 47 +- .../src/statement/stmt_return.rs | 5 +- .../src/statement/stmt_type_alias.rs | 17 +- ...es__pep604_union_types_line_breaks.py.snap | 20 +- ...bility@cases__preview_long_strings.py.snap | 16 +- ...__preview_long_strings__regression.py.snap | 34 +- ...ty@cases__preview_prefer_rhs_split.py.snap | 155 +---- ...ion__optional_parentheses_comments.py.snap | 40 ++ .../tests/snapshots/format@preview.py.snap | 30 +- .../format@statement__ann_assign.py.snap | 20 + .../format@statement__assign.py.snap | 36 + ...ment__assignment_split_value_first.py.snap | 457 +++++++++++++ 18 files changed, 1466 insertions(+), 325 deletions(-) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/assignment_split_value_first.options.json create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/assignment_split_value_first.py create mode 100644 crates/ruff_python_formatter/tests/snapshots/format@statement__assignment_split_value_first.py.snap diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/assignment_split_value_first.options.json b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/assignment_split_value_first.options.json new file mode 100644 index 0000000000000..8925dd0a8280f --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/assignment_split_value_first.options.json @@ -0,0 +1,5 @@ +[ + { + "preview": "enabled" + } +] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/assignment_split_value_first.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/assignment_split_value_first.py new file mode 100644 index 0000000000000..4c266a1ad50ee --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/assignment_split_value_first.py @@ -0,0 +1,218 @@ +####### +# Unsplittable target and value + +# Only parenthesize the value if it makes it fit, otherwise avoid parentheses. +b = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvee + +bbbbbbbbbbbbbbbb = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvv + +# Avoid parenthesizing the value even if the target exceeds the configured width +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = bbb + + +############ +# Splittable targets + +# Does not double-parenthesize tuples +( + first_item, + second_item, +) = some_looooooooong_module.some_loooooog_function_name( + first_argument, second_argument, third_argument +) + + +# Preserve parentheses around the first target +( + req["ticket"]["steps"]["step"][0]["tasks"]["task"]["fields"]["field"][ + "access_request" + ]["destinations"]["destination"][0]["ip_address"] +) = dst + +# Augmented assignment +req["ticket"]["steps"]["step"][0]["tasks"]["task"]["fields"]["field"][ + "access_request" +] += dst + +# Always parenthesize the value if it avoids splitting the target, regardless of the value's width. +_a: a[aaaa] = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvv +) + +##### +# Avoid parenthesizing the value if the expression right before the `=` splits to avoid an unnecessary pair of parentheses + +# The type annotation is guaranteed to split because it is too long. +_a: a[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvv +] = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvv + +# The target is too long +( + aaaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvv + +# The target splits because of a magic trailing comma +( + a, + b, +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvvvv + +# The targets split because of a comment +( + # leading + a +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvvvv + +( + a + # trailing +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvvvv + +( + a, # nested + b +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvvvv + +####### +# Multi targets + +# Black always parenthesizes the right if using multiple targets regardless if the parenthesized value exceeds the +# the configured line width or not +aaaa = bbbbbbbbbbbbbbbb = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvee +) + +# Black does parenthesize the target if the target itself exceeds the line width and only parenthesizes +# the values if it makes it fit. +# The second target is too long to ever fit into the configured line width. +aaaa = ( + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbdddd +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvee + +# Does also apply for other multi target assignments, as soon as a single target exceeds the configured +# width +aaaaaa = a["aaa"] = bbbbb[aa, bbb, cccc] = dddddddddd = eeeeee = ( + fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + +###################### +# Call expressions: +# For unsplittable targets: Parenthesize the call expression if it makes it fit. +# +# For splittable targets: +# Only parenthesize a call expression if the parens of the call don't fit on the same line +# as the target. Don't parenthesize the call expression if the target (or annotation) right before +# splits. + +# Don't parenthesize the function call if the left is unsplittable. +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = a.b.function( + arg1, arg2, arg3 +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + [1, 2, 3], + arg1, + [1, 2, 3], + arg2, + [1, 2, 3], + arg3, + dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd, + eeeeeeeeeeeeee, +) + +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = ( + function() +) +this_is_a_ridiculously_long_name_and_nobodyddddddddddddddddddddddddddddddd = ( + a.b.function(arg1, arg2, arg3) +) +this_is_a_ridiculously_long_name_and_nobodyddddddddddddddddddddddddddddddd = function() +this_is_a_ridiculously_long_name_and_nobodyddddddddddddddddddddddddddddddd = function( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 +) +this_is_a_ridiculously_long_name_and_nobodyddddddddddddddddddddddddddddddd = function( + [1, 2, 3], + arg1, + [1, 2, 3], + arg2, + [1, 2, 3], + arg3, + dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd, + eeeeeeeeeeeeee, +) + +####### Fluent call expressions +# Uses the regular `Multiline` layout where the entire `value` gets parenthesized +# if it doesn't fit on the line. +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use = ( + function().b().c([1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3) +) + + +####### +# Test comment inlining +value.__dict__[key] = ( + "test" # set some Thrift field to non-None in the struct aa bb cc dd ee +) +value.__dict__.keye = ( + "test" # set some Thrift field to non-None in the struct aa bb cc dd ee +) +value.__dict__.keye = ( + "test" # set some Thrift field to non-None in the struct aa bb cc dd ee +) + + +# Don't parenthesize the value because the target's trailing comma forces it to split. +a[ + aaaaaaa, + b, +] = cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc # comment + +# Parenthesize the value, but don't duplicate the comment. +a[aaaaaaa, b] = ( + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc # comment +) + +# Format both as flat, but don't loos the comment. +a[aaaaaaa, b] = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb # comment + +####################################################### +# Test the case where a parenthesized value now fits: +a[ + aaaaaaa, + b +] = ( + cccccccc # comment +) + +# Splits the target but not the value because of the magic trailing comma. +a[ + aaaaaaa, + b, +] = ( + cccccccc # comment +) + +# Splits the second target because of the comment and the first target because of the trailing comma. +a[ + aaaaaaa, + b, +] = ( + # leading comment + b +) = ( + cccccccc # comment +) + + +######## +# Type Alias Statement +type A[str, int, number] = VeryLongTypeNameThatShouldBreakFirstToTheRightBeforeSplitngtin + +type A[VeryLongTypeNameThatShouldBreakFirstToTheRightBeforeSplitngtinthatExceedsTheWidth] = str + diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index 435c39dedcc25..084a138912b70 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -952,7 +952,7 @@ impl OwnParentheses { /// Differs from [`has_own_parentheses`] in that it returns [`OwnParentheses::NonEmpty`] for /// parenthesized expressions, like `(1)` or `([1])`, regardless of whether those expression have /// their _own_ parentheses. -fn has_parentheses(expr: &Expr, context: &PyFormatContext) -> Option { +pub(crate) fn has_parentheses(expr: &Expr, context: &PyFormatContext) -> Option { let own_parentheses = has_own_parentheses(expr, context); // If the node has its own non-empty parentheses, we don't need to check for surrounding diff --git a/crates/ruff_python_formatter/src/preview.rs b/crates/ruff_python_formatter/src/preview.rs index 8354e83a64d4a..90379d1ad8fab 100644 --- a/crates/ruff_python_formatter/src/preview.rs +++ b/crates/ruff_python_formatter/src/preview.rs @@ -17,3 +17,10 @@ pub(crate) const fn is_hug_parens_with_braces_and_square_brackets_enabled( ) -> bool { context.is_preview() } + +/// Returns `true` if the [`prefer_splitting_right_hand_side_of_assignments`](https://github.com/astral-sh/ruff/issues/6975) preview style is enabled. +pub(crate) const fn is_prefer_splitting_right_hand_side_of_assignments_enabled( + context: &PyFormatContext, +) -> bool { + context.is_preview() +} diff --git a/crates/ruff_python_formatter/src/statement/stmt_ann_assign.rs b/crates/ruff_python_formatter/src/statement/stmt_ann_assign.rs index 17efcab1a8f77..89a97acc6f454 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_ann_assign.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_ann_assign.rs @@ -2,8 +2,12 @@ use ruff_formatter::write; use ruff_python_ast::StmtAnnAssign; use crate::comments::{SourceComment, SuppressionKind}; +use crate::expression::has_parentheses; use crate::prelude::*; -use crate::statement::stmt_assign::FormatStatementsLastExpression; +use crate::preview::is_prefer_splitting_right_hand_side_of_assignments_enabled; +use crate::statement::stmt_assign::{ + AnyAssignmentOperator, AnyBeforeOperator, FormatStatementsLastExpression, +}; use crate::statement::trailing_semicolon; #[derive(Default)] @@ -19,21 +23,33 @@ impl FormatNodeRule for FormatStmtAnnAssign { simple: _, } = item; - write!( - f, - [target.format(), token(":"), space(), annotation.format(),] - )?; + write!(f, [target.format(), token(":"), space()])?; if let Some(value) = value { - write!( - f, - [ - space(), - token("="), - space(), - FormatStatementsLastExpression::new(value, item) - ] - )?; + if is_prefer_splitting_right_hand_side_of_assignments_enabled(f.context()) + && has_parentheses(annotation, f.context()).is_some() + { + FormatStatementsLastExpression::RightToLeft { + before_operator: AnyBeforeOperator::Expression(annotation), + operator: AnyAssignmentOperator::Assign, + value, + statement: item.into(), + } + .fmt(f)?; + } else { + write!( + f, + [ + annotation.format(), + space(), + token("="), + space(), + FormatStatementsLastExpression::left_to_right(value, item) + ] + )?; + } + } else { + annotation.format().fmt(f)?; } if f.options().source_type().is_ipynb() diff --git a/crates/ruff_python_formatter/src/statement/stmt_assign.rs b/crates/ruff_python_formatter/src/statement/stmt_assign.rs index a183e4e2ada25..9430e7289a210 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_assign.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_assign.rs @@ -1,13 +1,17 @@ use ruff_formatter::{format_args, write, FormatError}; -use ruff_python_ast::{AnyNodeRef, Expr, StmtAssign}; +use ruff_python_ast::{AnyNodeRef, Expr, Operator, StmtAssign, TypeParams}; -use crate::comments::{trailing_comments, SourceComment, SuppressionKind}; +use crate::builders::parenthesize_if_expands; +use crate::comments::{ + trailing_comments, Comments, LeadingDanglingTrailingComments, SourceComment, SuppressionKind, +}; use crate::context::{NodeLevel, WithNodeLevel}; use crate::expression::parentheses::{ - NeedsParentheses, OptionalParentheses, Parentheses, Parenthesize, + is_expression_parenthesized, NeedsParentheses, OptionalParentheses, Parentheses, Parenthesize, }; use crate::expression::{has_own_parentheses, maybe_parenthesize_expression}; use crate::prelude::*; +use crate::preview::is_prefer_splitting_right_hand_side_of_assignments_enabled; use crate::statement::trailing_semicolon; #[derive(Default)] @@ -25,24 +29,66 @@ impl FormatNodeRule for FormatStmtAssign { "Expected at least on assignment target", ))?; - write!( - f, - [ - first.format(), - space(), - token("="), - space(), - FormatTargets { targets: rest } - ] - )?; + // The first target is special because it never gets parenthesized nor does the formatter remove parentheses if unnecessary. + let format_first = FormatTargetWithEqualOperator { + target: first, + preserve_parentheses: true, + }; - FormatStatementsLastExpression::new(value, item).fmt(f)?; + if is_prefer_splitting_right_hand_side_of_assignments_enabled(f.context()) { + // Avoid parenthesizing the value if the last target before the assigned value expands. + if let Some((last, head)) = rest.split_last() { + format_first.fmt(f)?; + + for target in head { + FormatTargetWithEqualOperator { + target, + preserve_parentheses: false, + } + .fmt(f)?; + } + + FormatStatementsLastExpression::RightToLeft { + before_operator: AnyBeforeOperator::Expression(last), + operator: AnyAssignmentOperator::Assign, + value, + statement: item.into(), + } + .fmt(f)?; + } + // Avoid parenthesizing the value for single-target assignments that where the + // target has its own parentheses (list, dict, tuple, ...) and the target expands. + else if has_target_own_parentheses(first, f.context()) + && !is_expression_parenthesized( + first.into(), + f.context().comments().ranges(), + f.context().source(), + ) + { + FormatStatementsLastExpression::RightToLeft { + before_operator: AnyBeforeOperator::Expression(first), + operator: AnyAssignmentOperator::Assign, + value, + statement: item.into(), + } + .fmt(f)?; + } + // For single targets that have no split points, parenthesize the value only + // if it makes it fit. Otherwise omit the parentheses. + else { + format_first.fmt(f)?; + FormatStatementsLastExpression::left_to_right(value, item).fmt(f)?; + } + } else { + write!(f, [format_first, FormatTargets { targets: rest }])?; + + FormatStatementsLastExpression::left_to_right(value, item).fmt(f)?; + } if f.options().source_type().is_ipynb() && f.context().node_level().is_last_top_level_statement() - && rest.is_empty() - && first.is_name_expr() && trailing_semicolon(item.into(), f.context().source()).is_some() + && matches!(targets.as_slice(), [Expr::Name(_)]) { token(";").fmt(f)?; } @@ -59,6 +105,7 @@ impl FormatNodeRule for FormatStmtAssign { } } +/// Formats the targets so that they split left-to right. #[derive(Debug)] struct FormatTargets<'a> { targets: &'a [Expr], @@ -71,7 +118,7 @@ impl Format> for FormatTargets<'_> { let parenthesize = if comments.has_leading(first) || comments.has_trailing(first) { ParenthesizeTarget::Always - } else if has_own_parentheses(first, f.context()).is_some() { + } else if has_target_own_parentheses(first, f.context()) { ParenthesizeTarget::Never } else { ParenthesizeTarget::IfBreaks @@ -129,10 +176,50 @@ enum ParenthesizeTarget { IfBreaks, } +/// Formats a single target with the equal operator. +struct FormatTargetWithEqualOperator<'a> { + target: &'a Expr, + + /// Whether parentheses should be preserved as in the source or if the target + /// should only be parenthesized if necessary (because of comments or because it doesn't fit). + preserve_parentheses: bool, +} + +impl Format> for FormatTargetWithEqualOperator<'_> { + fn fmt(&self, f: &mut Formatter>) -> FormatResult<()> { + // Preserve parentheses for the first target or around targets with leading or trailing comments. + if self.preserve_parentheses + || f.context().comments().has_leading(self.target) + || f.context().comments().has_trailing(self.target) + { + self.target.format().fmt(f)?; + } else if has_target_own_parentheses(self.target, f.context()) { + self.target + .format() + .with_options(Parentheses::Never) + .fmt(f)?; + } else { + parenthesize_if_expands(&self.target.format().with_options(Parentheses::Never)) + .fmt(f)?; + } + + write!(f, [space(), token("="), space()]) + } +} + /// Formats the last expression in statements that start with a keyword (like `return`) or after an operator (assignments). /// -/// It avoids parenthesizing unsplittable values (like `None`, `True`, `False`, Names, a subset of strings) just to make -/// the trailing comment fit and inlines a trailing comment if the value itself exceeds the configured line width: +/// The implementation avoids parenthesizing unsplittable values (like `None`, `True`, `False`, Names, a subset of strings) +/// if the value won't fit even when parenthesized. +/// +/// ## Trailing comments +/// Trailing comments are inlined inside the `value`'s parentheses rather than formatted at the end +/// of the statement for unsplittable values if the `value` gets parenthesized. +/// +/// Inlining the trailing comments prevent situations where the parenthesized value +/// still exceeds the configured line width, but parenthesizing helps to make the trailing comment fit. +/// Instead, it only parenthesizes `value` if it makes both the `value` and the trailing comment fit. +/// See [PR 8431](https://github.com/astral-sh/ruff/pull/8431) for more details. /// /// The implementation formats the statement's and value's trailing end of line comments: /// * after the expression if the expression needs no parentheses (necessary or the `expand_parent` makes the group never fit). @@ -155,123 +242,337 @@ enum ParenthesizeTarget { /// b = short # with comment /// ``` /// -/// The long name gets parenthesized because it exceeds the configured line width and the trailing comma of the +/// The long name gets parenthesized because it exceeds the configured line width and the trailing comment of the /// statement gets formatted inside (instead of outside) the parentheses. /// -/// The `short` name gets unparenthesized because it fits into the configured line length, regardless of whether +/// No parentheses are added for `short` because it fits into the configured line length, regardless of whether /// the comment exceeds the line width or not. /// /// This logic isn't implemented in [`place_comment`] by associating trailing statement comments to the expression because /// doing so breaks the suite empty lines formatting that relies on trailing comments to be stored on the statement. -pub(super) struct FormatStatementsLastExpression<'a> { - expression: &'a Expr, - parent: AnyNodeRef<'a>, +pub(super) enum FormatStatementsLastExpression<'a> { + /// Prefers to split what's left of `value` before splitting the value. + /// + /// ```python + /// aaaaaaa[bbbbbbbb] = some_long_value + /// ``` + /// + /// This layout splits `aaaaaaa[bbbbbbbb]` first assuming the whole statements exceeds the line width, resulting in + /// + /// ```python + /// aaaaaaa[ + /// bbbbbbbb + /// ] = some_long_value + /// ``` + /// + /// This layout is preferred over [`RightToLeft`] if the left is unsplittable (single keyword like `return` or a Name) + /// because it has better performance characteristics. + LeftToRight { + /// The right side of an assignment or the value returned in a return statement. + value: &'a Expr, + + /// The parent statement that encloses the `value` expression. + statement: AnyNodeRef<'a>, + }, + + /// Prefers parenthesizing the value before splitting the left side. Specific to assignments. + /// + /// Formats what's left of `value` together with the assignment operator and the assigned `value`. + /// This layout prefers parenthesizing the value over parenthesizing the left (target or type annotation): + /// + /// ```python + /// aaaaaaa[bbbbbbbb] = some_long_value + /// ``` + /// + /// gets formatted to... + /// + /// ```python + /// aaaaaaa[bbbbbbbb] = ( + /// some_long_value + /// ) + /// ``` + /// + /// ... regardless whether the value will fit or not. + /// + /// The left only gets parenthesized if the left exceeds the configured line width on its own or + /// is forced to split because of a magical trailing comma or contains comments: + /// + /// ```python + /// aaaaaaa[bbbbbbbb_exceeds_the_line_width] = some_long_value + /// ``` + /// + /// gets formatted to + /// ```python + /// aaaaaaa[ + /// bbbbbbbb_exceeds_the_line_width + /// ] = some_long_value + /// ``` + /// + /// The layout avoids parenthesizing the value when the left splits to avoid + /// unnecessary parentheses. Adding the parentheses, as shown in the below example, reduces readability. + /// + /// ```python + /// aaaaaaa[ + /// bbbbbbbb_exceeds_the_line_width + /// ] = ( + /// some_long_value + /// ) + /// + /// ## Non-fluent Call Expressions + /// Non-fluent call expressions in the `value` position are only parenthesized if the opening parentheses + /// exceeds the configured line length. The layout prefers splitting after the opening parentheses + /// if the `callee` expression and the opening parentheses fit. + /// fits on the line. + RightToLeft { + /// The expression that comes before the assignment operator. This is either + /// the last target, or the type annotation of an annotated assignment. + before_operator: AnyBeforeOperator<'a>, + + /// The assignment operator. Either `Assign` (`=`) or the operator used by the augmented assignment statement. + operator: AnyAssignmentOperator, + + /// The assigned `value`. + value: &'a Expr, + + /// The assignment statement. + statement: AnyNodeRef<'a>, + }, } impl<'a> FormatStatementsLastExpression<'a> { - pub(super) fn new>>(expression: &'a Expr, parent: P) -> Self { - Self { - expression, - parent: parent.into(), + pub(super) fn left_to_right>>(value: &'a Expr, statement: S) -> Self { + Self::LeftToRight { + value, + statement: statement.into(), } } } impl Format> for FormatStatementsLastExpression<'_> { fn fmt(&self, f: &mut Formatter>) -> FormatResult<()> { - let can_inline_comment = match self.expression { - Expr::Name(_) - | Expr::NoneLiteral(_) - | Expr::NumberLiteral(_) - | Expr::BooleanLiteral(_) => true, - Expr::StringLiteral(string) => { - string.needs_parentheses(self.parent, f.context()) == OptionalParentheses::BestFit - } - Expr::BytesLiteral(bytes) => { - bytes.needs_parentheses(self.parent, f.context()) == OptionalParentheses::BestFit - } - Expr::FString(fstring) => { - fstring.needs_parentheses(self.parent, f.context()) == OptionalParentheses::BestFit - } - _ => false, - }; + match self { + FormatStatementsLastExpression::LeftToRight { value, statement } => { + let can_inline_comment = should_inline_comments(value, *statement, f.context()); + + if !can_inline_comment { + return maybe_parenthesize_expression( + value, + *statement, + Parenthesize::IfBreaks, + ) + .fmt(f); + } - if !can_inline_comment { - return maybe_parenthesize_expression( - self.expression, - self.parent, - Parenthesize::IfBreaks, - ) - .fmt(f); - } + let comments = f.context().comments().clone(); + let expression_comments = comments.leading_dangling_trailing(*value); - let comments = f.context().comments().clone(); - let expression_comments = comments.leading_dangling_trailing(self.expression); + if let Some(inline_comments) = OptionalParenthesesInlinedComments::new( + &expression_comments, + *statement, + &comments, + ) { + let group_id = f.group_id("optional_parentheses"); - if expression_comments.has_leading() { - // Preserve the parentheses if the expression has any leading comments, - // same as `maybe_parenthesize_expression` - return self - .expression - .format() - .with_options(Parentheses::Always) - .fmt(f); - } + let f = &mut WithNodeLevel::new(NodeLevel::Expression(Some(group_id)), f); - let statement_trailing_comments = comments.trailing(self.parent); - let after_end_of_line = statement_trailing_comments - .partition_point(|comment| comment.line_position().is_end_of_line()); - let (stmt_inline_comments, _) = statement_trailing_comments.split_at(after_end_of_line); + best_fit_parenthesize(&format_with(|f| { + inline_comments.mark_formatted(); - let after_end_of_line = expression_comments - .trailing - .partition_point(|comment| comment.line_position().is_end_of_line()); + value.format().with_options(Parentheses::Never).fmt(f)?; - let (expression_inline_comments, expression_trailing_comments) = - expression_comments.trailing.split_at(after_end_of_line); + if !inline_comments.is_empty() { + // If the expressions exceeds the line width, format the comments in the parentheses + if_group_breaks(&inline_comments).fmt(f)?; + } - if expression_trailing_comments.is_empty() { - let inline_comments = OptionalParenthesesInlinedComments { - expression: expression_inline_comments, - statement: stmt_inline_comments, - }; + Ok(()) + })) + .with_group_id(Some(group_id)) + .fmt(f)?; - let group_id = f.group_id("optional_parentheses"); - let f = &mut WithNodeLevel::new(NodeLevel::Expression(Some(group_id)), f); + if !inline_comments.is_empty() { + // If the line fits into the line width, format the comments after the parenthesized expression + if_group_fits_on_line(&inline_comments) + .with_group_id(Some(group_id)) + .fmt(f)?; + } - best_fit_parenthesize(&format_with(|f| { - inline_comments.mark_formatted(); + Ok(()) + } else { + // Preserve the parentheses if the expression has any leading or trailing comments, + // to avoid syntax errors, similar to `maybe_parenthesize_expression`. + value.format().with_options(Parentheses::Always).fmt(f) + } + } + FormatStatementsLastExpression::RightToLeft { + before_operator, + operator, + value, + statement, + } => { + let should_inline_comments = should_inline_comments(value, *statement, f.context()); + + // Use the normal `maybe_parenthesize_layout` for splittable `value`s. + if !should_inline_comments + && !should_non_inlineable_use_best_fit(value, *statement, f.context()) + { + return write!( + f, + [ + before_operator, + space(), + operator, + space(), + maybe_parenthesize_expression( + value, + *statement, + Parenthesize::IfBreaks + ) + ] + ); + } - self.expression - .format() - .with_options(Parentheses::Never) - .fmt(f)?; + let comments = f.context().comments().clone(); + let expression_comments = comments.leading_dangling_trailing(*value); + + // Don't inline comments for attribute and call expressions for black compatibility + let inline_comments = if should_inline_comments { + OptionalParenthesesInlinedComments::new( + &expression_comments, + *statement, + &comments, + ) + } else if expression_comments.has_leading() + || expression_comments.has_trailing_own_line() + { + None + } else { + Some(OptionalParenthesesInlinedComments::default()) + }; + + let Some(inline_comments) = inline_comments else { + // Preserve the parentheses if the expression has any leading or trailing own line comments + // same as `maybe_parenthesize_expression` + return write!( + f, + [ + before_operator, + space(), + operator, + space(), + value.format().with_options(Parentheses::Always) + ] + ); + }; + + // Prevent inline comments to be formatted as part of the expression. + inline_comments.mark_formatted(); - if !inline_comments.is_empty() { - // If the expressions exceeds the line width, format the comments in the parentheses - if_group_breaks(&inline_comments) - .with_group_id(Some(group_id)) - .fmt(f)?; + let mut last_target = before_operator.memoized(); + + // Don't parenthesize the `value` if it is known that the target will break. + // This is mainly a performance optimisation that avoids unnecessary memoization + // and using the costly `BestFitting` layout if it is already known that only the last variant + // can ever fit because the left breaks. + if last_target.inspect(f)?.will_break() { + return write!( + f, + [ + last_target, + space(), + operator, + space(), + value.format().with_options(Parentheses::Never), + inline_comments + ] + ); } - Ok(()) - })) - .with_group_id(Some(group_id)) - .fmt(f)?; - - if !inline_comments.is_empty() { - // If the line fits into the line width, format the comments after the parenthesized expression - if_group_fits_on_line(&inline_comments) - .with_group_id(Some(group_id)) - .fmt(f)?; + let format_value = value.format().with_options(Parentheses::Never).memoized(); + + // Tries to fit the `left` and the `value` on a single line: + // ```python + // a = b = c + // ``` + let format_flat = format_with(|f| { + write!( + f, + [ + last_target, + space(), + operator, + space(), + format_value, + inline_comments + ] + ) + }); + + // Don't break the last assignment target but parenthesize the value to see if it fits (break right first). + // + // ```python + // a["bbbbb"] = ( + // c + // ) + // ``` + let format_parenthesize_value = format_with(|f| { + write!( + f, + [ + last_target, + space(), + operator, + space(), + token("("), + block_indent(&format_args![format_value, inline_comments]), + token(")") + ] + ) + }); + + // Fall back to parenthesizing (or splitting) the last target part if we can't make the value + // fit. Don't parenthesize the value to avoid unnecessary parentheses. + // + // ```python + // a[ + // "bbbbb" + // ] = c + // ``` + let format_split_left = format_with(|f| { + write!( + f, + [ + last_target, + space(), + operator, + space(), + format_value, + inline_comments + ] + ) + }); + + // For call expressions, prefer breaking after the call expression's opening parentheses + // over parenthesizing the entire call expression. + if value.is_call_expr() { + best_fitting![ + format_flat, + // Avoid parenthesizing the call expression if the `(` fit on the line + format_args![ + last_target, + space(), + operator, + space(), + group(&format_value).should_expand(true), + ], + format_parenthesize_value, + format_split_left + ] + .fmt(f) + } else { + best_fitting![format_flat, format_parenthesize_value, format_split_left].fmt(f) + } } - - Ok(()) - } else { - self.expression - .format() - .with_options(Parentheses::Always) - .fmt(f) } } } @@ -283,6 +584,35 @@ struct OptionalParenthesesInlinedComments<'a> { } impl<'a> OptionalParenthesesInlinedComments<'a> { + fn new( + expression_comments: &LeadingDanglingTrailingComments<'a>, + statement: AnyNodeRef<'a>, + comments: &'a Comments<'a>, + ) -> Option { + if expression_comments.has_leading() || expression_comments.has_trailing_own_line() { + return None; + } + + let statement_trailing_comments = comments.trailing(statement); + let after_end_of_line = statement_trailing_comments + .partition_point(|comment| comment.line_position().is_end_of_line()); + let (stmt_inline_comments, _) = statement_trailing_comments.split_at(after_end_of_line); + + let after_end_of_line = expression_comments + .trailing + .partition_point(|comment| comment.line_position().is_end_of_line()); + + let (expression_inline_comments, trailing_own_line_comments) = + expression_comments.trailing.split_at(after_end_of_line); + + debug_assert!(trailing_own_line_comments.is_empty(), "The method should have returned early if the expression has trailing own line comments"); + + Some(OptionalParenthesesInlinedComments { + expression: expression_inline_comments, + statement: stmt_inline_comments, + }) + } + fn is_empty(&self) -> bool { self.expression.is_empty() && self.statement.is_empty() } @@ -313,3 +643,97 @@ impl Format> for OptionalParenthesesInlinedComments<'_> { ) } } + +#[derive(Copy, Clone, Debug)] +pub(super) enum AnyAssignmentOperator { + Assign, + AugAssign(Operator), +} + +impl Format> for AnyAssignmentOperator { + fn fmt(&self, f: &mut Formatter>) -> FormatResult<()> { + match self { + AnyAssignmentOperator::Assign => token("=").fmt(f), + AnyAssignmentOperator::AugAssign(operator) => { + write!(f, [operator.format(), token("=")]) + } + } + } +} + +#[derive(Copy, Clone, Debug)] +pub(super) enum AnyBeforeOperator<'a> { + Expression(&'a Expr), + TypeParams(&'a TypeParams), +} + +impl Format> for AnyBeforeOperator<'_> { + fn fmt(&self, f: &mut Formatter>) -> FormatResult<()> { + match self { + AnyBeforeOperator::Expression(expression) => { + // Preserve parentheses around targets with comments. + if f.context().comments().has_leading(*expression) + || f.context().comments().has_trailing(*expression) + { + expression + .format() + .with_options(Parentheses::Preserve) + .fmt(f) + } + // Never parenthesize targets that come with their own parentheses, e.g. don't parenthesize lists or dictionary literals. + else if has_target_own_parentheses(expression, f.context()) { + expression.format().with_options(Parentheses::Never).fmt(f) + } else { + parenthesize_if_expands(&expression.format().with_options(Parentheses::Never)) + .fmt(f) + } + } + // Never parenthesize type params + AnyBeforeOperator::TypeParams(type_params) => type_params.format().fmt(f), + } + } +} + +/// Returns `true` for unsplittable expressions for which comments should be inlined. +fn should_inline_comments( + expression: &Expr, + parent: AnyNodeRef, + context: &PyFormatContext, +) -> bool { + match expression { + Expr::Name(_) | Expr::NoneLiteral(_) | Expr::NumberLiteral(_) | Expr::BooleanLiteral(_) => { + true + } + Expr::StringLiteral(string) => { + string.needs_parentheses(parent, context) == OptionalParentheses::BestFit + } + Expr::BytesLiteral(bytes) => { + bytes.needs_parentheses(parent, context) == OptionalParentheses::BestFit + } + Expr::FString(fstring) => { + fstring.needs_parentheses(parent, context) == OptionalParentheses::BestFit + } + _ => false, + } +} + +/// Tests whether an expression that for which comments shouldn't be inlined should use the best fit layout +fn should_non_inlineable_use_best_fit( + expr: &Expr, + parent: AnyNodeRef, + context: &PyFormatContext, +) -> bool { + match expr { + Expr::Attribute(attribute) => { + attribute.needs_parentheses(parent, context) == OptionalParentheses::BestFit + } + Expr::Call(call) => call.needs_parentheses(parent, context) == OptionalParentheses::BestFit, + _ => false, + } +} + +/// Returns `true` for targets that should not be parenthesized if they split because their expanded +/// layout comes with their own set of parentheses. +pub(super) fn has_target_own_parentheses(target: &Expr, context: &PyFormatContext) -> bool { + matches!(target, Expr::Tuple(_)) || has_own_parentheses(target, context).is_some() +} diff --git a/crates/ruff_python_formatter/src/statement/stmt_aug_assign.rs b/crates/ruff_python_formatter/src/statement/stmt_aug_assign.rs index 19202ecf0f982..003c10a32a8e1 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_aug_assign.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_aug_assign.rs @@ -2,8 +2,13 @@ use ruff_formatter::write; use ruff_python_ast::StmtAugAssign; use crate::comments::{SourceComment, SuppressionKind}; +use crate::expression::parentheses::is_expression_parenthesized; use crate::prelude::*; -use crate::statement::stmt_assign::FormatStatementsLastExpression; +use crate::preview::is_prefer_splitting_right_hand_side_of_assignments_enabled; +use crate::statement::stmt_assign::{ + has_target_own_parentheses, AnyAssignmentOperator, AnyBeforeOperator, + FormatStatementsLastExpression, +}; use crate::statement::trailing_semicolon; use crate::{AsFormat, FormatNodeRule}; @@ -18,17 +23,35 @@ impl FormatNodeRule for FormatStmtAugAssign { value, range: _, } = item; - write!( - f, - [ - target.format(), - space(), - op.format(), - token("="), - space(), - FormatStatementsLastExpression::new(value, item) - ] - )?; + + if is_prefer_splitting_right_hand_side_of_assignments_enabled(f.context()) + && has_target_own_parentheses(target, f.context()) + && !is_expression_parenthesized( + target.into(), + f.context().comments().ranges(), + f.context().source(), + ) + { + FormatStatementsLastExpression::RightToLeft { + before_operator: AnyBeforeOperator::Expression(target), + operator: AnyAssignmentOperator::AugAssign(*op), + value, + statement: item.into(), + } + .fmt(f)?; + } else { + write!( + f, + [ + target.format(), + space(), + op.format(), + token("="), + space(), + FormatStatementsLastExpression::left_to_right(value, item) + ] + )?; + } if f.options().source_type().is_ipynb() && f.context().node_level().is_last_top_level_statement() diff --git a/crates/ruff_python_formatter/src/statement/stmt_return.rs b/crates/ruff_python_formatter/src/statement/stmt_return.rs index b0c5253e0fa38..4eaa3d92613ab 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_return.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_return.rs @@ -30,7 +30,10 @@ impl FormatNodeRule for FormatStmtReturn { Some(value) => { write!( f, - [space(), FormatStatementsLastExpression::new(value, item)] + [ + space(), + FormatStatementsLastExpression::left_to_right(value, item) + ] ) } None => Ok(()), diff --git a/crates/ruff_python_formatter/src/statement/stmt_type_alias.rs b/crates/ruff_python_formatter/src/statement/stmt_type_alias.rs index 6376236afb7d1..b6ae69b4430af 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_type_alias.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_type_alias.rs @@ -3,7 +3,10 @@ use ruff_python_ast::StmtTypeAlias; use crate::comments::{SourceComment, SuppressionKind}; use crate::prelude::*; -use crate::statement::stmt_assign::FormatStatementsLastExpression; +use crate::preview::is_prefer_splitting_right_hand_side_of_assignments_enabled; +use crate::statement::stmt_assign::{ + AnyAssignmentOperator, AnyBeforeOperator, FormatStatementsLastExpression, +}; #[derive(Default)] pub struct FormatStmtTypeAlias; @@ -20,6 +23,16 @@ impl FormatNodeRule for FormatStmtTypeAlias { write!(f, [token("type"), space(), name.as_ref().format()])?; if let Some(type_params) = type_params { + if is_prefer_splitting_right_hand_side_of_assignments_enabled(f.context()) { + return FormatStatementsLastExpression::RightToLeft { + before_operator: AnyBeforeOperator::TypeParams(type_params), + operator: AnyAssignmentOperator::Assign, + value, + statement: item.into(), + } + .fmt(f); + }; + write!(f, [type_params.format()])?; } @@ -29,7 +42,7 @@ impl FormatNodeRule for FormatStmtTypeAlias { space(), token("="), space(), - FormatStatementsLastExpression::new(value, item) + FormatStatementsLastExpression::left_to_right(value, item) ] ) } diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pep604_union_types_line_breaks.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pep604_union_types_line_breaks.py.snap index 278a20e4a6650..bf6f676be094e 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pep604_union_types_line_breaks.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__pep604_union_types_line_breaks.py.snap @@ -95,7 +95,7 @@ def f( ```diff --- Black +++ Ruff -@@ -7,26 +7,16 @@ +@@ -7,23 +7,13 @@ ) # "AnnAssign"s now also work @@ -120,16 +120,10 @@ def f( - | Loooooooooooooooooooooooong - | Loooooooooooooooooooooooong -) = 7 --z: Short | Short2 | Short3 | Short4 = 8 --z: int = 2.3 --z: int = foo() +z: Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong = 7 -+z: (Short | Short2 | Short3 | Short4) = 8 -+z: (int) = 2.3 -+z: (int) = foo() - - # In case I go for not enforcing parantheses, this might get improved at the same time - x = ( + z: Short | Short2 | Short3 | Short4 = 8 + z: int = 2.3 + z: int = foo() @@ -63,7 +53,7 @@ @@ -186,9 +180,9 @@ z: (int) z: Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong | Loooooooooooooooooooooooong = 7 -z: (Short | Short2 | Short3 | Short4) = 8 -z: (int) = 2.3 -z: (int) = foo() +z: Short | Short2 | Short3 | Short4 = 8 +z: int = 2.3 +z: int = foo() # In case I go for not enforcing parantheses, this might get improved at the same time x = ( diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings.py.snap index b3a03820fa4ca..a589aeffed92e 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings.py.snap @@ -789,14 +789,12 @@ log.info(f"""Skipping: {'a' == 'b'} {desc['ms_name']} {money=} {dte=} {pos_share - "This is a large string that has a type annotation attached to it. A type" - " annotation should NOT stop a long string from being wrapped." -) --annotated_variable: Literal["fakse_literal"] = ( ++annotated_variable: Final = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped." + annotated_variable: Literal["fakse_literal"] = ( - "This is a large string that has a type annotation attached to it. A type" - " annotation should NOT stop a long string from being wrapped." --) -+annotated_variable: Final = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped." -+annotated_variable: Literal[ -+ "fakse_literal" -+] = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped." ++ "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped." + ) -backslashes = ( - "This is a really long string with \"embedded\" double quotes and 'single' quotes" @@ -1308,9 +1306,9 @@ annotated_variable: Final = ( + "using the '+' operator." ) annotated_variable: Final = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped." -annotated_variable: Literal[ - "fakse_literal" -] = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped." +annotated_variable: Literal["fakse_literal"] = ( + "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped." +) backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\" backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\\\" diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__regression.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__regression.py.snap index 1cde924609d48..762af6aa16c7e 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__regression.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_long_strings__regression.py.snap @@ -832,7 +832,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: some_commented_string = ( # This comment stays at the top. "This string is long but not so long that it needs hahahah toooooo be so greatttt" -@@ -279,38 +280,27 @@ +@@ -279,36 +280,25 @@ ) lpar_and_rpar_have_comments = func_call( # LPAR Comment @@ -852,33 +852,31 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: - f" {'' if ID is None else ID} | perl -nE 'print if /^{field}:/'" -) +cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {'' if ID is None else ID} | perl -nE 'print if /^{field}:/'" -+ -+cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {'{{}}' if ID is None else ID} | perl -nE 'print if /^{field}:/'" -cmd_fstring = ( - "sudo -E deluge-console info --detailed --sort-reverse=time_added" - f" {'{{}}' if ID is None else ID} | perl -nE 'print if /^{field}:/'" -) -+cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {{'' if ID is None else ID}} | perl -nE 'print if /^{field}:/'" ++cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {'{{}}' if ID is None else ID} | perl -nE 'print if /^{field}:/'" -cmd_fstring = ( - "sudo -E deluge-console info --detailed --sort-reverse=time_added {'' if ID is" - f" None else ID}} | perl -nE 'print if /^{field}:/'" -) -+fstring = f"This string really doesn't need to be an {{{{fstring}}}}, but this one most certainly, absolutely {does}." ++cmd_fstring = f"sudo -E deluge-console info --detailed --sort-reverse=time_added {{'' if ID is None else ID}} | perl -nE 'print if /^{field}:/'" ++fstring = f"This string really doesn't need to be an {{{{fstring}}}}, but this one most certainly, absolutely {does}." ++ fstring = ( - "This string really doesn't need to be an {{fstring}}, but this one most" - f" certainly, absolutely {does}." + f"We have to remember to escape {braces}." " Like {these}." f" But not {this}." ) - +- -fstring = f"We have to remember to escape {braces}. Like {{these}}. But not {this}." -- + class A: - class B: - def foo(): @@ -364,10 +354,7 @@ def foo(): if not hasattr(module, name): @@ -933,7 +931,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: ) -@@ -432,14 +415,12 @@ +@@ -432,9 +415,7 @@ assert xxxxxxx_xxxx in [ x.xxxxx.xxxxxx.xxxxx.xxxxxx, x.xxxxx.xxxxxx.xxxxx.xxxx, @@ -943,15 +941,7 @@ s = f'Lorem Ipsum is simply dummy text of the printing and typesetting industry: + ], "xxxxxxxxxxx xxxxxxx xxxx (xxxxxx xxxx) %x xxx xxxxx" % xxxxxxx_xxxx --value.__dict__[key] = ( -- "test" # set some Thrift field to non-None in the struct aa bb cc dd ee --) -+value.__dict__[ -+ key -+] = "test" # set some Thrift field to non-None in the struct aa bb cc dd ee - - RE_ONE_BACKSLASH = { - "asdf_hjkl_jkl": re.compile( + value.__dict__[key] = ( @@ -449,8 +430,7 @@ RE_TWO_BACKSLASHES = { @@ -1627,9 +1617,9 @@ class xxxxxxxxxxxxxxxxxxxxx(xxxx.xxxxxxxxxxxxx): ], "xxxxxxxxxxx xxxxxxx xxxx (xxxxxx xxxx) %x xxx xxxxx" % xxxxxxx_xxxx -value.__dict__[ - key -] = "test" # set some Thrift field to non-None in the struct aa bb cc dd ee +value.__dict__[key] = ( + "test" # set some Thrift field to non-None in the struct aa bb cc dd ee +) RE_ONE_BACKSLASH = { "asdf_hjkl_jkl": re.compile( diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_prefer_rhs_split.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_prefer_rhs_split.py.snap index 18b9fa9a06268..e799efc3145f6 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_prefer_rhs_split.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_prefer_rhs_split.py.snap @@ -118,57 +118,7 @@ a = ( ```diff --- Black +++ Ruff -@@ -1,29 +1,31 @@ --first_item, second_item = ( -- some_looooooooong_module.some_looooooooooooooong_function_name( -- first_argument, second_argument, third_argument -- ) -+( -+ first_item, -+ second_item, -+) = some_looooooooong_module.some_looooooooooooooong_function_name( -+ first_argument, second_argument, third_argument - ) - --some_dict["with_a_long_key"] = ( -- some_looooooooong_module.some_looooooooooooooong_function_name( -- first_argument, second_argument, third_argument -- ) -+some_dict[ -+ "with_a_long_key" -+] = some_looooooooong_module.some_looooooooooooooong_function_name( -+ first_argument, second_argument, third_argument - ) - - # Make sure it works when the RHS only has one pair of (optional) parens. --first_item, second_item = ( -- some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name --) -+( -+ first_item, -+ second_item, -+) = some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name - --some_dict["with_a_long_key"] = ( -- some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name --) -+some_dict[ -+ "with_a_long_key" -+] = some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name - - # Make sure chaining assignments work. --first_item, second_item, third_item, forth_item = m["everything"] = ( -- some_looooooooong_module.some_looooooooooooooong_function_name( -- first_argument, second_argument, third_argument -- ) -+first_item, second_item, third_item, forth_item = m[ -+ "everything" -+] = some_looooooooong_module.some_looooooooooooooong_function_name( -+ first_argument, second_argument, third_argument - ) - - # Make sure when the RHS's first split at the non-optional paren fits, -@@ -60,9 +62,7 @@ +@@ -60,9 +60,7 @@ some_arg ).intersection(pk_cols) @@ -179,76 +129,37 @@ a = ( some_kind_of_table[ some_key # type: ignore # noqa: E501 -@@ -85,15 +85,29 @@ - ) - - # Multiple targets --a = b = ( -- ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc --) -+a = ( -+ b -+) = ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc - --a = b = c = d = e = f = g = ( -+a = ( -+ b -+) = ( -+ c -+) = ( -+ d -+) = ( -+ e -+) = ( -+ f -+) = ( -+ g -+) = ( - hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh --) = i = j = ( -- kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk --) -+) = ( -+ i -+) = ( -+ j -+) = kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk - - a = ( - bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb ``` ## Ruff Output ```python -( - first_item, - second_item, -) = some_looooooooong_module.some_looooooooooooooong_function_name( - first_argument, second_argument, third_argument +first_item, second_item = ( + some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument + ) ) -some_dict[ - "with_a_long_key" -] = some_looooooooong_module.some_looooooooooooooong_function_name( - first_argument, second_argument, third_argument +some_dict["with_a_long_key"] = ( + some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument + ) ) # Make sure it works when the RHS only has one pair of (optional) parens. -( - first_item, - second_item, -) = some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name +first_item, second_item = ( + some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name +) -some_dict[ - "with_a_long_key" -] = some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name +some_dict["with_a_long_key"] = ( + some_looooooooong_module.SomeClass.some_looooooooooooooong_variable_name +) # Make sure chaining assignments work. -first_item, second_item, third_item, forth_item = m[ - "everything" -] = some_looooooooong_module.some_looooooooooooooong_function_name( - first_argument, second_argument, third_argument +first_item, second_item, third_item, forth_item = m["everything"] = ( + some_looooooooong_module.some_looooooooooooooong_function_name( + first_argument, second_argument, third_argument + ) ) # Make sure when the RHS's first split at the non-optional paren fits, @@ -308,29 +219,15 @@ some_kind_of_instance.some_kind_of_map[a_key] = ( ) # Multiple targets -a = ( - b -) = ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +a = b = ( + ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +) -a = ( - b -) = ( - c -) = ( - d -) = ( - e -) = ( - f -) = ( - g -) = ( +a = b = c = d = e = f = g = ( hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh -) = ( - i -) = ( - j -) = kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk +) = i = j = ( + kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk +) a = ( bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__optional_parentheses_comments.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__optional_parentheses_comments.py.snap index 4279cd03f29db..23c95ef3a2756 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__optional_parentheses_comments.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__optional_parentheses_comments.py.snap @@ -421,4 +421,44 @@ def test6(): ``` +## Preview changes +```diff +--- Stable ++++ Preview +@@ -72,13 +72,13 @@ + ## Breaking left + + # Should break `[a]` first +-____[ +- a +-] = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # c ++____[a] = ( ++ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # c ++) + +-____[ +- a +-] = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # cc ++____[a] = ( ++ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvv # cc ++) + + ( + # some weird comments +@@ -136,9 +136,9 @@ + # 89 characters parenthesized (collapse) + ____a: a = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c + +-_a: a[ +- b +-] = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c ++_a: a[b] = ( ++ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvv # c ++) + + ## Augmented Assign + +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap index eedd65bade86d..eea51abf01ce3 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap @@ -204,17 +204,17 @@ class RemoveNewlineBeforeClassDocstring: def f(): """Black's `Preview.prefer_splitting_right_hand_side_of_assignments`""" - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[ - bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb - ] = cccccccc.ccccccccccccc.cccccccc + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = ( + cccccccc.ccccccccccccc.cccccccc + ) - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[ - bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb - ] = cccccccc.ccccccccccccc().cccccccc + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = ( + cccccccc.ccccccccccccc().cccccccc + ) - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[ - bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb - ] = cccccccc.ccccccccccccc(d).cccccccc + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = ( + cccccccc.ccccccccccccc(d).cccccccc + ) aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = ( cccccccc.ccccccccccccc(d).cccccccc + e @@ -228,12 +228,12 @@ def f(): + eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee ) - self._cache: dict[ - DependencyCacheKey, list[list[DependencyPackage]] - ] = collections.defaultdict(list) - self._cached_dependencies_by_level: dict[ - int, list[DependencyCacheKey] - ] = collections.defaultdict(list) + self._cache: dict[DependencyCacheKey, list[list[DependencyPackage]]] = ( + collections.defaultdict(list) + ) + self._cached_dependencies_by_level: dict[int, list[DependencyCacheKey]] = ( + collections.defaultdict(list) + ) ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__ann_assign.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__ann_assign.py.snap index 69490f3caf53c..191b6d141bb42 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__ann_assign.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__ann_assign.py.snap @@ -67,4 +67,24 @@ class DefaultRunner: ``` +## Preview changes +```diff +--- Stable ++++ Preview +@@ -7,9 +7,9 @@ + Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb() + ) + +-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: ( +- Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +-) = Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb() ++bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = ( ++ Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb() ++) + + JSONSerializable: TypeAlias = ( + "str | int | float | bool | None | list | tuple | JSONMapping" +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__assign.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__assign.py.snap index 203d43b643802..b78a7687774c4 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__assign.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__assign.py.snap @@ -169,4 +169,40 @@ c = b[dddddd, aaaaaa] = ( ``` +## Preview changes +```diff +--- Stable ++++ Preview +@@ -1,7 +1,5 @@ + # break left hand side +-a1akjdshflkjahdslkfjlasfdahjlfds = ( +- bakjdshflkjahdslkfjlasfdahjlfds +-) = ( ++a1akjdshflkjahdslkfjlasfdahjlfds = bakjdshflkjahdslkfjlasfdahjlfds = ( + cakjdshflkjahdslkfjlasfdahjlfds + ) = kjaödkjaföjfahlfdalfhaöfaöfhaöfha = fkjaödkjaföjfahlfdalfhaöfaöfhaöfha = g = 3 + +@@ -9,15 +7,13 @@ + a2 = b2 = 2 + + # Break the last element +-a = ( +- asdf +-) = ( ++a = asdf = ( + fjhalsdljfalflaflapamsakjsdhflakjdslfjhalsdljfalflaflapamsakjsdhflakjdslfjhalsdljfal + ) = 1 + +-aa = [ +- bakjdshflkjahdslkfjlasfdahjlfds +-] = dddd = ddd = fkjaödkjaföjfahlfdalfhaöfaöfhaöfha = g = [3] ++aa = [bakjdshflkjahdslkfjlasfdahjlfds] = dddd = ddd = ( ++ fkjaödkjaföjfahlfdalfhaöfaöfhaöfha ++) = g = [3] + + aa = [] = dddd = ddd = fkjaödkjaföjfahlfdalfhaöfaöfhaöfha = g = [3] + +``` + + diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__assignment_split_value_first.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__assignment_split_value_first.py.snap new file mode 100644 index 0000000000000..6fca0005232fd --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__assignment_split_value_first.py.snap @@ -0,0 +1,457 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/assignment_split_value_first.py +--- +## Input +```python +####### +# Unsplittable target and value + +# Only parenthesize the value if it makes it fit, otherwise avoid parentheses. +b = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvee + +bbbbbbbbbbbbbbbb = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvv + +# Avoid parenthesizing the value even if the target exceeds the configured width +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = bbb + + +############ +# Splittable targets + +# Does not double-parenthesize tuples +( + first_item, + second_item, +) = some_looooooooong_module.some_loooooog_function_name( + first_argument, second_argument, third_argument +) + + +# Preserve parentheses around the first target +( + req["ticket"]["steps"]["step"][0]["tasks"]["task"]["fields"]["field"][ + "access_request" + ]["destinations"]["destination"][0]["ip_address"] +) = dst + +# Augmented assignment +req["ticket"]["steps"]["step"][0]["tasks"]["task"]["fields"]["field"][ + "access_request" +] += dst + +# Always parenthesize the value if it avoids splitting the target, regardless of the value's width. +_a: a[aaaa] = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvv +) + +##### +# Avoid parenthesizing the value if the expression right before the `=` splits to avoid an unnecessary pair of parentheses + +# The type annotation is guaranteed to split because it is too long. +_a: a[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvv +] = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvv + +# The target is too long +( + aaaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvv + +# The target splits because of a magic trailing comma +( + a, + b, +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvvvv + +# The targets split because of a comment +( + # leading + a +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvvvv + +( + a + # trailing +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvvvv + +( + a, # nested + b +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvvvv + +####### +# Multi targets + +# Black always parenthesizes the right if using multiple targets regardless if the parenthesized value exceeds the +# the configured line width or not +aaaa = bbbbbbbbbbbbbbbb = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvee +) + +# Black does parenthesize the target if the target itself exceeds the line width and only parenthesizes +# the values if it makes it fit. +# The second target is too long to ever fit into the configured line width. +aaaa = ( + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbdddd +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvee + +# Does also apply for other multi target assignments, as soon as a single target exceeds the configured +# width +aaaaaa = a["aaa"] = bbbbb[aa, bbb, cccc] = dddddddddd = eeeeee = ( + fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + +###################### +# Call expressions: +# For unsplittable targets: Parenthesize the call expression if it makes it fit. +# +# For splittable targets: +# Only parenthesize a call expression if the parens of the call don't fit on the same line +# as the target. Don't parenthesize the call expression if the target (or annotation) right before +# splits. + +# Don't parenthesize the function call if the left is unsplittable. +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = a.b.function( + arg1, arg2, arg3 +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + [1, 2, 3], + arg1, + [1, 2, 3], + arg2, + [1, 2, 3], + arg3, + dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd, + eeeeeeeeeeeeee, +) + +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = ( + function() +) +this_is_a_ridiculously_long_name_and_nobodyddddddddddddddddddddddddddddddd = ( + a.b.function(arg1, arg2, arg3) +) +this_is_a_ridiculously_long_name_and_nobodyddddddddddddddddddddddddddddddd = function() +this_is_a_ridiculously_long_name_and_nobodyddddddddddddddddddddddddddddddd = function( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 +) +this_is_a_ridiculously_long_name_and_nobodyddddddddddddddddddddddddddddddd = function( + [1, 2, 3], + arg1, + [1, 2, 3], + arg2, + [1, 2, 3], + arg3, + dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd, + eeeeeeeeeeeeee, +) + +####### Fluent call expressions +# Uses the regular `Multiline` layout where the entire `value` gets parenthesized +# if it doesn't fit on the line. +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use = ( + function().b().c([1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3) +) + + +####### +# Test comment inlining +value.__dict__[key] = ( + "test" # set some Thrift field to non-None in the struct aa bb cc dd ee +) +value.__dict__.keye = ( + "test" # set some Thrift field to non-None in the struct aa bb cc dd ee +) +value.__dict__.keye = ( + "test" # set some Thrift field to non-None in the struct aa bb cc dd ee +) + + +# Don't parenthesize the value because the target's trailing comma forces it to split. +a[ + aaaaaaa, + b, +] = cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc # comment + +# Parenthesize the value, but don't duplicate the comment. +a[aaaaaaa, b] = ( + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc # comment +) + +# Format both as flat, but don't loos the comment. +a[aaaaaaa, b] = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb # comment + +####################################################### +# Test the case where a parenthesized value now fits: +a[ + aaaaaaa, + b +] = ( + cccccccc # comment +) + +# Splits the target but not the value because of the magic trailing comma. +a[ + aaaaaaa, + b, +] = ( + cccccccc # comment +) + +# Splits the second target because of the comment and the first target because of the trailing comma. +a[ + aaaaaaa, + b, +] = ( + # leading comment + b +) = ( + cccccccc # comment +) + + +######## +# Type Alias Statement +type A[str, int, number] = VeryLongTypeNameThatShouldBreakFirstToTheRightBeforeSplitngtin + +type A[VeryLongTypeNameThatShouldBreakFirstToTheRightBeforeSplitngtinthatExceedsTheWidth] = str + +``` + +## Outputs +### Output 1 +``` +indent-style = space +line-width = 88 +indent-width = 4 +quote-style = Double +line-ending = LineFeed +magic-trailing-comma = Respect +docstring-code = Disabled +docstring-code-line-width = 88 +preview = Enabled +``` + +```python +####### +# Unsplittable target and value + +# Only parenthesize the value if it makes it fit, otherwise avoid parentheses. +b = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvee + +bbbbbbbbbbbbbbbb = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvv +) + +# Avoid parenthesizing the value even if the target exceeds the configured width +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = bbb + + +############ +# Splittable targets + +# Does not double-parenthesize tuples +( + first_item, + second_item, +) = some_looooooooong_module.some_loooooog_function_name( + first_argument, second_argument, third_argument +) + + +# Preserve parentheses around the first target +( + req["ticket"]["steps"]["step"][0]["tasks"]["task"]["fields"]["field"][ + "access_request" + ]["destinations"]["destination"][0]["ip_address"] +) = dst + +# Augmented assignment +req["ticket"]["steps"]["step"][0]["tasks"]["task"]["fields"]["field"][ + "access_request" +] += dst + +# Always parenthesize the value if it avoids splitting the target, regardless of the value's width. +_a: a[aaaa] = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvv +) + +##### +# Avoid parenthesizing the value if the expression right before the `=` splits to avoid an unnecessary pair of parentheses + +# The type annotation is guaranteed to split because it is too long. +_a: a[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvv +] = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvv + +# The target is too long +( + aaaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvv + +# The target splits because of a magic trailing comma +( + a, + b, +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvvvv + +# The targets split because of a comment +( + # leading + a +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvvvv + +( + a + # trailing +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvvvv + +( + a, # nested + b, +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvvvv + +####### +# Multi targets + +# Black always parenthesizes the right if using multiple targets regardless if the parenthesized value exceeds the +# the configured line width or not +aaaa = bbbbbbbbbbbbbbbb = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvee +) + +# Black does parenthesize the target if the target itself exceeds the line width and only parenthesizes +# the values if it makes it fit. +# The second target is too long to ever fit into the configured line width. +aaaa = ( + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbdddd +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbvvvvvvvvvvvvvvvvvee + +# Does also apply for other multi target assignments, as soon as a single target exceeds the configured +# width +aaaaaa = a["aaa"] = bbbbb[aa, bbb, cccc] = dddddddddd = eeeeee = ( + fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + +###################### +# Call expressions: +# For unsplittable targets: Parenthesize the call expression if it makes it fit. +# +# For splittable targets: +# Only parenthesize a call expression if the parens of the call don't fit on the same line +# as the target. Don't parenthesize the call expression if the target (or annotation) right before +# splits. + +# Don't parenthesize the function call if the left is unsplittable. +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = a.b.function( + arg1, arg2, arg3 +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 +) +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function( + [1, 2, 3], + arg1, + [1, 2, 3], + arg2, + [1, 2, 3], + arg3, + dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd, + eeeeeeeeeeeeee, +) + +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = function() +this_is_a_ridiculously_long_name_and_nobodyddddddddddddddddddddddddddddddd = ( + a.b.function(arg1, arg2, arg3) +) +this_is_a_ridiculously_long_name_and_nobodyddddddddddddddddddddddddddddddd = function() +this_is_a_ridiculously_long_name_and_nobodyddddddddddddddddddddddddddddddd = function( + [1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3 +) +this_is_a_ridiculously_long_name_and_nobodyddddddddddddddddddddddddddddddd = function( + [1, 2, 3], + arg1, + [1, 2, 3], + arg2, + [1, 2, 3], + arg3, + dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd, + eeeeeeeeeeeeee, +) + +####### Fluent call expressions +# Uses the regular `Multiline` layout where the entire `value` gets parenthesized +# if it doesn't fit on the line. +this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use = ( + function().b().c([1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3) +) + + +####### +# Test comment inlining +value.__dict__[key] = ( + "test" # set some Thrift field to non-None in the struct aa bb cc dd ee +) +value.__dict__.keye = ( + "test" # set some Thrift field to non-None in the struct aa bb cc dd ee +) +value.__dict__.keye = ( + "test" # set some Thrift field to non-None in the struct aa bb cc dd ee +) + + +# Don't parenthesize the value because the target's trailing comma forces it to split. +a[ + aaaaaaa, + b, +] = cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc # comment + +# Parenthesize the value, but don't duplicate the comment. +a[aaaaaaa, b] = ( + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc # comment +) + +# Format both as flat, but don't loos the comment. +a[aaaaaaa, b] = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb # comment + +####################################################### +# Test the case where a parenthesized value now fits: +a[aaaaaaa, b] = cccccccc # comment + +# Splits the target but not the value because of the magic trailing comma. +a[ + aaaaaaa, + b, +] = cccccccc # comment + +# Splits the second target because of the comment and the first target because of the trailing comma. +a[ + aaaaaaa, + b, +] = ( + # leading comment + b +) = cccccccc # comment + + +######## +# Type Alias Statement +type A[str, int, number] = ( + VeryLongTypeNameThatShouldBreakFirstToTheRightBeforeSplitngtin +) + +type A[ + VeryLongTypeNameThatShouldBreakFirstToTheRightBeforeSplitngtinthatExceedsTheWidth +] = str +``` + + + From cb99815c3e6a9e22b97dcc8ad689abf568b9b3e0 Mon Sep 17 00:00:00 2001 From: Chris Hipple Date: Wed, 13 Dec 2023 00:33:19 -0500 Subject: [PATCH 178/197] Feature: Add SARIF output support (#9078) ## Summary Adds support for sarif v2.1.0 output to cli, usable via the output-format paramter. `ruff . --output-format=sarif` Includes a few changes I wasn't sure of, namely: * Adds a few derives for Clone & Copy, which I think could be removed with a little extra work as well. ## Test Plan I built and ran this against several large open source projects and verified that the output sarif was valid, using [Microsoft's SARIF validator tool](https://sarifweb.azurewebsites.net/Validation) I've also attached an output of the sarif generated by this version of ruff on the main branch of django at commit: b287af5dc9 [django_main_b287af5dc9_sarif.json](https://github.com/astral-sh/ruff/files/13626222/django_main_b287af5dc9_sarif.json) Note: this needs to be regenerated with the latest changes and confirmed. ## Open Points [ ] Convert to just using all Rules all the time [ ] Fix the issue with getting the file URI when compiling for web assembly --- Cargo.lock | 1 + crates/ruff_cli/src/printer.rs | 5 +- crates/ruff_linter/Cargo.toml | 1 + crates/ruff_linter/src/message/mod.rs | 2 + crates/ruff_linter/src/message/sarif.rs | 212 +++++++++++++++++++++++ crates/ruff_linter/src/settings/types.rs | 1 + docs/configuration.md | 2 +- ruff.schema.json | 3 +- 8 files changed, 224 insertions(+), 3 deletions(-) create mode 100644 crates/ruff_linter/src/message/sarif.rs diff --git a/Cargo.lock b/Cargo.lock index 9b71a65a67481..8b2225369f672 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2259,6 +2259,7 @@ dependencies = [ "typed-arena", "unicode-width", "unicode_names2", + "url", "wsl", ] diff --git a/crates/ruff_cli/src/printer.rs b/crates/ruff_cli/src/printer.rs index 228c124d68569..5bfdece63beaa 100644 --- a/crates/ruff_cli/src/printer.rs +++ b/crates/ruff_cli/src/printer.rs @@ -13,7 +13,7 @@ use ruff_linter::fs::relativize_path; use ruff_linter::logging::LogLevel; use ruff_linter::message::{ AzureEmitter, Emitter, EmitterContext, GithubEmitter, GitlabEmitter, GroupedEmitter, - JsonEmitter, JsonLinesEmitter, JunitEmitter, PylintEmitter, TextEmitter, + JsonEmitter, JsonLinesEmitter, JunitEmitter, PylintEmitter, SarifEmitter, TextEmitter, }; use ruff_linter::notify_user; use ruff_linter::registry::{AsRule, Rule}; @@ -291,6 +291,9 @@ impl Printer { SerializationFormat::Azure => { AzureEmitter.emit(writer, &diagnostics.messages, &context)?; } + SerializationFormat::Sarif => { + SarifEmitter.emit(writer, &diagnostics.messages, &context)?; + } } writer.flush()?; diff --git a/crates/ruff_linter/Cargo.toml b/crates/ruff_linter/Cargo.toml index fcbc1121a0912..60206ec2f42fc 100644 --- a/crates/ruff_linter/Cargo.toml +++ b/crates/ruff_linter/Cargo.toml @@ -71,6 +71,7 @@ toml = { workspace = true } typed-arena = { version = "2.0.2" } unicode-width = { workspace = true } unicode_names2 = { workspace = true } +url = { version = "2.2.2" } wsl = { version = "0.1.0" } [dev-dependencies] diff --git a/crates/ruff_linter/src/message/mod.rs b/crates/ruff_linter/src/message/mod.rs index 69f7241b04099..2f44de44eda71 100644 --- a/crates/ruff_linter/src/message/mod.rs +++ b/crates/ruff_linter/src/message/mod.rs @@ -17,6 +17,7 @@ use ruff_diagnostics::{Diagnostic, DiagnosticKind, Fix}; use ruff_notebook::NotebookIndex; use ruff_source_file::{SourceFile, SourceLocation}; use ruff_text_size::{Ranged, TextRange, TextSize}; +pub use sarif::SarifEmitter; pub use text::TextEmitter; mod azure; @@ -28,6 +29,7 @@ mod json; mod json_lines; mod junit; mod pylint; +mod sarif; mod text; #[derive(Debug, PartialEq, Eq)] diff --git a/crates/ruff_linter/src/message/sarif.rs b/crates/ruff_linter/src/message/sarif.rs new file mode 100644 index 0000000000000..3517c0eee335a --- /dev/null +++ b/crates/ruff_linter/src/message/sarif.rs @@ -0,0 +1,212 @@ +use std::io::Write; + +use anyhow::Result; +use serde::{Serialize, Serializer}; +use serde_json::json; + +use ruff_source_file::OneIndexed; + +use crate::codes::Rule; +use crate::fs::normalize_path; +use crate::message::{Emitter, EmitterContext, Message}; +use crate::registry::{AsRule, Linter, RuleNamespace}; +use crate::VERSION; + +use strum::IntoEnumIterator; + +pub struct SarifEmitter; + +impl Emitter for SarifEmitter { + fn emit( + &mut self, + writer: &mut dyn Write, + messages: &[Message], + _context: &EmitterContext, + ) -> Result<()> { + let results = messages + .iter() + .map(SarifResult::from_message) + .collect::>>()?; + + let output = json!({ + "$schema": "https://json.schemastore.org/sarif-2.1.0.json", + "version": "2.1.0", + "runs": [{ + "tool": { + "driver": { + "name": "ruff", + "informationUri": "https://github.com/astral-sh/ruff", + "rules": Rule::iter().map(SarifRule::from).collect::>(), + "version": VERSION.to_string(), + } + }, + "results": results, + }], + }); + serde_json::to_writer_pretty(writer, &output)?; + Ok(()) + } +} + +#[derive(Debug, Clone)] +struct SarifRule<'a> { + name: &'a str, + code: String, + linter: &'a str, + summary: &'a str, + explanation: Option<&'a str>, + url: Option, +} + +impl From for SarifRule<'_> { + fn from(rule: Rule) -> Self { + let code = rule.noqa_code().to_string(); + let (linter, _) = Linter::parse_code(&code).unwrap(); + Self { + name: rule.into(), + code, + linter: linter.name(), + summary: rule.message_formats()[0], + explanation: rule.explanation(), + url: rule.url(), + } + } +} + +impl Serialize for SarifRule<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + json!({ + "id": self.code, + "shortDescription": { + "text": self.summary, + }, + "fullDescription": { + "text": self.explanation, + }, + "help": { + "text": self.summary, + }, + "helpUri": self.url, + "properties": { + "id": self.code, + "kind": self.linter, + "name": self.name, + "problem.severity": "error".to_string(), + }, + }) + .serialize(serializer) + } +} + +#[derive(Debug)] +struct SarifResult { + rule: Rule, + level: String, + message: String, + uri: String, + start_line: OneIndexed, + start_column: OneIndexed, + end_line: OneIndexed, + end_column: OneIndexed, +} + +impl SarifResult { + #[cfg(not(target_arch = "wasm32"))] + fn from_message(message: &Message) -> Result { + let start_location = message.compute_start_location(); + let end_location = message.compute_end_location(); + let path = normalize_path(message.filename()); + Ok(Self { + rule: message.kind.rule(), + level: "error".to_string(), + message: message.kind.name.clone(), + uri: url::Url::from_file_path(&path) + .map_err(|()| anyhow::anyhow!("Failed to convert path to URL: {}", path.display()))? + .to_string(), + start_line: start_location.row, + start_column: start_location.column, + end_line: end_location.row, + end_column: end_location.column, + }) + } + + #[cfg(target_arch = "wasm32")] + #[allow(clippy::unnecessary_wraps)] + fn from_message(message: &Message) -> Result { + let start_location = message.compute_start_location(); + let end_location = message.compute_end_location(); + let path = normalize_path(message.filename()); + Ok(Self { + rule: message.kind.rule(), + level: "error".to_string(), + message: message.kind.name.clone(), + uri: path.display().to_string(), + start_line: start_location.row, + start_column: start_location.column, + end_line: end_location.row, + end_column: end_location.column, + }) + } +} + +impl Serialize for SarifResult { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + json!({ + "level": self.level, + "message": { + "text": self.message, + }, + "locations": [{ + "physicalLocation": { + "artifactLocation": { + "uri": self.uri, + }, + "region": { + "startLine": self.start_line, + "startColumn": self.start_column, + "endLine": self.end_line, + "endColumn": self.end_column, + } + } + }], + "ruleId": self.rule.noqa_code().to_string(), + }) + .serialize(serializer) + } +} + +#[cfg(test)] +mod tests { + + use crate::message::tests::{capture_emitter_output, create_messages}; + use crate::message::SarifEmitter; + + fn get_output() -> String { + let mut emitter = SarifEmitter {}; + capture_emitter_output(&mut emitter, &create_messages()) + } + + #[test] + fn valid_json() { + let content = get_output(); + serde_json::from_str::(&content).unwrap(); + } + + #[test] + fn test_results() { + let content = get_output(); + let sarif = serde_json::from_str::(content.as_str()).unwrap(); + let rules = sarif["runs"][0]["tool"]["driver"]["rules"] + .as_array() + .unwrap(); + let results = sarif["runs"][0]["results"].as_array().unwrap(); + assert_eq!(results.len(), 3); + assert!(rules.len() > 3); + } +} diff --git a/crates/ruff_linter/src/settings/types.rs b/crates/ruff_linter/src/settings/types.rs index 70ff7a9190f3f..10bfb5189ebc2 100644 --- a/crates/ruff_linter/src/settings/types.rs +++ b/crates/ruff_linter/src/settings/types.rs @@ -423,6 +423,7 @@ pub enum SerializationFormat { Gitlab, Pylint, Azure, + Sarif, } impl Default for SerializationFormat { diff --git a/docs/configuration.md b/docs/configuration.md index 08a33ffad2b34..32d6b2eb130fc 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -481,7 +481,7 @@ Options: --ignore-noqa Ignore any `# noqa` comments --output-format - Output serialization format for violations [env: RUFF_OUTPUT_FORMAT=] [possible values: text, json, json-lines, junit, grouped, github, gitlab, pylint, azure] + Output serialization format for violations [env: RUFF_OUTPUT_FORMAT=] [possible values: text, json, json-lines, junit, grouped, github, gitlab, pylint, azure, sarif] -o, --output-file Specify file to write the linter output to (default: stdout) --target-version diff --git a/ruff.schema.json b/ruff.schema.json index 8f67f9a12d787..d7ff44db9d7b0 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -3663,7 +3663,8 @@ "github", "gitlab", "pylint", - "azure" + "azure", + "sarif" ] }, "Strictness": { From 18452cf477390e849979df46dbceb88a8c3dfbe1 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Wed, 13 Dec 2023 00:31:20 -0600 Subject: [PATCH 179/197] Add `as_slice` method for all string nodes (#9111) This PR adds a `as_slice` method to all the string nodes which returns all the parts of the nodes as a slice. This will be useful in the next PR to split the string formatting to use this method to extract the _single node_ or _implicitly concanated nodes_. --- .../src/checkers/ast/analyze/expression.rs | 2 +- .../rules/hardcoded_sql_expression.rs | 2 +- .../flake8_pytest_style/rules/helpers.rs | 2 +- .../pylint/rules/assert_on_string_literal.rs | 4 +- .../tryceratops/rules/raise_vanilla_args.rs | 2 +- crates/ruff_python_ast/src/comparable.rs | 10 +- crates/ruff_python_ast/src/helpers.rs | 2 +- crates/ruff_python_ast/src/node.rs | 6 +- crates/ruff_python_ast/src/nodes.rs | 130 +++++++++++++----- crates/ruff_python_ast/src/visitor.rs | 6 +- .../src/visitor/transformer.rs | 6 +- crates/ruff_python_codegen/src/generator.rs | 6 +- .../src/expression/string/mod.rs | 6 +- 13 files changed, 120 insertions(+), 64 deletions(-) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index ee666e48c96d4..257db41db5413 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -1277,7 +1277,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { } Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { if checker.enabled(Rule::UnicodeKindPrefix) { - for string_part in value.parts() { + for string_part in value { pyupgrade::rules::unicode_kind_prefix(checker, string_part); } } diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs index 25d0f3e7103d4..ff892e6b3f962 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_sql_expression.rs @@ -57,7 +57,7 @@ impl Violation for HardcodedSQLExpression { /// becomes `foobar {x}baz`. fn concatenated_f_string(expr: &ast::ExprFString, locator: &Locator) -> String { expr.value - .parts() + .iter() .filter_map(|part| { raw_contents(locator.slice(part)).map(|s| s.escape_default().to_string()) }) diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs index 8bc9f4423b440..9ac12913539d9 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs @@ -56,7 +56,7 @@ pub(super) fn is_empty_or_null_string(expr: &Expr) -> bool { Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => value.is_empty(), Expr::NoneLiteral(_) => true, Expr::FString(ast::ExprFString { value, .. }) => { - value.parts().all(|f_string_part| match f_string_part { + value.iter().all(|f_string_part| match f_string_part { ast::FStringPart::Literal(literal) => literal.is_empty(), ast::FStringPart::FString(f_string) => f_string .elements diff --git a/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs b/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs index 034c9b3126a56..5f0801731f695 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs @@ -70,7 +70,7 @@ pub(crate) fn assert_on_string_literal(checker: &mut Checker, test: &Expr) { )); } Expr::FString(ast::ExprFString { value, .. }) => { - let kind = if value.parts().all(|f_string_part| match f_string_part { + let kind = if value.iter().all(|f_string_part| match f_string_part { ast::FStringPart::Literal(literal) => literal.is_empty(), ast::FStringPart::FString(f_string) => { f_string.elements.iter().all(|element| match element { @@ -82,7 +82,7 @@ pub(crate) fn assert_on_string_literal(checker: &mut Checker, test: &Expr) { } }) { Kind::Empty - } else if value.parts().any(|f_string_part| match f_string_part { + } else if value.iter().any(|f_string_part| match f_string_part { ast::FStringPart::Literal(literal) => !literal.is_empty(), ast::FStringPart::FString(f_string) => { f_string.elements.iter().any(|element| match element { diff --git a/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs b/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs index bb35bd8cdc7da..b50d6fd7e7ef0 100644 --- a/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs +++ b/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs @@ -90,7 +90,7 @@ pub(crate) fn raise_vanilla_args(checker: &mut Checker, expr: &Expr) { fn contains_message(expr: &Expr) -> bool { match expr { Expr::FString(ast::ExprFString { value, .. }) => { - for f_string_part in value.parts() { + for f_string_part in value { match f_string_part { ast::FStringPart::Literal(literal) => { if literal.chars().any(char::is_whitespace) { diff --git a/crates/ruff_python_ast/src/comparable.rs b/crates/ruff_python_ast/src/comparable.rs index b4a94f3544380..b3c7faf116a5c 100644 --- a/crates/ruff_python_ast/src/comparable.rs +++ b/crates/ruff_python_ast/src/comparable.rs @@ -583,10 +583,10 @@ impl<'a> From> for ComparableLiteral<'a> { value, .. }) => Self::Bool(value), ast::LiteralExpressionRef::StringLiteral(ast::ExprStringLiteral { value, .. }) => { - Self::Str(value.parts().map(Into::into).collect()) + Self::Str(value.iter().map(Into::into).collect()) } ast::LiteralExpressionRef::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => { - Self::Bytes(value.parts().map(Into::into).collect()) + Self::Bytes(value.iter().map(Into::into).collect()) } ast::LiteralExpressionRef::NumberLiteral(ast::ExprNumberLiteral { value, .. }) => { Self::Number(value.into()) @@ -1012,17 +1012,17 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> { }), ast::Expr::FString(ast::ExprFString { value, range: _ }) => { Self::FString(ExprFString { - parts: value.parts().map(Into::into).collect(), + parts: value.iter().map(Into::into).collect(), }) } ast::Expr::StringLiteral(ast::ExprStringLiteral { value, range: _ }) => { Self::StringLiteral(ExprStringLiteral { - parts: value.parts().map(Into::into).collect(), + parts: value.iter().map(Into::into).collect(), }) } ast::Expr::BytesLiteral(ast::ExprBytesLiteral { value, range: _ }) => { Self::BytesLiteral(ExprBytesLiteral { - parts: value.parts().map(Into::into).collect(), + parts: value.iter().map(Into::into).collect(), }) } ast::Expr::NumberLiteral(ast::ExprNumberLiteral { value, range: _ }) => { diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index b9e0866837d6c..fceba83d02a80 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -1326,7 +1326,7 @@ impl Truthiness { Expr::NoneLiteral(_) => Self::Falsey, Expr::EllipsisLiteral(_) => Self::Truthy, Expr::FString(ast::ExprFString { value, .. }) => { - if value.parts().all(|part| match part { + if value.iter().all(|part| match part { ast::FStringPart::Literal(string_literal) => string_literal.is_empty(), ast::FStringPart::FString(f_string) => f_string.elements.is_empty(), }) { diff --git a/crates/ruff_python_ast/src/node.rs b/crates/ruff_python_ast/src/node.rs index 94bb5d40d2148..35a536004c2a3 100644 --- a/crates/ruff_python_ast/src/node.rs +++ b/crates/ruff_python_ast/src/node.rs @@ -2742,7 +2742,7 @@ impl AstNode for ast::ExprFString { { let ast::ExprFString { value, range: _ } = self; - for f_string_part in value.parts() { + for f_string_part in value { match f_string_part { ast::FStringPart::Literal(string_literal) => { visitor.visit_string_literal(string_literal); @@ -2788,7 +2788,7 @@ impl AstNode for ast::ExprStringLiteral { { let ast::ExprStringLiteral { value, range: _ } = self; - for string_literal in value.parts() { + for string_literal in value { visitor.visit_string_literal(string_literal); } } @@ -2827,7 +2827,7 @@ impl AstNode for ast::ExprBytesLiteral { { let ast::ExprBytesLiteral { value, range: _ } = self; - for bytes_literal in value.parts() { + for bytes_literal in value { visitor.visit_bytes_literal(bytes_literal); } } diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index 964742af492e7..f24a8063e008e 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -4,8 +4,8 @@ use std::cell::OnceCell; use std::fmt; use std::fmt::Debug; use std::ops::Deref; +use std::slice::{Iter, IterMut}; -use itertools::Either::{Left, Right}; use itertools::Itertools; use ruff_text_size::{Ranged, TextRange, TextSize}; @@ -1051,23 +1051,33 @@ impl FStringValue { matches!(self.inner, FStringValueInner::Concatenated(_)) } - /// Returns an iterator over all the [`FStringPart`]s contained in this value. - pub fn parts(&self) -> impl Iterator { + /// Returns a slice of all the [`FStringPart`]s contained in this value. + pub fn as_slice(&self) -> &[FStringPart] { match &self.inner { - FStringValueInner::Single(part) => Left(std::iter::once(part)), - FStringValueInner::Concatenated(parts) => Right(parts.iter()), + FStringValueInner::Single(part) => std::slice::from_ref(part), + FStringValueInner::Concatenated(parts) => parts, } } - /// Returns an iterator over all the [`FStringPart`]s contained in this value - /// that allows modification. - pub(crate) fn parts_mut(&mut self) -> impl Iterator { + /// Returns a mutable slice of all the [`FStringPart`]s contained in this value. + fn as_mut_slice(&mut self) -> &mut [FStringPart] { match &mut self.inner { - FStringValueInner::Single(part) => Left(std::iter::once(part)), - FStringValueInner::Concatenated(parts) => Right(parts.iter_mut()), + FStringValueInner::Single(part) => std::slice::from_mut(part), + FStringValueInner::Concatenated(parts) => parts, } } + /// Returns an iterator over all the [`FStringPart`]s contained in this value. + pub fn iter(&self) -> Iter { + self.as_slice().iter() + } + + /// Returns an iterator over all the [`FStringPart`]s contained in this value + /// that allows modification. + pub(crate) fn iter_mut(&mut self) -> IterMut { + self.as_mut_slice().iter_mut() + } + /// Returns an iterator over the [`StringLiteral`] parts contained in this value. /// /// Note that this doesn't nest into the f-string parts. For example, @@ -1078,7 +1088,7 @@ impl FStringValue { /// /// Here, the string literal parts returned would be `"foo"` and `"baz"`. pub fn literals(&self) -> impl Iterator { - self.parts().filter_map(|part| part.as_literal()) + self.iter().filter_map(|part| part.as_literal()) } /// Returns an iterator over the [`FString`] parts contained in this value. @@ -1091,7 +1101,7 @@ impl FStringValue { /// /// Here, the f-string parts returned would be `f"bar {x}"` and `f"qux"`. pub fn f_strings(&self) -> impl Iterator { - self.parts().filter_map(|part| part.as_f_string()) + self.iter().filter_map(|part| part.as_f_string()) } /// Returns an iterator over all the [`FStringElement`] contained in this value. @@ -1110,6 +1120,15 @@ impl FStringValue { } } +impl<'a> IntoIterator for &'a FStringValue { + type Item = &'a FStringPart; + type IntoIter = Iter<'a, FStringPart>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + /// An internal representation of [`FStringValue`]. #[derive(Clone, Debug, PartialEq)] enum FStringValueInner { @@ -1238,26 +1257,36 @@ impl StringLiteralValue { /// For an implicitly concatenated string, it returns `true` only if the first /// string literal is a unicode string. pub fn is_unicode(&self) -> bool { - self.parts().next().map_or(false, |part| part.unicode) + self.iter().next().map_or(false, |part| part.unicode) } - /// Returns an iterator over all the [`StringLiteral`] parts contained in this value. - pub fn parts(&self) -> impl Iterator { + /// Returns a slice of all the [`StringLiteral`] parts contained in this value. + pub fn as_slice(&self) -> &[StringLiteral] { match &self.inner { - StringLiteralValueInner::Single(value) => Left(std::iter::once(value)), - StringLiteralValueInner::Concatenated(value) => Right(value.strings.iter()), + StringLiteralValueInner::Single(value) => std::slice::from_ref(value), + StringLiteralValueInner::Concatenated(value) => value.strings.as_slice(), } } - /// Returns an iterator over all the [`StringLiteral`] parts contained in this value - /// that allows modification. - pub(crate) fn parts_mut(&mut self) -> impl Iterator { + /// Returns a mutable slice of all the [`StringLiteral`] parts contained in this value. + fn as_mut_slice(&mut self) -> &mut [StringLiteral] { match &mut self.inner { - StringLiteralValueInner::Single(value) => Left(std::iter::once(value)), - StringLiteralValueInner::Concatenated(value) => Right(value.strings.iter_mut()), + StringLiteralValueInner::Single(value) => std::slice::from_mut(value), + StringLiteralValueInner::Concatenated(value) => value.strings.as_mut_slice(), } } + /// Returns an iterator over all the [`StringLiteral`] parts contained in this value. + pub fn iter(&self) -> Iter { + self.as_slice().iter() + } + + /// Returns an iterator over all the [`StringLiteral`] parts contained in this value + /// that allows modification. + pub(crate) fn iter_mut(&mut self) -> IterMut { + self.as_mut_slice().iter_mut() + } + /// Returns `true` if the string literal value is empty. pub fn is_empty(&self) -> bool { self.len() == 0 @@ -1266,12 +1295,12 @@ impl StringLiteralValue { /// Returns the total length of the string literal value, in bytes, not /// [`char`]s or graphemes. pub fn len(&self) -> usize { - self.parts().fold(0, |acc, part| acc + part.value.len()) + self.iter().fold(0, |acc, part| acc + part.value.len()) } /// Returns an iterator over the [`char`]s of each string literal part. pub fn chars(&self) -> impl Iterator + '_ { - self.parts().flat_map(|part| part.value.chars()) + self.iter().flat_map(|part| part.value.chars()) } /// Returns the concatenated string value as a [`str`]. @@ -1286,6 +1315,15 @@ impl StringLiteralValue { } } +impl<'a> IntoIterator for &'a StringLiteralValue { + type Item = &'a StringLiteral; + type IntoIter = Iter<'a, StringLiteral>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + impl PartialEq for StringLiteralValue { fn eq(&self, other: &str) -> bool { if self.len() != other.len() { @@ -1457,37 +1495,55 @@ impl BytesLiteralValue { matches!(self.inner, BytesLiteralValueInner::Concatenated(_)) } - /// Returns an iterator over all the [`BytesLiteral`] parts contained in this value. - pub fn parts(&self) -> impl Iterator { + /// Returns a slice of all the [`BytesLiteral`] parts contained in this value. + pub fn as_slice(&self) -> &[BytesLiteral] { match &self.inner { - BytesLiteralValueInner::Single(value) => Left(std::iter::once(value)), - BytesLiteralValueInner::Concatenated(values) => Right(values.iter()), + BytesLiteralValueInner::Single(value) => std::slice::from_ref(value), + BytesLiteralValueInner::Concatenated(value) => value.as_slice(), } } - /// Returns an iterator over all the [`BytesLiteral`] parts contained in this value - /// that allows modification. - pub(crate) fn parts_mut(&mut self) -> impl Iterator { + /// Returns a mutable slice of all the [`BytesLiteral`] parts contained in this value. + fn as_mut_slice(&mut self) -> &mut [BytesLiteral] { match &mut self.inner { - BytesLiteralValueInner::Single(value) => Left(std::iter::once(value)), - BytesLiteralValueInner::Concatenated(values) => Right(values.iter_mut()), + BytesLiteralValueInner::Single(value) => std::slice::from_mut(value), + BytesLiteralValueInner::Concatenated(value) => value.as_mut_slice(), } } + /// Returns an iterator over all the [`BytesLiteral`] parts contained in this value. + pub fn iter(&self) -> Iter { + self.as_slice().iter() + } + + /// Returns an iterator over all the [`BytesLiteral`] parts contained in this value + /// that allows modification. + pub(crate) fn iter_mut(&mut self) -> IterMut { + self.as_mut_slice().iter_mut() + } + /// Returns `true` if the concatenated bytes has a length of zero. pub fn is_empty(&self) -> bool { - self.parts().all(|part| part.is_empty()) + self.iter().all(|part| part.is_empty()) } /// Returns the length of the concatenated bytes. pub fn len(&self) -> usize { - self.parts().map(|part| part.len()).sum() + self.iter().map(|part| part.len()).sum() } /// Returns an iterator over the bytes of the concatenated bytes. fn bytes(&self) -> impl Iterator + '_ { - self.parts() - .flat_map(|part| part.as_slice().iter().copied()) + self.iter().flat_map(|part| part.as_slice().iter().copied()) + } +} + +impl<'a> IntoIterator for &'a BytesLiteralValue { + type Item = &'a BytesLiteral; + type IntoIter = Iter<'a, BytesLiteral>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() } } diff --git a/crates/ruff_python_ast/src/visitor.rs b/crates/ruff_python_ast/src/visitor.rs index 15a9985b5cf7b..2d8773fcfdcb0 100644 --- a/crates/ruff_python_ast/src/visitor.rs +++ b/crates/ruff_python_ast/src/visitor.rs @@ -477,7 +477,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) { visitor.visit_arguments(arguments); } Expr::FString(ast::ExprFString { value, .. }) => { - for part in value.parts() { + for part in value { match part { FStringPart::Literal(string_literal) => { visitor.visit_string_literal(string_literal); @@ -487,12 +487,12 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) { } } Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { - for string_literal in value.parts() { + for string_literal in value { visitor.visit_string_literal(string_literal); } } Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => { - for bytes_literal in value.parts() { + for bytes_literal in value { visitor.visit_bytes_literal(bytes_literal); } } diff --git a/crates/ruff_python_ast/src/visitor/transformer.rs b/crates/ruff_python_ast/src/visitor/transformer.rs index 36ee7687f33c0..caa111c43f95b 100644 --- a/crates/ruff_python_ast/src/visitor/transformer.rs +++ b/crates/ruff_python_ast/src/visitor/transformer.rs @@ -464,7 +464,7 @@ pub fn walk_expr(visitor: &V, expr: &mut Expr) { visitor.visit_arguments(arguments); } Expr::FString(ast::ExprFString { value, .. }) => { - for f_string_part in value.parts_mut() { + for f_string_part in value.iter_mut() { match f_string_part { ast::FStringPart::Literal(string_literal) => { visitor.visit_string_literal(string_literal); @@ -476,12 +476,12 @@ pub fn walk_expr(visitor: &V, expr: &mut Expr) { } } Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { - for string_literal in value.parts_mut() { + for string_literal in value.iter_mut() { visitor.visit_string_literal(string_literal); } } Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => { - for bytes_literal in value.parts_mut() { + for bytes_literal in value.iter_mut() { visitor.visit_bytes_literal(bytes_literal); } } diff --git a/crates/ruff_python_codegen/src/generator.rs b/crates/ruff_python_codegen/src/generator.rs index 9baacbdbd3ac0..7f9d5d4f8e2a8 100644 --- a/crates/ruff_python_codegen/src/generator.rs +++ b/crates/ruff_python_codegen/src/generator.rs @@ -1077,7 +1077,7 @@ impl<'a> Generator<'a> { } Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => { let mut first = true; - for bytes_literal in value.parts() { + for bytes_literal in value { self.p_delim(&mut first, " "); self.p_bytes_repr(&bytes_literal.value); } @@ -1273,7 +1273,7 @@ impl<'a> Generator<'a> { fn unparse_string_literal_value(&mut self, value: &ast::StringLiteralValue) { let mut first = true; - for string_literal in value.parts() { + for string_literal in value { self.p_delim(&mut first, " "); self.unparse_string_literal(string_literal); } @@ -1281,7 +1281,7 @@ impl<'a> Generator<'a> { fn unparse_f_string_value(&mut self, value: &ast::FStringValue, is_spec: bool) { let mut first = true; - for f_string_part in value.parts() { + for f_string_part in value { self.p_delim(&mut first, " "); match f_string_part { ast::FStringPart::Literal(string_literal) => { diff --git a/crates/ruff_python_formatter/src/expression/string/mod.rs b/crates/ruff_python_formatter/src/expression/string/mod.rs index 1bd7f28af9c56..135594be3a044 100644 --- a/crates/ruff_python_formatter/src/expression/string/mod.rs +++ b/crates/ruff_python_formatter/src/expression/string/mod.rs @@ -86,13 +86,13 @@ impl<'a> AnyString<'a> { fn parts(&self) -> Vec> { match self { Self::String(ExprStringLiteral { value, .. }) => { - value.parts().map(AnyStringPart::String).collect() + value.iter().map(AnyStringPart::String).collect() } Self::Bytes(ExprBytesLiteral { value, .. }) => { - value.parts().map(AnyStringPart::Bytes).collect() + value.iter().map(AnyStringPart::Bytes).collect() } Self::FString(ExprFString { value, .. }) => value - .parts() + .iter() .map(|f_string_part| match f_string_part { ast::FStringPart::Literal(string_literal) => { AnyStringPart::String(string_literal) From b6fb972e6f08608babf663bfe63f31d0795a7d54 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Wed, 13 Dec 2023 11:02:11 -0500 Subject: [PATCH 180/197] config: add new `docstring-code-format` knob (#8854) This PR does the plumbing to make a new formatting option, `docstring-code-format`, available in the configuration for end users. It is disabled by default (opt-in). It is opt-in at least initially to reflect a conservative posture. The intent is to make it opt-out at some point in the future. This was split out from #8811 in order to make #8811 easier to merge. Namely, once this is merged, docstring code snippet formatting will become available to end users. (See comments below for how we arrived at the name.) Closes #7146 ## Test Plan Other than the standard test suite, I ran the formatter over the CPython and polars projects to ensure both that the result looked sensible and that tests still passed. At time of writing, one issue that currently appears is that reformatting code snippets trips the long line lint: https://github.com/BurntSushi/polars/actions/runs/7006619426/job/19058868021 --- crates/ruff_cli/tests/format.rs | 93 +++++++++++ crates/ruff_python_formatter/src/options.rs | 15 +- .../tests/snapshots/format@docstring.py.snap | 10 +- .../format@docstring_code_examples.py.snap | 43 +++-- ...ormat@docstring_code_examples_crlf.py.snap | 2 +- .../format@expression__bytes.py.snap | 4 +- .../format@expression__string.py.snap | 4 +- ...rmat@fmt_on_off__fmt_off_docstring.py.snap | 4 +- .../format@fmt_on_off__indent.py.snap | 6 +- ...at@fmt_on_off__mixed_space_and_tab.py.snap | 6 +- .../tests/snapshots/format@preview.py.snap | 4 +- .../snapshots/format@quote_style.py.snap | 6 +- .../format@skip_magic_trailing_comma.py.snap | 4 +- ...ment__assignment_split_value_first.py.snap | 2 +- .../tests/snapshots/format@tab_width.py.snap | 6 +- crates/ruff_workspace/src/configuration.rs | 24 ++- crates/ruff_workspace/src/options.rs | 152 +++++++++++++++++- crates/ruff_workspace/src/settings.rs | 12 +- docs/configuration.md | 28 ++++ docs/formatter.md | 101 +++++++++++- ruff.schema.json | 34 ++++ 21 files changed, 505 insertions(+), 55 deletions(-) diff --git a/crates/ruff_cli/tests/format.rs b/crates/ruff_cli/tests/format.rs index e9970645d7b67..cd3e14629899e 100644 --- a/crates/ruff_cli/tests/format.rs +++ b/crates/ruff_cli/tests/format.rs @@ -139,6 +139,99 @@ if condition: Ok(()) } +#[test] +fn docstring_options() -> Result<()> { + let tempdir = TempDir::new()?; + let ruff_toml = tempdir.path().join("ruff.toml"); + fs::write( + &ruff_toml, + r#" +[format] +docstring-code-format = true +docstring-code-line-length = 20 +"#, + )?; + + assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) + .args(["format", "--config"]) + .arg(&ruff_toml) + .arg("-") + .pass_stdin(r#" +def f(x): + ''' + Something about `f`. And an example: + + .. code-block:: python + + foo, bar, quux = this_is_a_long_line(lion, hippo, lemur, bear) + + Another example: + + ```py + foo, bar, quux = this_is_a_long_line(lion, hippo, lemur, bear) + ``` + + And another: + + >>> foo, bar, quux = this_is_a_long_line(lion, hippo, lemur, bear) + ''' + pass +"#), @r###" +success: true +exit_code: 0 +----- stdout ----- +def f(x): + """ + Something about `f`. And an example: + + .. code-block:: python + + ( + foo, + bar, + quux, + ) = this_is_a_long_line( + lion, + hippo, + lemur, + bear, + ) + + Another example: + + ```py + ( + foo, + bar, + quux, + ) = this_is_a_long_line( + lion, + hippo, + lemur, + bear, + ) + ``` + + And another: + + >>> ( + ... foo, + ... bar, + ... quux, + ... ) = this_is_a_long_line( + ... lion, + ... hippo, + ... lemur, + ... bear, + ... ) + """ + pass + +----- stderr ----- +"###); + Ok(()) +} + #[test] fn mixed_line_endings() -> Result<()> { let tempdir = TempDir::new()?; diff --git a/crates/ruff_python_formatter/src/options.rs b/crates/ruff_python_formatter/src/options.rs index 8f3bc431ec815..4f637dca9ee10 100644 --- a/crates/ruff_python_formatter/src/options.rs +++ b/crates/ruff_python_formatter/src/options.rs @@ -175,6 +175,12 @@ impl PyFormatOptions { self } + #[must_use] + pub fn with_docstring_code_line_width(mut self, line_width: DocstringCodeLineWidth) -> Self { + self.docstring_code_line_width = line_width; + self + } + #[must_use] pub fn with_preview(mut self, preview: PreviewMode) -> Self { self.preview = preview; @@ -302,13 +308,14 @@ impl DocstringCode { } } -#[derive(Copy, Clone, Eq, PartialEq, CacheKey)] +#[derive(Copy, Clone, Default, Eq, PartialEq, CacheKey)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))] #[cfg_attr(feature = "serde", serde(untagged))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum DocstringCodeLineWidth { Fixed(LineWidth), + #[default] #[cfg_attr( feature = "serde", serde(deserialize_with = "deserialize_docstring_code_line_width_dynamic") @@ -316,12 +323,6 @@ pub enum DocstringCodeLineWidth { Dynamic, } -impl Default for DocstringCodeLineWidth { - fn default() -> DocstringCodeLineWidth { - DocstringCodeLineWidth::Fixed(default_line_width()) - } -} - impl std::fmt::Debug for DocstringCodeLineWidth { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match *self { diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap index 98220dcff890a..bf8fa7f40df94 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap @@ -173,7 +173,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -347,7 +347,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -521,7 +521,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -695,7 +695,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -869,7 +869,7 @@ quote-style = Single line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap index b93825ea198e6..672b7a715d623 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap @@ -1366,7 +1366,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -2736,7 +2736,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -4106,7 +4106,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -5476,7 +5476,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -6846,7 +6846,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Enabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -7090,7 +7090,9 @@ def doctest_long_lines(): This won't get wrapped even though it exceeds our configured line width because it doesn't exceed the line width within this docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey + ... ) But this one is long enough to get wrapped. >>> foo, bar, quux = this_is_a_long_line( @@ -8211,7 +8213,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Enabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -8455,7 +8457,9 @@ def doctest_long_lines(): This won't get wrapped even though it exceeds our configured line width because it doesn't exceed the line width within this docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey + ... ) But this one is long enough to get wrapped. >>> foo, bar, quux = this_is_a_long_line( @@ -9576,7 +9580,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Enabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -9820,11 +9824,22 @@ def doctest_long_lines(): This won't get wrapped even though it exceeds our configured line width because it doesn't exceed the line width within this docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey + ... ) But this one is long enough to get wrapped. >>> foo, bar, quux = this_is_a_long_line( - ... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard + ... lion, + ... giraffe, + ... hippo, + ... zeba, + ... lemur, + ... penguin, + ... monkey, + ... spider, + ... bear, + ... leopard, ... ) """ # This demostrates a normal line that will get wrapped but won't @@ -10941,7 +10956,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Enabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -11185,7 +11200,9 @@ def doctest_long_lines(): This won't get wrapped even though it exceeds our configured line width because it doesn't exceed the line width within this docstring. e.g, the `f` in `foo` is treated as the first column. - >>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey) + >>> foo, bar, quux = this_is_a_long_line( + ... lion, giraffe, hippo, zeba, lemur, penguin, monkey + ... ) But this one is long enough to get wrapped. >>> foo, bar, quux = this_is_a_long_line( diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap index 347c3cc2a8388..9f7fd5b9ac5b7 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap @@ -25,7 +25,7 @@ quote-style = Double line-ending = CarriageReturnLineFeed magic-trailing-comma = Respect docstring-code = Enabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap index fc89a38635108..b741654c94c4a 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap @@ -136,7 +136,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -288,7 +288,7 @@ quote-style = Single line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap index 0829244eb68b4..306a10a49f9fe 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap @@ -151,7 +151,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -327,7 +327,7 @@ quote-style = Single line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap index 2080aa4a52451..2c5ce6935feec 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap @@ -35,7 +35,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -71,7 +71,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap index a0c8fd1ef68e4..f1db6d7a8bfdc 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap @@ -16,7 +16,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -33,7 +33,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -50,7 +50,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap index 2ff76b7092a66..7ff04c9571b70 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap @@ -31,7 +31,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -64,7 +64,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -97,7 +97,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap index eea51abf01ce3..fdedcce512dd8 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap @@ -82,7 +82,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -164,7 +164,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Enabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap index 9bce249d23c2f..ed5c09022e14e 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap @@ -66,7 +66,7 @@ quote-style = Single line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -137,7 +137,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -208,7 +208,7 @@ quote-style = Preserve line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap index b7e43061b7da2..83b67689f467f 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap @@ -49,7 +49,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -105,7 +105,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Ignore docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__assignment_split_value_first.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__assignment_split_value_first.py.snap index 6fca0005232fd..38e2e31a44354 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__assignment_split_value_first.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__assignment_split_value_first.py.snap @@ -234,7 +234,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Enabled ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap index 9f39a521a260a..ea85babc1bab7 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap @@ -24,7 +24,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -49,7 +49,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` @@ -77,7 +77,7 @@ quote-style = Double line-ending = LineFeed magic-trailing-comma = Respect docstring-code = Disabled -docstring-code-line-width = 88 +docstring-code-line-width = "dynamic" preview = Disabled ``` diff --git a/crates/ruff_workspace/src/configuration.rs b/crates/ruff_workspace/src/configuration.rs index 6b3e2abbc45a1..fe95418e69c43 100644 --- a/crates/ruff_workspace/src/configuration.rs +++ b/crates/ruff_workspace/src/configuration.rs @@ -34,7 +34,9 @@ use ruff_linter::settings::{ use ruff_linter::{ fs, warn_user, warn_user_once, warn_user_once_by_id, RuleSelector, RUFF_PKG_VERSION, }; -use ruff_python_formatter::{MagicTrailingComma, QuoteStyle}; +use ruff_python_formatter::{ + DocstringCode, DocstringCodeLineWidth, MagicTrailingComma, QuoteStyle, +}; use crate::options::{ Flake8AnnotationsOptions, Flake8BanditOptions, Flake8BugbearOptions, Flake8BuiltinsOptions, @@ -189,6 +191,12 @@ impl Configuration { magic_trailing_comma: format .magic_trailing_comma .unwrap_or(format_defaults.magic_trailing_comma), + docstring_code_format: format + .docstring_code_format + .unwrap_or(format_defaults.docstring_code_format), + docstring_code_line_width: format + .docstring_code_line_width + .unwrap_or(format_defaults.docstring_code_line_width), }; let lint = self.lint; @@ -1020,6 +1028,8 @@ pub struct FormatConfiguration { pub quote_style: Option, pub magic_trailing_comma: Option, pub line_ending: Option, + pub docstring_code_format: Option, + pub docstring_code_line_width: Option, } impl FormatConfiguration { @@ -1046,6 +1056,14 @@ impl FormatConfiguration { } }), line_ending: options.line_ending, + docstring_code_format: options.docstring_code_format.map(|yes| { + if yes { + DocstringCode::Enabled + } else { + DocstringCode::Disabled + } + }), + docstring_code_line_width: options.docstring_code_line_length, }) } @@ -1059,6 +1077,10 @@ impl FormatConfiguration { quote_style: self.quote_style.or(other.quote_style), magic_trailing_comma: self.magic_trailing_comma.or(other.magic_trailing_comma), line_ending: self.line_ending.or(other.line_ending), + docstring_code_format: self.docstring_code_format.or(other.docstring_code_format), + docstring_code_line_width: self + .docstring_code_line_width + .or(other.docstring_code_line_width), } } } diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index c0ce2c2e79f98..b032c2be3acf5 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -27,7 +27,7 @@ use ruff_linter::settings::types::{ }; use ruff_linter::{warn_user_once, RuleSelector}; use ruff_macros::{CombineOptions, OptionsMetadata}; -use ruff_python_formatter::QuoteStyle; +use ruff_python_formatter::{DocstringCodeLineWidth, QuoteStyle}; use crate::settings::LineEnding; @@ -2948,6 +2948,156 @@ pub struct FormatOptions { "# )] pub line_ending: Option, + + /// Whether to format code snippets in docstrings. + /// + /// When this is enabled, Python code examples within docstrings are + /// automatically reformatted. + /// + /// For example, when this is enabled, the following code: + /// + /// ```python + /// def f(x): + /// """ + /// Something about `f`. And an example in doctest format: + /// + /// >>> f( x ) + /// + /// Markdown is also supported: + /// + /// ```py + /// f( x ) + /// ``` + /// + /// As are reStructuredText literal blocks:: + /// + /// f( x ) + /// + /// + /// And reStructuredText code blocks: + /// + /// .. code-block:: python + /// + /// f( x ) + /// """ + /// pass + /// ``` + /// + /// ... will be reformatted (assuming the rest of the options are set to + /// their defaults) as: + /// + /// ```python + /// def f(x): + /// """ + /// Something about `f`. And an example in doctest format: + /// + /// >>> f(x) + /// + /// Markdown is also supported: + /// + /// ```py + /// f(x) + /// ``` + /// + /// As are reStructuredText literal blocks:: + /// + /// f(x) + /// + /// + /// And reStructuredText code blocks: + /// + /// .. code-block:: python + /// + /// f(x) + /// """ + /// pass + /// ``` + /// + /// If a code snippt in a docstring contains invalid Python code or if the + /// formatter would otherwise write invalid Python code, then the code + /// example is ignored by the formatter and kept as-is. + /// + /// Currently, doctest, Markdown, reStructuredText literal blocks, and + /// reStructuredText code blocks are all supported and automatically + /// recognized. In the case of unlabeled fenced code blocks in Markdown and + /// reStructuredText literal blocks, the contents are assumed to be Python + /// and reformatted. As with any other format, if the contents aren't valid + /// Python, then the block is left untouched automatically. + #[option( + default = "false", + value_type = "bool", + example = r#" + # Enable reformatting of code snippets in docstrings. + docstring-code-format = true + "# + )] + pub docstring_code_format: Option, + + /// Set the line length used when formatting code snippets in docstrings. + /// + /// This only has an effect when the `docstring-code-format` setting is + /// enabled. + /// + /// The default value for this setting is `"dynamic"`, which has the effect + /// of ensuring that any reformatted code examples in docstrings adhere to + /// the global line length configuration that is used for the surrounding + /// Python code. The point of this setting is that it takes the indentation + /// of the docstring into account when reformatting code examples. + /// + /// Alternatively, this can be set to a fixed integer, which will result + /// in the same line length limit being applied to all reformatted code + /// examples in docstrings. When set to a fixed integer, the indent of the + /// docstring is not taken into account. That is, this may result in lines + /// in the reformatted code example that exceed the globally configured + /// line length limit. + /// + /// For example, when this is set to `20` and `docstring-code-format` is + /// enabled, then this code: + /// + /// ```python + /// def f(x): + /// ''' + /// Something about `f`. And an example: + /// + /// .. code-block:: python + /// + /// foo, bar, quux = this_is_a_long_line(lion, hippo, lemur, bear) + /// ''' + /// pass + /// ``` + /// + /// ... will be reformatted (assuming the rest of the options are set + /// to their defaults) as: + /// + /// ```python + /// def f(x): + /// """ + /// Something about `f`. And an example: + /// + /// .. code-block:: python + /// + /// ( + /// foo, + /// bar, + /// quux, + /// ) = this_is_a_long_line( + /// lion, + /// hippo, + /// lemur, + /// bear, + /// ) + /// """ + /// pass + /// ``` + #[option( + default = r#""dynamic""#, + value_type = r#"int | "dynamic""#, + example = r#" + # Format all docstring code snippets with a line length of 60. + docstring-code-line-length = 60 + "# + )] + pub docstring_code_line_length: Option, } #[cfg(test)] diff --git a/crates/ruff_workspace/src/settings.rs b/crates/ruff_workspace/src/settings.rs index 982732e487317..8ee030ea3b42a 100644 --- a/crates/ruff_workspace/src/settings.rs +++ b/crates/ruff_workspace/src/settings.rs @@ -5,7 +5,10 @@ use ruff_linter::settings::types::{FilePattern, FilePatternSet, SerializationFor use ruff_linter::settings::LinterSettings; use ruff_macros::CacheKey; use ruff_python_ast::PySourceType; -use ruff_python_formatter::{MagicTrailingComma, PreviewMode, PyFormatOptions, QuoteStyle}; +use ruff_python_formatter::{ + DocstringCode, DocstringCodeLineWidth, MagicTrailingComma, PreviewMode, PyFormatOptions, + QuoteStyle, +}; use ruff_source_file::find_newline; use std::path::{Path, PathBuf}; @@ -124,6 +127,9 @@ pub struct FormatterSettings { pub magic_trailing_comma: MagicTrailingComma, pub line_ending: LineEnding, + + pub docstring_code_format: DocstringCode, + pub docstring_code_line_width: DocstringCodeLineWidth, } impl FormatterSettings { @@ -157,6 +163,8 @@ impl FormatterSettings { .with_preview(self.preview) .with_line_ending(line_ending) .with_line_width(self.line_width) + .with_docstring_code(self.docstring_code_format) + .with_docstring_code_line_width(self.docstring_code_line_width) } } @@ -173,6 +181,8 @@ impl Default for FormatterSettings { indent_width: default_options.indent_width(), quote_style: default_options.quote_style(), magic_trailing_comma: default_options.magic_trailing_comma(), + docstring_code_format: default_options.docstring_code(), + docstring_code_line_width: default_options.docstring_code_line_width(), } } } diff --git a/docs/configuration.md b/docs/configuration.md index 32d6b2eb130fc..ec1dd0fa577df 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -71,6 +71,20 @@ If left unspecified, Ruff's default configuration is equivalent to: # Like Black, automatically detect the appropriate line ending. line-ending = "auto" + + # Enable auto-formatting of code examples in docstrings. Markdown, + # reStructuredText code/literal blocks and doctests are all supported. + # + # This is currently disabled by default, but it is planned for this + # to be opt-out in the future. + docstring-code-format = false + + # Set the line length limit used when formatting code snippets in + # docstrings. + # + # This only has an effect when the `docstring-code-format` setting is + # enabled. + docstring-code-line-length = "dynamic" ``` === "ruff.toml" @@ -134,6 +148,20 @@ If left unspecified, Ruff's default configuration is equivalent to: # Like Black, automatically detect the appropriate line ending. line-ending = "auto" + + # Enable auto-formatting of code examples in docstrings. Markdown, + # reStructuredText code/literal blocks and doctests are all supported. + # + # This is currently disabled by default, but it is planned for this + # to be opt-out in the future. + docstring-code-format = false + + # Set the line length limit used when formatting code snippets in + # docstrings. + # + # This only has an effect when the `docstring-code-format` setting is + # enabled. + docstring-code-line-length = "dynamic" ``` As an example, the following would configure Ruff to: diff --git a/docs/formatter.md b/docs/formatter.md index 14d35e94a2dcd..8c8537946862d 100644 --- a/docs/formatter.md +++ b/docs/formatter.md @@ -103,10 +103,12 @@ Going forward, the Ruff Formatter will support Black's preview style under Ruff' ## Configuration The Ruff Formatter exposes a small set of configuration options, some of which are also supported -by Black (like line width), some of which are unique to Ruff (like quote and indentation style). +by Black (like line width), some of which are unique to Ruff (like quote, indentation style and +formatting code examples in docstrings). -For example, to configure the formatter to use single quotes, a line width of 100, and -tab indentation, add the following to your configuration file: +For example, to configure the formatter to use single quotes, format code +examples in docstrings, a line width of 100, and tab indentation, add the +following to your configuration file: === "pyproject.toml" @@ -117,6 +119,7 @@ tab indentation, add the following to your configuration file: [tool.ruff.format] quote-style = "single" indent-style = "tab" + docstring-code-format = true ``` === "ruff.toml" @@ -127,6 +130,7 @@ tab indentation, add the following to your configuration file: [format] quote-style = "single" indent-style = "tab" + docstring-code-format = true ``` @@ -137,6 +141,97 @@ Given the focus on Black compatibility (and unlike formatters like [YAPF](https: Ruff does not currently expose any configuration options to modify core formatting behavior outside of these trivia-related settings. +## Docstring formatting + +The Ruff formatter provides an opt-in feature for automatically formatting +Python code examples in docstrings. The Ruff formatter currently recognizes +code examples in the following formats: + +* The Python [doctest] format. +* CommonMark [fenced code blocks] with the following info strings: `python`, +`py`, `python3`, or `py3`. Fenced code blocks without an info string are +assumed to be Python code examples and also formatted. +* reStructuredText [literal blocks]. While literal blocks may contain things +other than Python, this is meant to reflect a long-standing convention in the +Python ecosystem where literal blocks often contain Python code. +* reStructuredText [`code-block` and `sourcecode` directives]. As with +Markdown, the language names recognized for Python are `python`, `py`, +`python3`, or `py3`. + +If a code example is recognized and treated as Python, the Ruff formatter will +automatically skip it if the code does not parse as valid Python or if the +reformatted code would produce an invalid Python program. + +Users may also configure the line length limit used for reformatting Python +code examples in docstrings. The default is a special value, `dynamic`, which +instructs the formatter to respect the line length limit setting for the +surrounding Python code. The `dynamic` setting ensures that even when code +examples are found inside indented docstrings, the line length limit configured +for the surrounding Python code will not be exceeded. Users may also configure +a fixed line length limit for code examples in docstrings. + +For example, this configuration shows how to enable docstring code formatting +with a fixed line length limit: + +=== "pyproject.toml" + + ```toml + [tool.ruff.format] + docstring-code-format = true + docstring-code-line-length = 20 + ``` + +=== "ruff.toml" + + ```toml + [format] + docstring-code-format = true + docstring-code-line-length = 20 + ``` + +With the above configuration, this code: + +```python +def f(x): + ''' + Something about `f`. And an example: + + .. code-block:: python + + foo, bar, quux = this_is_a_long_line(lion, hippo, lemur, bear) + ''' + pass +``` + +... will be reformatted (assuming the rest of the options are set +to their defaults) as: + +```python +def f(x): + """ + Something about `f`. And an example: + + .. code-block:: python + + ( + foo, + bar, + quux, + ) = this_is_a_long_line( + lion, + hippo, + lemur, + bear, + ) + """ + pass +``` + +[doctest]: https://docs.python.org/3/library/doctest.html +[fenced code blocks]: https://spec.commonmark.org/0.30/#fenced-code-blocks +[literal blocks]: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks +[`code-block` and `sourcecode` directives]: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block + ## Format suppression Like Black, Ruff supports `# fmt: on`, `# fmt: off`, and `# fmt: skip` pragma comments, which can diff --git a/ruff.schema.json b/ruff.schema.json index d7ff44db9d7b0..c382714b70616 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -747,6 +747,16 @@ } ] }, + "DocstringCodeLineWidth": { + "anyOf": [ + { + "$ref": "#/definitions/LineWidth" + }, + { + "type": "null" + } + ] + }, "Flake8AnnotationsOptions": { "type": "object", "properties": { @@ -1248,6 +1258,24 @@ "description": "Experimental: Configures how `ruff format` formats your code.\n\nPlease provide feedback in [this discussion](https://github.com/astral-sh/ruff/discussions/7310).", "type": "object", "properties": { + "docstring-code-format": { + "description": "Whether to format code snippets in docstrings.\n\nWhen this is enabled, Python code examples within docstrings are automatically reformatted.\n\nFor example, when this is enabled, the following code:\n\n```python def f(x): \"\"\" Something about `f`. And an example in doctest format:\n\n>>> f( x )\n\nMarkdown is also supported:\n\n```py f( x ) ```\n\nAs are reStructuredText literal blocks::\n\nf( x )\n\nAnd reStructuredText code blocks:\n\n.. code-block:: python\n\nf( x ) \"\"\" pass ```\n\n... will be reformatted (assuming the rest of the options are set to their defaults) as:\n\n```python def f(x): \"\"\" Something about `f`. And an example in doctest format:\n\n>>> f(x)\n\nMarkdown is also supported:\n\n```py f(x) ```\n\nAs are reStructuredText literal blocks::\n\nf(x)\n\nAnd reStructuredText code blocks:\n\n.. code-block:: python\n\nf(x) \"\"\" pass ```\n\nIf a code snippt in a docstring contains invalid Python code or if the formatter would otherwise write invalid Python code, then the code example is ignored by the formatter and kept as-is.\n\nCurrently, doctest, Markdown, reStructuredText literal blocks, and reStructuredText code blocks are all supported and automatically recognized. In the case of unlabeled fenced code blocks in Markdown and reStructuredText literal blocks, the contents are assumed to be Python and reformatted. As with any other format, if the contents aren't valid Python, then the block is left untouched automatically.", + "type": [ + "boolean", + "null" + ] + }, + "docstring-code-line-length": { + "description": "Set the line length used when formatting code snippets in docstrings.\n\nThis only has an effect when the `docstring-code-format` setting is enabled.\n\nThe default value for this setting is `\"dynamic\"`, which has the effect of ensuring that any reformatted code examples in docstrings adhere to the global line length configuration that is used for the surrounding Python code. The point of this setting is that it takes the indentation of the docstring into account when reformatting code examples.\n\nAlternatively, this can be set to a fixed integer, which will result in the same line length limit being applied to all reformatted code examples in docstrings. When set to a fixed integer, the indent of the docstring is not taken into account. That is, this may result in lines in the reformatted code example that exceed the globally configured line length limit.\n\nFor example, when this is set to `20` and `docstring-code-format` is enabled, then this code:\n\n```python def f(x): ''' Something about `f`. And an example:\n\n.. code-block:: python\n\nfoo, bar, quux = this_is_a_long_line(lion, hippo, lemur, bear) ''' pass ```\n\n... will be reformatted (assuming the rest of the options are set to their defaults) as:\n\n```python def f(x): \"\"\" Something about `f`. And an example:\n\n.. code-block:: python\n\n( foo, bar, quux, ) = this_is_a_long_line( lion, hippo, lemur, bear, ) \"\"\" pass ```", + "anyOf": [ + { + "$ref": "#/definitions/DocstringCodeLineWidth" + }, + { + "type": "null" + } + ] + }, "exclude": { "description": "A list of file patterns to exclude from formatting in addition to the files excluded globally (see [`exclude`](#exclude), and [`extend-exclude`](#extend-exclude)).\n\nExclusions are based on globs, and can be either:\n\n- Single-path patterns, like `.mypy_cache` (to exclude any directory named `.mypy_cache` in the tree), `foo.py` (to exclude any file named `foo.py`), or `foo_*.py` (to exclude any file matching `foo_*.py` ). - Relative patterns, like `directory/foo.py` (to exclude that specific file) or `directory/*.py` (to exclude any Python files in `directory`). Note that these paths are relative to the project root (e.g., the directory containing your `pyproject.toml`).\n\nFor more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax).", "type": [ @@ -1652,6 +1680,12 @@ "maximum": 320.0, "minimum": 1.0 }, + "LineWidth": { + "description": "The maximum visual width to which the formatter should try to limit a line.", + "type": "integer", + "format": "uint16", + "minimum": 1.0 + }, "LintOptions": { "description": "Experimental section to configure Ruff's linting. This new section will eventually replace the top-level linting options.\n\nOptions specified in the `lint` section take precedence over the top-level settings.", "type": "object", From c014622003e9b348310d7b7be862f6ccffae7137 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 13 Dec 2023 13:19:51 -0500 Subject: [PATCH 181/197] Bump version to v0.1.8 (#9116) --- CHANGELOG.md | 57 +++++++++++++++++++++++++++++++ Cargo.lock | 8 ++--- README.md | 2 +- crates/flake8_to_ruff/Cargo.toml | 2 +- crates/ruff_cli/Cargo.toml | 2 +- crates/ruff_linter/Cargo.toml | 2 +- crates/ruff_shrinking/Cargo.toml | 2 +- docs/integrations.md | 6 ++-- pyproject.toml | 2 +- scripts/benchmarks/pyproject.toml | 2 +- 10 files changed, 71 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5be1f46ffe6a..1fda890d53892 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,62 @@ # Changelog +## 0.1.8 + +This release includes opt-in support for formatting Python snippets within +docstrings via the `docstring-code-format` setting. +[Check out the blog post](https://astral.sh/blog/v0.1.8) for more details! + +### Preview features + +- Add `"preserve"` quote-style to mimic Black's skip-string-normalization ([#8822](https://github.com/astral-sh/ruff/pull/8822)) +- Implement `prefer_splitting_right_hand_side_of_assignments` preview style ([#8943](https://github.com/astral-sh/ruff/pull/8943)) +- \[`pycodestyle`\] Add fix for `unexpected-spaces-around-keyword-parameter-equals` ([#9072](https://github.com/astral-sh/ruff/pull/9072)) +- \[`pycodestyle`\] Add fix for comment-related whitespace rules ([#9075](https://github.com/astral-sh/ruff/pull/9075)) +- \[`pycodestyle`\] Allow `sys.path` modifications between imports ([#9047](https://github.com/astral-sh/ruff/pull/9047)) +- \[`refurb`\] Implement `hashlib-digest-hex` (`FURB181`) ([#9077](https://github.com/astral-sh/ruff/pull/9077)) + +### Rule changes + +- Allow `flake8-type-checking` rules to automatically quote runtime-evaluated references ([#6001](https://github.com/astral-sh/ruff/pull/6001)) +- Allow transparent cell magics in Jupyter Notebooks ([#8911](https://github.com/astral-sh/ruff/pull/8911)) +- \[`flake8-annotations`\] Avoid `ANN2xx` fixes for abstract methods with empty bodies ([#9034](https://github.com/astral-sh/ruff/pull/9034)) +- \[`flake8-self`\] Ignore underscore references in type annotations ([#9036](https://github.com/astral-sh/ruff/pull/9036)) +- \[`pep8-naming`\] Allow class names when `apps.get_model` is a non-string ([#9065](https://github.com/astral-sh/ruff/pull/9065)) +- \[`pycodestyle`\] Allow `matplotlib.use` calls to intersperse imports ([#9094](https://github.com/astral-sh/ruff/pull/9094)) +- \[`pyflakes`\] Support fixing unused assignments in tuples by renaming variables (`F841`) ([#9107](https://github.com/astral-sh/ruff/pull/9107)) +- \[`pylint`\] Add fix for `subprocess-run-without-check` (`PLW1510`) ([#6708](https://github.com/astral-sh/ruff/pull/6708)) + +### Formatter + +- Add `docstring-code-format` knob to enable docstring snippet formatting ([#8854](https://github.com/astral-sh/ruff/pull/8854)) +- Use double quotes for all docstrings, including single-quoted docstrings ([#9020](https://github.com/astral-sh/ruff/pull/9020)) +- Implement "dynamic" line width mode for docstring code formatting ([#9098](https://github.com/astral-sh/ruff/pull/9098)) +- Support reformatting Markdown code blocks ([#9030](https://github.com/astral-sh/ruff/pull/9030)) +- add support for formatting reStructuredText code snippets ([#9003](https://github.com/astral-sh/ruff/pull/9003)) +- Avoid trailing comma for single-argument with positional separator ([#9076](https://github.com/astral-sh/ruff/pull/9076)) +- Fix handling of trailing target comment ([#9051](https://github.com/astral-sh/ruff/pull/9051)) + +### CLI + +- Hide unsafe fix suggestions when explicitly disabled ([#9095](https://github.com/astral-sh/ruff/pull/9095)) +- Add SARIF support to `--output-format` ([#9078](https://github.com/astral-sh/ruff/pull/9078)) + +### Bug fixes + +- Apply unnecessary index rule prior to enumerate rewrite ([#9012](https://github.com/astral-sh/ruff/pull/9012)) +- \[`flake8-err-msg`\] Allow `EM` fixes even if `msg` variable is defined ([#9059](https://github.com/astral-sh/ruff/pull/9059)) +- \[`flake8-pie`\] Prevent keyword arguments duplication ([#8450](https://github.com/astral-sh/ruff/pull/8450)) +- \[`flake8-pie`\] Respect trailing comma in `unnecessary-dict-kwargs` (`PIE804`) ([#9015](https://github.com/astral-sh/ruff/pull/9015)) +- \[`flake8-raise`\] Avoid removing parentheses on ctypes.WinError ([#9027](https://github.com/astral-sh/ruff/pull/9027)) +- \[`isort`\] Avoid invalid combination of `force-sort-within-types` and `lines-between-types` ([#9041](https://github.com/astral-sh/ruff/pull/9041)) +- \[`isort`\] Ensure that from-style imports are always ordered first in `__future__` ([#9039](https://github.com/astral-sh/ruff/pull/9039)) +- \[`pycodestyle`\] Allow tab indentation before keyword ([#9099](https://github.com/astral-sh/ruff/pull/9099)) +- \[`pylint`\] Ignore `@overrides` and `@overloads` for `too-many-positional` ([#9000](https://github.com/astral-sh/ruff/pull/9000)) +- \[`pyupgrade`\] Enable `printf-string-formatting` fix with comments on right-hand side ([#9037](https://github.com/astral-sh/ruff/pull/9037)) +- \[`refurb`\] Make `math-constant` (`FURB152`) rule more targeted ([#9054](https://github.com/astral-sh/ruff/pull/9054)) +- \[`refurb`\] Support floating-point base in `redundant-log-base` (`FURB163`) ([#9100](https://github.com/astral-sh/ruff/pull/9100)) +- \[`ruff`\] Detect `unused-asyncio-dangling-task` (`RUF006`) on unused assignments ([#9060](https://github.com/astral-sh/ruff/pull/9060)) + ## 0.1.7 ### Preview features diff --git a/Cargo.lock b/Cargo.lock index 8b2225369f672..c17db959ae1c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -809,7 +809,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flake8-to-ruff" -version = "0.1.7" +version = "0.1.8" dependencies = [ "anyhow", "clap", @@ -2063,7 +2063,7 @@ dependencies = [ [[package]] name = "ruff_cli" -version = "0.1.7" +version = "0.1.8" dependencies = [ "annotate-snippets 0.9.2", "anyhow", @@ -2199,7 +2199,7 @@ dependencies = [ [[package]] name = "ruff_linter" -version = "0.1.7" +version = "0.1.8" dependencies = [ "aho-corasick", "annotate-snippets 0.9.2", @@ -2452,7 +2452,7 @@ dependencies = [ [[package]] name = "ruff_shrinking" -version = "0.1.7" +version = "0.1.8" dependencies = [ "anyhow", "clap", diff --git a/README.md b/README.md index 82884d86df3aa..7554930ad0460 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff ```yaml - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.7 + rev: v0.1.8 hooks: # Run the linter. - id: ruff diff --git a/crates/flake8_to_ruff/Cargo.toml b/crates/flake8_to_ruff/Cargo.toml index cf87a0c39a90e..71e5032e76aa0 100644 --- a/crates/flake8_to_ruff/Cargo.toml +++ b/crates/flake8_to_ruff/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "flake8-to-ruff" -version = "0.1.7" +version = "0.1.8" description = """ Convert Flake8 configuration files to Ruff configuration files. """ diff --git a/crates/ruff_cli/Cargo.toml b/crates/ruff_cli/Cargo.toml index 21fa5ddacd64a..ded05207e05a5 100644 --- a/crates/ruff_cli/Cargo.toml +++ b/crates/ruff_cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ruff_cli" -version = "0.1.7" +version = "0.1.8" publish = false authors = { workspace = true } edition = { workspace = true } diff --git a/crates/ruff_linter/Cargo.toml b/crates/ruff_linter/Cargo.toml index 60206ec2f42fc..ea1cb6570b57b 100644 --- a/crates/ruff_linter/Cargo.toml +++ b/crates/ruff_linter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ruff_linter" -version = "0.1.7" +version = "0.1.8" publish = false authors = { workspace = true } edition = { workspace = true } diff --git a/crates/ruff_shrinking/Cargo.toml b/crates/ruff_shrinking/Cargo.toml index c390d646fa5df..f655da8bab610 100644 --- a/crates/ruff_shrinking/Cargo.toml +++ b/crates/ruff_shrinking/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ruff_shrinking" -version = "0.1.7" +version = "0.1.8" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/docs/integrations.md b/docs/integrations.md index 831fcd3f18315..50ae43c9ca1e7 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -14,7 +14,7 @@ Ruff can be used as a [pre-commit](https://pre-commit.com) hook via [`ruff-pre-c ```yaml - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.7 + rev: v0.1.8 hooks: # Run the linter. - id: ruff @@ -27,7 +27,7 @@ To enable lint fixes, add the `--fix` argument to the lint hook: ```yaml - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.7 + rev: v0.1.8 hooks: # Run the linter. - id: ruff @@ -41,7 +41,7 @@ To run the hooks over Jupyter Notebooks too, add `jupyter` to the list of allowe ```yaml - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.7 + rev: v0.1.8 hooks: # Run the linter. - id: ruff diff --git a/pyproject.toml b/pyproject.toml index 981dca4ca291b..9a1a059a9a222 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "ruff" -version = "0.1.7" +version = "0.1.8" description = "An extremely fast Python linter and code formatter, written in Rust." authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }] readme = "README.md" diff --git a/scripts/benchmarks/pyproject.toml b/scripts/benchmarks/pyproject.toml index 669c6f794d7b4..c7b4070e1a19a 100644 --- a/scripts/benchmarks/pyproject.toml +++ b/scripts/benchmarks/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "scripts" -version = "0.1.7" +version = "0.1.8" description = "" authors = ["Charles Marsh "] From b8fc006e52f48ab2d45329357e175aeb49d412c1 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 13 Dec 2023 14:39:57 -0500 Subject: [PATCH 182/197] Fix blog post URL in changelog (#9119) Closes https://github.com/astral-sh/ruff/issues/9118. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fda890d53892..cebb80b27088e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This release includes opt-in support for formatting Python snippets within docstrings via the `docstring-code-format` setting. -[Check out the blog post](https://astral.sh/blog/v0.1.8) for more details! +[Check out the blog post](https://astral.sh/blog/ruff-v0.1.8) for more details! ### Preview features From 7256b882b92150fbc5f646c7aa41f98044e8d535 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Thu, 14 Dec 2023 13:58:17 +0900 Subject: [PATCH 183/197] Fix `can_omit_optional_parentheses` for expressions with a right most fstring (#9124) --- .../test/fixtures/ruff/expression/binary.py | 12 +++++++ .../src/expression/mod.rs | 36 ++++++++++--------- .../format@expression__binary.py.snap | 24 +++++++++++++ 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/binary.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/binary.py index 5d91dc500a930..83c6f0ff9fc3a 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/binary.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/binary.py @@ -319,6 +319,18 @@ ) ) +# Skip FString content when determining whether to omit optional parentheses or not.0 +# The below expression should be parenthesized because it ends with an fstring and starts with a name. +# (Call expressions at the beginning don't count as parenthesized because they don't start with parens). +assert ( + format.format_event(spec) + == f'Event("_remove_cookie", {{key:`testkey`,options:{json.dumps(options)}}})' +) +# Avoid parentheses for this example because it starts with a tuple expression. +assert ( + (spec, format) + == f'Event("_remove_cookie", {{key:`testkey`,options:{json.dumps(options)}}})' +) rowuses = [(1 << j) | # column ordinal (1 << (n + i-j + n-1)) | # NW-SE ordinal diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index 084a138912b70..391a61fd26af5 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -552,17 +552,13 @@ fn can_omit_optional_parentheses(expr: &Expr, context: &PyFormatContext) -> bool // Only use the layout if the first expression starts with parentheses // or the last expression ends with parentheses of some sort, and // those parentheses are non-empty. - if visitor + visitor .last .is_some_and(|last| is_parenthesized(last, context)) - { - true - } else { - visitor + || visitor .first .expression() .is_some_and(|first| is_parenthesized(first, context)) - } } } @@ -689,16 +685,6 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> { // Don't walk the slice, because the slice is always parenthesized. return; } - Expr::UnaryOp(ast::ExprUnaryOp { - range: _, - op, - operand: _, - }) => { - if op.is_invert() { - self.update_max_precedence(OperatorPrecedence::BitwiseInversion); - } - self.first.set_if_none(First::Token); - } // `[a, b].test.test[300].dot` Expr::Attribute(ast::ExprAttribute { @@ -727,10 +713,23 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> { } Expr::FString(ast::ExprFString { value, .. }) if value.is_implicit_concatenated() => { self.update_max_precedence(OperatorPrecedence::String); + return; } // Expressions with sub expressions but a preceding token // Mark this expression as first expression and not the sub expression. + // Visit the sub-expressions because the sub expressions may be the end of the entire expression. + Expr::UnaryOp(ast::ExprUnaryOp { + range: _, + op, + operand: _, + }) => { + if op.is_invert() { + self.update_max_precedence(OperatorPrecedence::BitwiseInversion); + } + self.first.set_if_none(First::Token); + } + Expr::Lambda(_) | Expr::Await(_) | Expr::Yield(_) @@ -739,6 +738,7 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> { self.first.set_if_none(First::Token); } + // Terminal nodes or nodes that wrap a sub-expression (where the sub expression can never be the end). Expr::Tuple(_) | Expr::NamedExpr(_) | Expr::GeneratorExp(_) @@ -751,7 +751,9 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> { | Expr::EllipsisLiteral(_) | Expr::Name(_) | Expr::Slice(_) - | Expr::IpyEscapeCommand(_) => {} + | Expr::IpyEscapeCommand(_) => { + return; + } }; walk_expr(self, expr); diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__binary.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__binary.py.snap index e245378863ad4..1d59b5b13a1bc 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__binary.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__binary.py.snap @@ -325,6 +325,18 @@ expected_content = ( ) ) +# Skip FString content when determining whether to omit optional parentheses or not.0 +# The below expression should be parenthesized because it ends with an fstring and starts with a name. +# (Call expressions at the beginning don't count as parenthesized because they don't start with parens). +assert ( + format.format_event(spec) + == f'Event("_remove_cookie", {{key:`testkey`,options:{json.dumps(options)}}})' +) +# Avoid parentheses for this example because it starts with a tuple expression. +assert ( + (spec, format) + == f'Event("_remove_cookie", {{key:`testkey`,options:{json.dumps(options)}}})' +) rowuses = [(1 << j) | # column ordinal (1 << (n + i-j + n-1)) | # NW-SE ordinal @@ -790,6 +802,18 @@ expected_content = ( ) ) +# Skip FString content when determining whether to omit optional parentheses or not.0 +# The below expression should be parenthesized because it ends with an fstring and starts with a name. +# (Call expressions at the beginning don't count as parenthesized because they don't start with parens). +assert ( + format.format_event(spec) + == f'Event("_remove_cookie", {{key:`testkey`,options:{json.dumps(options)}}})' +) +# Avoid parentheses for this example because it starts with a tuple expression. +assert ( + spec, + format, +) == f'Event("_remove_cookie", {{key:`testkey`,options:{json.dumps(options)}}})' rowuses = [ (1 << j) # column ordinal From c99eae2c08df71b5d3477324259e5f8c49bf5018 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Thu, 14 Dec 2023 15:02:53 +0900 Subject: [PATCH 184/197] `can_omit_optional_parentheses`: Exit early for unparenthesized expressions (#9125) --- .../src/expression/mod.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index 391a61fd26af5..f2b020af4950c 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -533,15 +533,15 @@ fn can_omit_optional_parentheses(expr: &Expr, context: &PyFormatContext) -> bool let mut visitor = CanOmitOptionalParenthesesVisitor::new(context); visitor.visit_subexpression(expr); - if visitor.max_precedence == OperatorPrecedence::None { + if !visitor.any_parenthesized_expressions { + // Only use the more complex IR when there is any expression that we can possibly split by + false + } else if visitor.max_precedence == OperatorPrecedence::None { true } else if visitor.max_precedence_count > 1 { false } else if visitor.max_precedence == OperatorPrecedence::Attribute { true - } else if !visitor.any_parenthesized_expressions { - // Only use the more complex IR when there is any expression that we can possibly split by - false } else { fn is_parenthesized(expr: &Expr, context: &PyFormatContext) -> bool { // Don't break subscripts except in parenthesized context. It looks weird. @@ -716,6 +716,9 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> { return; } + // Non terminal nodes that don't have a termination token. + Expr::NamedExpr(_) | Expr::GeneratorExp(_) | Expr::Tuple(_) => {} + // Expressions with sub expressions but a preceding token // Mark this expression as first expression and not the sub expression. // Visit the sub-expressions because the sub expressions may be the end of the entire expression. @@ -738,11 +741,8 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> { self.first.set_if_none(First::Token); } - // Terminal nodes or nodes that wrap a sub-expression (where the sub expression can never be the end). - Expr::Tuple(_) - | Expr::NamedExpr(_) - | Expr::GeneratorExp(_) - | Expr::FString(_) + // Terminal nodes or nodes that wrap a sub-expression (where the sub expression can never be at the end). + Expr::FString(_) | Expr::StringLiteral(_) | Expr::BytesLiteral(_) | Expr::NumberLiteral(_) From 28b1aa201bc2dfd9653c643f1f5d33c5309bbd86 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Thu, 14 Dec 2023 09:53:43 -0500 Subject: [PATCH 185/197] ruff_python_formatter: fix 'dynamic' mode with doctests (#9129) This fixes a bug where the current indent level was not calculated correctly for doctests. Namely, it didn't account for the extra indent level (in terms of ASCII spaces) used by by the PS1 (`>>> `) and PS2 (`... `) prompts. As a result, lines could extend up to 4 spaces beyond the configured line length limit. We fix that by passing the `CodeExampleKind` to the `format` routine instead of just the code itself. In this way, `format` can query whether there will be any extra indent added _after_ formatting the code and take that into account for its line length setting. We add a few regression tests, taken directly from @stinodego's examples. Fixes #9126 --- ...string_code_examples_dynamic_line_width.py | 49 ++++ .../src/expression/string/docstring.rs | 43 ++- ...g_code_examples_dynamic_line_width.py.snap | 245 ++++++++++++++++++ 3 files changed, 325 insertions(+), 12 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_dynamic_line_width.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_dynamic_line_width.py index 04027909eda6e..e84d3b0707b8b 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_dynamic_line_width.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_dynamic_line_width.py @@ -170,3 +170,52 @@ def abcdefghijklmnopqrstuvwxyz(abc, ddef, ghi, jkl, mno, pqr, stu, vwx, yz, a1, Done. """ pass + + +# See: https://github.com/astral-sh/ruff/issues/9126 +def doctest_extra_indent1(): + """ + Docstring example containing a class. + + Examples + -------- + >>> @pl.api.register_dataframe_namespace("split") + ... class SplitFrame: + ... def __init__(self, df: pl.DataFrame): + ... self._df = df + ... + ... def by_first_letter_of_column_values(self, col: str) -> list[pl.DataFrame]: + ... return [ + ... self._df.filter(pl.col(col).str.starts_with(c)) + ... for c in sorted( + ... set(df.select(pl.col(col).str.slice(0, 1)).to_series()) + ... ) + ... ] + """ + + +# See: https://github.com/astral-sh/ruff/issues/9126 +class DoctestExtraIndent2: + def example2(): + """ + Regular docstring of class method. + + Examples + -------- + >>> df = pl.DataFrame( + ... {"foo": [1, 2, 3], "bar": [6, 7, 8], "ham": ["a", "b", "c"]} + ... ) + """ + + +# See: https://github.com/astral-sh/ruff/issues/9126 +def doctest_extra_indent3(): + """ + Pragma comment. + + Examples + -------- + >>> af1, af2, af3 = pl.align_frames( + ... df1, df2, df3, on="dt" + ... ) # doctest: +IGNORE_RESULT + """ diff --git a/crates/ruff_python_formatter/src/expression/string/docstring.rs b/crates/ruff_python_formatter/src/expression/string/docstring.rs index e750a52641b03..9037edcd91519 100644 --- a/crates/ruff_python_formatter/src/expression/string/docstring.rs +++ b/crates/ruff_python_formatter/src/expression/string/docstring.rs @@ -316,7 +316,7 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { } } CodeExampleAddAction::Format { mut kind } => { - let Some(formatted_lines) = self.format(kind.code())? else { + let Some(formatted_lines) = self.format(&mut kind)? else { // Since we've failed to emit these lines, we need to // put them back in the queue but have them jump to the // front of the queue to get processed before any other @@ -432,9 +432,13 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { Ok(()) } - /// Given a sequence of lines from a code snippet, format them and return + /// Given a code example, format them and return /// the formatted code as a sequence of owned docstring lines. /// + /// This may mutate the code example in place if extracting the lines of + /// code requires adjusting which part of each line is used for the actual + /// code bit. + /// /// This routine generally only returns an error when the recursive call /// to the formatter itself returns a `FormatError`. In all other cases /// (for example, if the code snippet is invalid Python or even if the @@ -448,29 +452,33 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> { /// but at time of writing, it wasn't clear to me how to best do that. fn format( &mut self, - code: &[CodeExampleLine<'_>], + kind: &mut CodeExampleKind<'_>, ) -> FormatResult>>> { use ruff_python_parser::AsMode; - let (Some(unformatted_first), Some(unformatted_last)) = (code.first(), code.last()) else { - return Ok(None); - }; - let codeblob = code - .iter() - .map(|line| line.code) - .collect::>() - .join("\n"); let line_width = match self.f.options().docstring_code_line_width() { DocstringCodeLineWidth::Fixed(width) => width, DocstringCodeLineWidth::Dynamic => { let global_line_width = self.f.options().line_width().value(); let indent_width = self.f.options().indent_width(); let indent_level = self.f.context().indent_level(); - let current_indent = indent_level.to_ascii_spaces(indent_width); + let current_indent = indent_level + .to_ascii_spaces(indent_width) + .saturating_add(kind.extra_indent_ascii_spaces()); let width = std::cmp::max(1, global_line_width.saturating_sub(current_indent)); LineWidth::try_from(width).expect("width is capped at a minimum of 1") } }; + + let code = kind.code(); + let (Some(unformatted_first), Some(unformatted_last)) = (code.first(), code.last()) else { + return Ok(None); + }; + let codeblob = code + .iter() + .map(|line| line.code) + .collect::>() + .join("\n"); let options = self .f .options() @@ -778,6 +786,17 @@ impl<'src> CodeExampleKind<'src> { CodeExampleKind::Markdown(fenced) => fenced.lines, } } + + /// This returns any extra indent that will be added after formatting this + /// code example. + /// + /// The extra indent is expressed in units of ASCII space characters. + fn extra_indent_ascii_spaces(&self) -> u16 { + match *self { + CodeExampleKind::Doctest(_) => 4, + _ => 0, + } + } } /// State corresponding to a single doctest code example found in a docstring. diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_dynamic_line_width.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_dynamic_line_width.py.snap index 91c1984124c9d..1bab5f433b52a 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_dynamic_line_width.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_dynamic_line_width.py.snap @@ -176,6 +176,55 @@ class Abcdefghijklmopqrstuvwxyz(Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1, Done. """ pass + + +# See: https://github.com/astral-sh/ruff/issues/9126 +def doctest_extra_indent1(): + """ + Docstring example containing a class. + + Examples + -------- + >>> @pl.api.register_dataframe_namespace("split") + ... class SplitFrame: + ... def __init__(self, df: pl.DataFrame): + ... self._df = df + ... + ... def by_first_letter_of_column_values(self, col: str) -> list[pl.DataFrame]: + ... return [ + ... self._df.filter(pl.col(col).str.starts_with(c)) + ... for c in sorted( + ... set(df.select(pl.col(col).str.slice(0, 1)).to_series()) + ... ) + ... ] + """ + + +# See: https://github.com/astral-sh/ruff/issues/9126 +class DoctestExtraIndent2: + def example2(): + """ + Regular docstring of class method. + + Examples + -------- + >>> df = pl.DataFrame( + ... {"foo": [1, 2, 3], "bar": [6, 7, 8], "ham": ["a", "b", "c"]} + ... ) + """ + + +# See: https://github.com/astral-sh/ruff/issues/9126 +def doctest_extra_indent3(): + """ + Pragma comment. + + Examples + -------- + >>> af1, af2, af3 = pl.align_frames( + ... df1, df2, df3, on="dt" + ... ) # doctest: +IGNORE_RESULT + """ ``` ## Outputs @@ -433,6 +482,55 @@ def unindented_barely_exceeds_limit(): Done. """ pass + + +# See: https://github.com/astral-sh/ruff/issues/9126 +def doctest_extra_indent1(): + """ + Docstring example containing a class. + + Examples + -------- + >>> @pl.api.register_dataframe_namespace("split") + ... class SplitFrame: + ... def __init__(self, df: pl.DataFrame): + ... self._df = df + ... + ... def by_first_letter_of_column_values(self, col: str) -> list[pl.DataFrame]: + ... return [ + ... self._df.filter(pl.col(col).str.starts_with(c)) + ... for c in sorted( + ... set(df.select(pl.col(col).str.slice(0, 1)).to_series()) + ... ) + ... ] + """ + + +# See: https://github.com/astral-sh/ruff/issues/9126 +class DoctestExtraIndent2: + def example2(): + """ + Regular docstring of class method. + + Examples + -------- + >>> df = pl.DataFrame( + ... {"foo": [1, 2, 3], "bar": [6, 7, 8], "ham": ["a", "b", "c"]} + ... ) + """ + + +# See: https://github.com/astral-sh/ruff/issues/9126 +def doctest_extra_indent3(): + """ + Pragma comment. + + Examples + -------- + >>> af1, af2, af3 = pl.align_frames( + ... df1, df2, df3, on="dt" + ... ) # doctest: +IGNORE_RESULT + """ ``` @@ -686,6 +784,49 @@ def unindented_barely_exceeds_limit(): Done. """ pass + + +# See: https://github.com/astral-sh/ruff/issues/9126 +def doctest_extra_indent1(): + """ + Docstring example containing a class. + + Examples + -------- + >>> @pl.api.register_dataframe_namespace("split") + ... class SplitFrame: + ... def __init__(self, df: pl.DataFrame): + ... self._df = df + ... + ... def by_first_letter_of_column_values(self, col: str) -> list[pl.DataFrame]: + ... return [ + ... self._df.filter(pl.col(col).str.starts_with(c)) + ... for c in sorted(set(df.select(pl.col(col).str.slice(0, 1)).to_series())) + ... ] + """ + + +# See: https://github.com/astral-sh/ruff/issues/9126 +class DoctestExtraIndent2: + def example2(): + """ + Regular docstring of class method. + + Examples + -------- + >>> df = pl.DataFrame({"foo": [1, 2, 3], "bar": [6, 7, 8], "ham": ["a", "b", "c"]}) + """ + + +# See: https://github.com/astral-sh/ruff/issues/9126 +def doctest_extra_indent3(): + """ + Pragma comment. + + Examples + -------- + >>> af1, af2, af3 = pl.align_frames(df1, df2, df3, on="dt") # doctest: +IGNORE_RESULT + """ ``` @@ -943,6 +1084,55 @@ def unindented_barely_exceeds_limit(): Done. """ pass + + +# See: https://github.com/astral-sh/ruff/issues/9126 +def doctest_extra_indent1(): + """ + Docstring example containing a class. + + Examples + -------- + >>> @pl.api.register_dataframe_namespace("split") + ... class SplitFrame: + ... def __init__(self, df: pl.DataFrame): + ... self._df = df + ... + ... def by_first_letter_of_column_values(self, col: str) -> list[pl.DataFrame]: + ... return [ + ... self._df.filter(pl.col(col).str.starts_with(c)) + ... for c in sorted( + ... set(df.select(pl.col(col).str.slice(0, 1)).to_series()) + ... ) + ... ] + """ + + +# See: https://github.com/astral-sh/ruff/issues/9126 +class DoctestExtraIndent2: + def example2(): + """ + Regular docstring of class method. + + Examples + -------- + >>> df = pl.DataFrame( + ... {"foo": [1, 2, 3], "bar": [6, 7, 8], "ham": ["a", "b", "c"]} + ... ) + """ + + +# See: https://github.com/astral-sh/ruff/issues/9126 +def doctest_extra_indent3(): + """ + Pragma comment. + + Examples + -------- + >>> af1, af2, af3 = pl.align_frames( + ... df1, df2, df3, on="dt" + ... ) # doctest: +IGNORE_RESULT + """ ``` @@ -1624,6 +1814,61 @@ def unindented_barely_exceeds_limit(): Done. """ pass + + +# See: https://github.com/astral-sh/ruff/issues/9126 +def doctest_extra_indent1(): + """ + Docstring example containing a class. + + Examples + -------- + >>> @pl.api.register_dataframe_namespace("split") + ... class SplitFrame: + ... def __init__(self, df: pl.DataFrame): + ... self._df = df + ... + ... def by_first_letter_of_column_values( + ... self, col: str + ... ) -> list[pl.DataFrame]: + ... return [ + ... self._df.filter(pl.col(col).str.starts_with(c)) + ... for c in sorted( + ... set( + ... df.select( + ... pl.col(col).str.slice(0, 1) + ... ).to_series() + ... ) + ... ) + ... ] + """ + + +# See: https://github.com/astral-sh/ruff/issues/9126 +class DoctestExtraIndent2: + def example2(): + """ + Regular docstring of class method. + + Examples + -------- + >>> df = pl.DataFrame( + ... {"foo": [1, 2, 3], "bar": [6, 7, 8], "ham": ["a", "b", "c"]} + ... ) + """ + + +# See: https://github.com/astral-sh/ruff/issues/9126 +def doctest_extra_indent3(): + """ + Pragma comment. + + Examples + -------- + >>> af1, af2, af3 = pl.align_frames( + ... df1, df2, df3, on="dt" + ... ) # doctest: +IGNORE_RESULT + """ ``` From 189e947808f15932450dfc384dbe4c1219502550 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Thu, 14 Dec 2023 12:55:10 -0600 Subject: [PATCH 186/197] Split string formatting to individual nodes (#9058) This PR splits the string formatting code in the formatter to be handled by the respective nodes. Previously, the string formatting was done through a single `FormatString` interface. Now, the nodes themselves are responsible for formatting. The following changes were made: 1. Remove `StringLayout::ImplicitStringConcatenationInBinaryLike` and inline the call to `FormatStringContinuation`. After the refactor, the binary like formatting would delegate to `FormatString` which would then delegate to `FormatStringContinuation`. This removes the intermediary steps. 2. Add formatter implementation for `FStringPart` which delegates it to the respective string literal or f-string node. 3. Add `ExprStringLiteralKind` which is either `String` or `Docstring`. If it's a docstring variant, then the string expression would not be implicitly concatenated. This is guaranteed by the `DocstringStmt::try_from_expression` constructor. 4. Add `StringLiteralKind` which is either a `String`, `Docstring` or `InImplicitlyConcatenatedFString`. The last variant is for when the string literal is implicitly concatenated with an f-string (`"foo" f"bar {x}"`). 5. Remove `FormatString`. 6. Extract the f-string quote detection as a standalone function which is public to the crate. This is used to detect the quote to be used for an f-string at the expression level (`ExprFString` or `FormatStringContinuation`). ### Formatter ecosystem result **This PR** | project | similarity index | total files | changed files | |----------------|------------------:|------------------:|------------------:| | cpython | 0.75804 | 1799 | 1648 | | django | 0.99984 | 2772 | 34 | | home-assistant | 0.99955 | 10596 | 214 | | poetry | 0.99905 | 321 | 15 | | transformers | 0.99967 | 2657 | 324 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99980 | 3669 | 18 | | warehouse | 0.99976 | 654 | 14 | | zulip | 0.99958 | 1459 | 36 | **main** | project | similarity index | total files | changed files | |----------------|------------------:|------------------:|------------------:| | cpython | 0.75804 | 1799 | 1648 | | django | 0.99984 | 2772 | 34 | | home-assistant | 0.99955 | 10596 | 214 | | poetry | 0.99905 | 321 | 15 | | transformers | 0.99967 | 2657 | 324 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99980 | 3669 | 18 | | warehouse | 0.99976 | 654 | 14 | | zulip | 0.99958 | 1459 | 36 | --- crates/ruff_python_formatter/generate.py | 12 +- crates/ruff_python_formatter/src/context.rs | 2 +- .../src/expression/binary_like.rs | 16 +- .../src/expression/expr_bytes_literal.rs | 14 +- .../src/expression/expr_f_string.rs | 55 ++++- .../src/expression/expr_string_literal.rs | 54 +++- .../src/expression/mod.rs | 1 - crates/ruff_python_formatter/src/generated.rs | 64 ----- crates/ruff_python_formatter/src/lib.rs | 1 + .../src/other/bytes_literal.rs | 15 +- .../src/other/f_string.rs | 47 +++- .../src/other/f_string_part.rs | 39 +++ crates/ruff_python_formatter/src/other/mod.rs | 1 + .../src/other/string_literal.rs | 70 +++++- .../src/statement/suite.rs | 4 +- .../src/{expression => }/string/docstring.rs | 2 +- .../src/{expression => }/string/mod.rs | 233 ++++++------------ 17 files changed, 364 insertions(+), 266 deletions(-) create mode 100644 crates/ruff_python_formatter/src/other/f_string_part.rs rename crates/ruff_python_formatter/src/{expression => }/string/docstring.rs (99%) rename crates/ruff_python_formatter/src/{expression => }/string/mod.rs (79%) diff --git a/crates/ruff_python_formatter/generate.py b/crates/ruff_python_formatter/generate.py index 16fddd11fbd7e..bf89ac1a4b523 100755 --- a/crates/ruff_python_formatter/generate.py +++ b/crates/ruff_python_formatter/generate.py @@ -33,9 +33,15 @@ def rustfmt(code: str) -> str: nodes = [] for node_line in node_lines: node = node_line.split("(")[1].split(")")[0].split("::")[-1].split("<")[0] - # These nodes aren't used in the formatter as the formatting of them is handled - # in one of the other nodes containing them. - if node in ("FStringLiteralElement", "FStringExpressionElement"): + # `FString` and `StringLiteral` has a custom implementation while the formatting for + # `FStringLiteralElement` and `FStringExpressionElement` are handled by the `FString` + # implementation. + if node in ( + "FString", + "StringLiteral", + "FStringLiteralElement", + "FStringExpressionElement", + ): continue nodes.append(node) print(nodes) diff --git a/crates/ruff_python_formatter/src/context.rs b/crates/ruff_python_formatter/src/context.rs index 8407e7cdc4323..b5dc85fcb3039 100644 --- a/crates/ruff_python_formatter/src/context.rs +++ b/crates/ruff_python_formatter/src/context.rs @@ -1,5 +1,5 @@ use crate::comments::Comments; -use crate::expression::string::QuoteChar; +use crate::string::QuoteChar; use crate::PyFormatOptions; use ruff_formatter::{Buffer, FormatContext, GroupId, IndentWidth, SourceCode}; use ruff_source_file::Locator; diff --git a/crates/ruff_python_formatter/src/expression/binary_like.rs b/crates/ruff_python_formatter/src/expression/binary_like.rs index 9a9feea584831..3e153ad8c2358 100644 --- a/crates/ruff_python_formatter/src/expression/binary_like.rs +++ b/crates/ruff_python_formatter/src/expression/binary_like.rs @@ -18,10 +18,10 @@ use crate::expression::parentheses::{ is_expression_parenthesized, write_in_parentheses_only_group_end_tag, write_in_parentheses_only_group_start_tag, Parentheses, }; -use crate::expression::string::{AnyString, FormatString, StringLayout}; use crate::expression::OperatorPrecedence; use crate::prelude::*; use crate::preview::is_fix_power_op_line_length_enabled; +use crate::string::{AnyString, FormatStringContinuation}; #[derive(Copy, Clone, Debug)] pub(super) enum BinaryLike<'a> { @@ -395,9 +395,10 @@ impl Format> for BinaryLike<'_> { [ operand.leading_binary_comments().map(leading_comments), leading_comments(comments.leading(&string_constant)), - FormatString::new(&string_constant).with_layout( - StringLayout::ImplicitConcatenatedStringInBinaryLike, - ), + // Call `FormatStringContinuation` directly to avoid formatting + // the implicitly concatenated string with the enclosing group + // because the group is added by the binary like formatting. + FormatStringContinuation::new(&string_constant), trailing_comments(comments.trailing(&string_constant)), operand.trailing_binary_comments().map(trailing_comments), line_suffix_boundary(), @@ -413,9 +414,10 @@ impl Format> for BinaryLike<'_> { f, [ leading_comments(comments.leading(&string_constant)), - FormatString::new(&string_constant).with_layout( - StringLayout::ImplicitConcatenatedStringInBinaryLike - ), + // Call `FormatStringContinuation` directly to avoid formatting + // the implicitly concatenated string with the enclosing group + // because the group is added by the binary like formatting. + FormatStringContinuation::new(&string_constant), trailing_comments(comments.trailing(&string_constant)), ] )?; diff --git a/crates/ruff_python_formatter/src/expression/expr_bytes_literal.rs b/crates/ruff_python_formatter/src/expression/expr_bytes_literal.rs index 2fc0cd474ce77..4869a2d536908 100644 --- a/crates/ruff_python_formatter/src/expression/expr_bytes_literal.rs +++ b/crates/ruff_python_formatter/src/expression/expr_bytes_literal.rs @@ -3,16 +3,24 @@ use ruff_python_ast::ExprBytesLiteral; use crate::comments::SourceComment; use crate::expression::expr_string_literal::is_multiline_string; -use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses}; -use crate::expression::string::{AnyString, FormatString}; +use crate::expression::parentheses::{ + in_parentheses_only_group, NeedsParentheses, OptionalParentheses, +}; use crate::prelude::*; +use crate::string::{AnyString, FormatStringContinuation}; #[derive(Default)] pub struct FormatExprBytesLiteral; impl FormatNodeRule for FormatExprBytesLiteral { fn fmt_fields(&self, item: &ExprBytesLiteral, f: &mut PyFormatter) -> FormatResult<()> { - FormatString::new(&AnyString::Bytes(item)).fmt(f) + let ExprBytesLiteral { value, .. } = item; + + match value.as_slice() { + [bytes_literal] => bytes_literal.format().fmt(f), + _ => in_parentheses_only_group(&FormatStringContinuation::new(&AnyString::Bytes(item))) + .fmt(f), + } } fn fmt_dangling_comments( diff --git a/crates/ruff_python_formatter/src/expression/expr_f_string.rs b/crates/ruff_python_formatter/src/expression/expr_f_string.rs index 12e112ecc1638..8a8ac81d3524e 100644 --- a/crates/ruff_python_formatter/src/expression/expr_f_string.rs +++ b/crates/ruff_python_formatter/src/expression/expr_f_string.rs @@ -1,21 +1,35 @@ use memchr::memchr2; -use crate::comments::SourceComment; -use ruff_formatter::FormatResult; -use ruff_python_ast::AnyNodeRef; -use ruff_python_ast::ExprFString; +use ruff_python_ast::{AnyNodeRef, ExprFString}; +use ruff_source_file::Locator; +use ruff_text_size::Ranged; -use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses}; +use crate::comments::SourceComment; +use crate::expression::parentheses::{ + in_parentheses_only_group, NeedsParentheses, OptionalParentheses, +}; +use crate::other::f_string_part::FormatFStringPart; use crate::prelude::*; - -use super::string::{AnyString, FormatString}; +use crate::string::{AnyString, FormatStringContinuation, Quoting}; #[derive(Default)] pub struct FormatExprFString; impl FormatNodeRule for FormatExprFString { fn fmt_fields(&self, item: &ExprFString, f: &mut PyFormatter) -> FormatResult<()> { - FormatString::new(&AnyString::FString(item)).fmt(f) + let ExprFString { value, .. } = item; + + match value.as_slice() { + [f_string_part] => FormatFStringPart::new( + f_string_part, + f_string_quoting(item, &f.context().locator()), + ) + .fmt(f), + _ => { + in_parentheses_only_group(&FormatStringContinuation::new(&AnyString::FString(item))) + .fmt(f) + } + } } fn fmt_dangling_comments( @@ -43,3 +57,28 @@ impl NeedsParentheses for ExprFString { } } } + +pub(crate) fn f_string_quoting(f_string: &ExprFString, locator: &Locator) -> Quoting { + let unprefixed = locator + .slice(f_string.range()) + .trim_start_matches(|c| c != '"' && c != '\''); + let triple_quoted = unprefixed.starts_with(r#"""""#) || unprefixed.starts_with(r"'''"); + + if f_string + .value + .elements() + .filter_map(|element| element.as_expression()) + .any(|expression| { + let string_content = locator.slice(expression.range()); + if triple_quoted { + string_content.contains(r#"""""#) || string_content.contains("'''") + } else { + string_content.contains(['"', '\'']) + } + }) + { + Quoting::Preserve + } else { + Quoting::CanChange + } +} diff --git a/crates/ruff_python_formatter/src/expression/expr_string_literal.rs b/crates/ruff_python_formatter/src/expression/expr_string_literal.rs index 199fb740ef712..442081886d2ca 100644 --- a/crates/ruff_python_formatter/src/expression/expr_string_literal.rs +++ b/crates/ruff_python_formatter/src/expression/expr_string_literal.rs @@ -1,34 +1,66 @@ use ruff_formatter::FormatRuleWithOptions; -use ruff_python_ast::AnyNodeRef; -use ruff_python_ast::ExprStringLiteral; +use ruff_python_ast::{AnyNodeRef, ExprStringLiteral}; use ruff_text_size::{Ranged, TextLen, TextRange}; use crate::comments::SourceComment; -use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses}; -use crate::expression::string::{ - AnyString, FormatString, StringLayout, StringPrefix, StringQuotes, +use crate::expression::parentheses::{ + in_parentheses_only_group, NeedsParentheses, OptionalParentheses, }; +use crate::other::string_literal::{FormatStringLiteral, StringLiteralKind}; use crate::prelude::*; +use crate::string::{AnyString, FormatStringContinuation, StringPrefix, StringQuotes}; #[derive(Default)] pub struct FormatExprStringLiteral { - layout: StringLayout, + kind: ExprStringLiteralKind, +} + +#[derive(Default, Copy, Clone, Debug)] +pub enum ExprStringLiteralKind { + #[default] + String, + Docstring, +} + +impl ExprStringLiteralKind { + const fn string_literal_kind(self) -> StringLiteralKind { + match self { + ExprStringLiteralKind::String => StringLiteralKind::String, + ExprStringLiteralKind::Docstring => StringLiteralKind::Docstring, + } + } + + const fn is_docstring(self) -> bool { + matches!(self, ExprStringLiteralKind::Docstring) + } } impl FormatRuleWithOptions> for FormatExprStringLiteral { - type Options = StringLayout; + type Options = ExprStringLiteralKind; fn with_options(mut self, options: Self::Options) -> Self { - self.layout = options; + self.kind = options; self } } impl FormatNodeRule for FormatExprStringLiteral { fn fmt_fields(&self, item: &ExprStringLiteral, f: &mut PyFormatter) -> FormatResult<()> { - FormatString::new(&AnyString::String(item)) - .with_layout(self.layout) - .fmt(f) + let ExprStringLiteral { value, .. } = item; + + match value.as_slice() { + [string_literal] => { + FormatStringLiteral::new(string_literal, self.kind.string_literal_kind()).fmt(f) + } + _ => { + // This is just a sanity check because [`DocstringStmt::try_from_statement`] + // ensures that the docstring is a *single* string literal. + assert!(!self.kind.is_docstring()); + + in_parentheses_only_group(&FormatStringContinuation::new(&AnyString::String(item))) + } + .fmt(f), + } } fn fmt_dangling_comments( diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index f2b020af4950c..335941316cfde 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -58,7 +58,6 @@ pub(crate) mod expr_yield; pub(crate) mod expr_yield_from; mod operator; pub(crate) mod parentheses; -pub(crate) mod string; #[derive(Copy, Clone, PartialEq, Eq, Default)] pub struct FormatExpr { diff --git a/crates/ruff_python_formatter/src/generated.rs b/crates/ruff_python_formatter/src/generated.rs index 5b01cd16f842b..a5217a11d1487 100644 --- a/crates/ruff_python_formatter/src/generated.rs +++ b/crates/ruff_python_formatter/src/generated.rs @@ -2943,70 +2943,6 @@ impl<'ast> IntoFormat> for ast::TypeParamParamSpec { } } -impl FormatRule> for crate::other::f_string::FormatFString { - #[inline] - fn fmt(&self, node: &ast::FString, f: &mut PyFormatter) -> FormatResult<()> { - FormatNodeRule::::fmt(self, node, f) - } -} -impl<'ast> AsFormat> for ast::FString { - type Format<'a> = FormatRefWithRule< - 'a, - ast::FString, - crate::other::f_string::FormatFString, - PyFormatContext<'ast>, - >; - fn format(&self) -> Self::Format<'_> { - FormatRefWithRule::new(self, crate::other::f_string::FormatFString::default()) - } -} -impl<'ast> IntoFormat> for ast::FString { - type Format = FormatOwnedWithRule< - ast::FString, - crate::other::f_string::FormatFString, - PyFormatContext<'ast>, - >; - fn into_format(self) -> Self::Format { - FormatOwnedWithRule::new(self, crate::other::f_string::FormatFString::default()) - } -} - -impl FormatRule> - for crate::other::string_literal::FormatStringLiteral -{ - #[inline] - fn fmt(&self, node: &ast::StringLiteral, f: &mut PyFormatter) -> FormatResult<()> { - FormatNodeRule::::fmt(self, node, f) - } -} -impl<'ast> AsFormat> for ast::StringLiteral { - type Format<'a> = FormatRefWithRule< - 'a, - ast::StringLiteral, - crate::other::string_literal::FormatStringLiteral, - PyFormatContext<'ast>, - >; - fn format(&self) -> Self::Format<'_> { - FormatRefWithRule::new( - self, - crate::other::string_literal::FormatStringLiteral::default(), - ) - } -} -impl<'ast> IntoFormat> for ast::StringLiteral { - type Format = FormatOwnedWithRule< - ast::StringLiteral, - crate::other::string_literal::FormatStringLiteral, - PyFormatContext<'ast>, - >; - fn into_format(self) -> Self::Format { - FormatOwnedWithRule::new( - self, - crate::other::string_literal::FormatStringLiteral::default(), - ) - } -} - impl FormatRule> for crate::other::bytes_literal::FormatBytesLiteral { diff --git a/crates/ruff_python_formatter/src/lib.rs b/crates/ruff_python_formatter/src/lib.rs index beaa4070c0c37..05f122606bd79 100644 --- a/crates/ruff_python_formatter/src/lib.rs +++ b/crates/ruff_python_formatter/src/lib.rs @@ -36,6 +36,7 @@ mod prelude; mod preview; mod shared_traits; pub(crate) mod statement; +pub(crate) mod string; pub(crate) mod type_param; mod verbatim; diff --git a/crates/ruff_python_formatter/src/other/bytes_literal.rs b/crates/ruff_python_formatter/src/other/bytes_literal.rs index 55117241f8598..c6445c8d6adc3 100644 --- a/crates/ruff_python_formatter/src/other/bytes_literal.rs +++ b/crates/ruff_python_formatter/src/other/bytes_literal.rs @@ -1,12 +1,23 @@ use ruff_python_ast::BytesLiteral; +use ruff_text_size::Ranged; use crate::prelude::*; +use crate::string::{Quoting, StringPart}; #[derive(Default)] pub struct FormatBytesLiteral; impl FormatNodeRule for FormatBytesLiteral { - fn fmt_fields(&self, _item: &BytesLiteral, _f: &mut PyFormatter) -> FormatResult<()> { - unreachable!("Handled inside of `FormatExprBytesLiteral`"); + fn fmt_fields(&self, item: &BytesLiteral, f: &mut PyFormatter) -> FormatResult<()> { + let locator = f.context().locator(); + + StringPart::from_source(item.range(), &locator) + .normalize( + Quoting::CanChange, + &locator, + f.options().quote_style(), + f.context().docstring(), + ) + .fmt(f) } } diff --git a/crates/ruff_python_formatter/src/other/f_string.rs b/crates/ruff_python_formatter/src/other/f_string.rs index e08254aba7511..da81162c2ef54 100644 --- a/crates/ruff_python_formatter/src/other/f_string.rs +++ b/crates/ruff_python_formatter/src/other/f_string.rs @@ -1,12 +1,49 @@ use ruff_python_ast::FString; +use ruff_text_size::Ranged; use crate::prelude::*; +use crate::string::{Quoting, StringPart}; -#[derive(Default)] -pub struct FormatFString; +/// Formats an f-string which is part of a larger f-string expression. +/// +/// For example, this would be used to format the f-string part in `"foo" f"bar {x}"` +/// or the standalone f-string in `f"foo {x} bar"`. +pub(crate) struct FormatFString<'a> { + value: &'a FString, + /// The quoting of an f-string. This is determined by the parent node + /// (f-string expression) and is required to format an f-string correctly. + quoting: Quoting, +} + +impl<'a> FormatFString<'a> { + pub(crate) fn new(value: &'a FString, quoting: Quoting) -> Self { + Self { value, quoting } + } +} + +impl Format> for FormatFString<'_> { + fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { + let locator = f.context().locator(); + + let result = StringPart::from_source(self.value.range(), &locator) + .normalize( + self.quoting, + &locator, + f.options().quote_style(), + f.context().docstring(), + ) + .fmt(f); + + // TODO(dhruvmanila): With PEP 701, comments can be inside f-strings. + // This is to mark all of those comments as formatted but we need to + // figure out how to handle them. Note that this needs to be done only + // after the f-string is formatted, so only for all the non-formatted + // comments. + let comments = f.context().comments(); + self.value.elements.iter().for_each(|value| { + comments.mark_verbatim_node_comments_formatted(value.into()); + }); -impl FormatNodeRule for FormatFString { - fn fmt_fields(&self, _item: &FString, _f: &mut PyFormatter) -> FormatResult<()> { - unreachable!("Handled inside of `FormatExprFString`"); + result } } diff --git a/crates/ruff_python_formatter/src/other/f_string_part.rs b/crates/ruff_python_formatter/src/other/f_string_part.rs new file mode 100644 index 0000000000000..c471b5fc8cd4f --- /dev/null +++ b/crates/ruff_python_formatter/src/other/f_string_part.rs @@ -0,0 +1,39 @@ +use ruff_python_ast::FStringPart; + +use crate::other::f_string::FormatFString; +use crate::other::string_literal::{FormatStringLiteral, StringLiteralKind}; +use crate::prelude::*; +use crate::string::Quoting; + +/// Formats an f-string part which is either a string literal or an f-string. +/// +/// This delegates the actual formatting to the appropriate formatter. +pub(crate) struct FormatFStringPart<'a> { + part: &'a FStringPart, + /// The quoting to be used for all the f-string parts. This is determined by + /// the parent node (f-string expression) and is required to format all parts + /// correctly. + quoting: Quoting, +} + +impl<'a> FormatFStringPart<'a> { + pub(crate) fn new(part: &'a FStringPart, quoting: Quoting) -> Self { + Self { part, quoting } + } +} + +impl Format> for FormatFStringPart<'_> { + fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { + match self.part { + FStringPart::Literal(string_literal) => FormatStringLiteral::new( + string_literal, + // If an f-string part is a string literal, the f-string is always + // implicitly concatenated e.g., `"foo" f"bar {x}"`. A standalone + // string literal would be a string expression, not an f-string. + StringLiteralKind::InImplicitlyConcatenatedFString(self.quoting), + ) + .fmt(f), + FStringPart::FString(f_string) => FormatFString::new(f_string, self.quoting).fmt(f), + } + } +} diff --git a/crates/ruff_python_formatter/src/other/mod.rs b/crates/ruff_python_formatter/src/other/mod.rs index c980a14c0fe09..d07339f717cbf 100644 --- a/crates/ruff_python_formatter/src/other/mod.rs +++ b/crates/ruff_python_formatter/src/other/mod.rs @@ -7,6 +7,7 @@ pub(crate) mod decorator; pub(crate) mod elif_else_clause; pub(crate) mod except_handler_except_handler; pub(crate) mod f_string; +pub(crate) mod f_string_part; pub(crate) mod identifier; pub(crate) mod keyword; pub(crate) mod match_case; diff --git a/crates/ruff_python_formatter/src/other/string_literal.rs b/crates/ruff_python_formatter/src/other/string_literal.rs index 291552db73a1d..e23db85707830 100644 --- a/crates/ruff_python_formatter/src/other/string_literal.rs +++ b/crates/ruff_python_formatter/src/other/string_literal.rs @@ -1,12 +1,72 @@ use ruff_python_ast::StringLiteral; +use ruff_text_size::Ranged; use crate::prelude::*; +use crate::string::{docstring, Quoting, StringPart}; +use crate::QuoteStyle; -#[derive(Default)] -pub struct FormatStringLiteral; +pub(crate) struct FormatStringLiteral<'a> { + value: &'a StringLiteral, + layout: StringLiteralKind, +} + +impl<'a> FormatStringLiteral<'a> { + pub(crate) fn new(value: &'a StringLiteral, layout: StringLiteralKind) -> Self { + Self { value, layout } + } +} + +/// The kind of a string literal. +#[derive(Copy, Clone, Debug, Default)] +pub(crate) enum StringLiteralKind { + /// A normal string literal e.g., `"foo"`. + #[default] + String, + /// A string literal used as a docstring. + Docstring, + /// A string literal that is implicitly concatenated with an f-string. This + /// makes the overall expression an f-string whose quoting detection comes + /// from the parent node (f-string expression). + InImplicitlyConcatenatedFString(Quoting), +} + +impl StringLiteralKind { + /// Checks if this string literal is a docstring. + pub(crate) const fn is_docstring(self) -> bool { + matches!(self, StringLiteralKind::Docstring) + } + + /// Returns the quoting to be used for this string literal. + fn quoting(self) -> Quoting { + match self { + StringLiteralKind::String | StringLiteralKind::Docstring => Quoting::CanChange, + StringLiteralKind::InImplicitlyConcatenatedFString(quoting) => quoting, + } + } +} + +impl Format> for FormatStringLiteral<'_> { + fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { + let locator = f.context().locator(); + + let quote_style = if self.layout.is_docstring() { + // Per PEP 8 and PEP 257, always prefer double quotes for docstrings + QuoteStyle::Double + } else { + f.options().quote_style() + }; + + let normalized = StringPart::from_source(self.value.range(), &locator).normalize( + self.layout.quoting(), + &locator, + quote_style, + f.context().docstring(), + ); -impl FormatNodeRule for FormatStringLiteral { - fn fmt_fields(&self, _item: &StringLiteral, _f: &mut PyFormatter) -> FormatResult<()> { - unreachable!("Handled inside of `FormatExprStringLiteral`"); + if self.layout.is_docstring() { + docstring::format(&normalized, f) + } else { + normalized.fmt(f) + } } } diff --git a/crates/ruff_python_formatter/src/statement/suite.rs b/crates/ruff_python_formatter/src/statement/suite.rs index 1b33dbd41aa16..8b3d9e1a5efbd 100644 --- a/crates/ruff_python_formatter/src/statement/suite.rs +++ b/crates/ruff_python_formatter/src/statement/suite.rs @@ -9,7 +9,7 @@ use crate::comments::{ leading_comments, trailing_comments, Comments, LeadingDanglingTrailingComments, }; use crate::context::{NodeLevel, TopLevelStatementPosition, WithIndentLevel, WithNodeLevel}; -use crate::expression::string::StringLayout; +use crate::expression::expr_string_literal::ExprStringLiteralKind; use crate::prelude::*; use crate::statement::stmt_expr::FormatStmtExpr; use crate::verbatim::{ @@ -609,7 +609,7 @@ impl Format> for DocstringStmt<'_> { leading_comments(node_comments.leading), string_literal .format() - .with_options(StringLayout::DocString), + .with_options(ExprStringLiteralKind::Docstring), ] )?; diff --git a/crates/ruff_python_formatter/src/expression/string/docstring.rs b/crates/ruff_python_formatter/src/string/docstring.rs similarity index 99% rename from crates/ruff_python_formatter/src/expression/string/docstring.rs rename to crates/ruff_python_formatter/src/string/docstring.rs index 9037edcd91519..51fee063ca97e 100644 --- a/crates/ruff_python_formatter/src/expression/string/docstring.rs +++ b/crates/ruff_python_formatter/src/string/docstring.rs @@ -102,7 +102,7 @@ use super::{NormalizedString, QuoteChar}; /// line c /// """ /// ``` -pub(super) fn format(normalized: &NormalizedString, f: &mut PyFormatter) -> FormatResult<()> { +pub(crate) fn format(normalized: &NormalizedString, f: &mut PyFormatter) -> FormatResult<()> { let docstring = &normalized.text; // Black doesn't change the indentation of docstrings that contain an escaped newline diff --git a/crates/ruff_python_formatter/src/expression/string/mod.rs b/crates/ruff_python_formatter/src/string/mod.rs similarity index 79% rename from crates/ruff_python_formatter/src/expression/string/mod.rs rename to crates/ruff_python_formatter/src/string/mod.rs index 135594be3a044..57c11cd622900 100644 --- a/crates/ruff_python_formatter/src/expression/string/mod.rs +++ b/crates/ruff_python_formatter/src/string/mod.rs @@ -5,35 +5,41 @@ use bitflags::bitflags; use ruff_formatter::{format_args, write}; use ruff_python_ast::AnyNodeRef; use ruff_python_ast::{ - self as ast, ExprBytesLiteral, ExprFString, ExprStringLiteral, ExpressionRef, + self as ast, Expr, ExprBytesLiteral, ExprFString, ExprStringLiteral, ExpressionRef, }; use ruff_source_file::Locator; use ruff_text_size::{Ranged, TextLen, TextRange, TextSize}; use crate::comments::{leading_comments, trailing_comments}; -use crate::expression::parentheses::{ - in_parentheses_only_group, in_parentheses_only_soft_line_break_or_space, -}; -use crate::expression::Expr; +use crate::expression::expr_f_string::f_string_quoting; +use crate::expression::parentheses::in_parentheses_only_soft_line_break_or_space; +use crate::other::f_string::FormatFString; +use crate::other::string_literal::{FormatStringLiteral, StringLiteralKind}; use crate::prelude::*; use crate::QuoteStyle; -mod docstring; +pub(crate) mod docstring; -#[derive(Copy, Clone, Debug)] -enum Quoting { +#[derive(Copy, Clone, Debug, Default)] +pub(crate) enum Quoting { + #[default] CanChange, Preserve, } +/// Represents any kind of string expression. This could be either a string, +/// bytes or f-string. #[derive(Clone, Debug)] -pub(super) enum AnyString<'a> { +pub(crate) enum AnyString<'a> { String(&'a ExprStringLiteral), Bytes(&'a ExprBytesLiteral), FString(&'a ExprFString), } impl<'a> AnyString<'a> { + /// Creates a new [`AnyString`] from the given [`Expr`]. + /// + /// Returns `None` if the expression is not either a string, bytes or f-string. pub(crate) fn from_expression(expression: &'a Expr) -> Option> { match expression { Expr::StringLiteral(string) => Some(AnyString::String(string)), @@ -43,39 +49,8 @@ impl<'a> AnyString<'a> { } } - fn quoting(&self, locator: &Locator) -> Quoting { - match self { - Self::String(_) | Self::Bytes(_) => Quoting::CanChange, - Self::FString(f_string) => { - let unprefixed = locator - .slice(f_string.range) - .trim_start_matches(|c| c != '"' && c != '\''); - let triple_quoted = - unprefixed.starts_with(r#"""""#) || unprefixed.starts_with(r"'''"); - if f_string.value.elements().any(|element| match element { - ast::FStringElement::Expression(ast::FStringExpressionElement { - range, - .. - }) => { - let string_content = locator.slice(*range); - if triple_quoted { - string_content.contains(r#"""""#) || string_content.contains("'''") - } else { - string_content.contains(['"', '\'']) - } - } - ast::FStringElement::Literal(_) => false, - }) { - Quoting::Preserve - } else { - Quoting::CanChange - } - } - } - } - /// Returns `true` if the string is implicitly concatenated. - pub(super) fn is_implicit_concatenated(&self) -> bool { + pub(crate) fn is_implicit_concatenated(&self) -> bool { match self { Self::String(ExprStringLiteral { value, .. }) => value.is_implicit_concatenated(), Self::Bytes(ExprBytesLiteral { value, .. }) => value.is_implicit_concatenated(), @@ -83,21 +58,38 @@ impl<'a> AnyString<'a> { } } - fn parts(&self) -> Vec> { + /// Returns the quoting to be used for this string. + fn quoting(&self, locator: &Locator<'_>) -> Quoting { match self { - Self::String(ExprStringLiteral { value, .. }) => { - value.iter().map(AnyStringPart::String).collect() - } + Self::String(_) | Self::Bytes(_) => Quoting::CanChange, + Self::FString(f_string) => f_string_quoting(f_string, locator), + } + } + + /// Returns a vector of all the [`AnyStringPart`] of this string. + fn parts(&self, quoting: Quoting) -> Vec> { + match self { + Self::String(ExprStringLiteral { value, .. }) => value + .iter() + .map(|part| AnyStringPart::String { + part, + layout: StringLiteralKind::String, + }) + .collect(), Self::Bytes(ExprBytesLiteral { value, .. }) => { value.iter().map(AnyStringPart::Bytes).collect() } Self::FString(ExprFString { value, .. }) => value .iter() .map(|f_string_part| match f_string_part { - ast::FStringPart::Literal(string_literal) => { - AnyStringPart::String(string_literal) - } - ast::FStringPart::FString(f_string) => AnyStringPart::FString(f_string), + ast::FStringPart::Literal(string_literal) => AnyStringPart::String { + part: string_literal, + layout: StringLiteralKind::InImplicitlyConcatenatedFString(quoting), + }, + ast::FStringPart::FString(f_string) => AnyStringPart::FString { + part: f_string, + quoting, + }, }) .collect(), } @@ -134,19 +126,29 @@ impl<'a> From<&AnyString<'a>> for ExpressionRef<'a> { } } +/// Represents any kind of string which is part of an implicitly concatenated +/// string. This could be either a string, bytes or f-string. +/// +/// This is constructed from the [`AnyString::parts`] method on [`AnyString`]. #[derive(Clone, Debug)] enum AnyStringPart<'a> { - String(&'a ast::StringLiteral), + String { + part: &'a ast::StringLiteral, + layout: StringLiteralKind, + }, Bytes(&'a ast::BytesLiteral), - FString(&'a ast::FString), + FString { + part: &'a ast::FString, + quoting: Quoting, + }, } impl<'a> From<&AnyStringPart<'a>> for AnyNodeRef<'a> { fn from(value: &AnyStringPart<'a>) -> Self { match value { - AnyStringPart::String(part) => AnyNodeRef::StringLiteral(part), + AnyStringPart::String { part, .. } => AnyNodeRef::StringLiteral(part), AnyStringPart::Bytes(part) => AnyNodeRef::BytesLiteral(part), - AnyStringPart::FString(part) => AnyNodeRef::FString(part), + AnyStringPart::FString { part, .. } => AnyNodeRef::FString(part), } } } @@ -154,99 +156,33 @@ impl<'a> From<&AnyStringPart<'a>> for AnyNodeRef<'a> { impl Ranged for AnyStringPart<'_> { fn range(&self) -> TextRange { match self { - Self::String(part) => part.range(), + Self::String { part, .. } => part.range(), Self::Bytes(part) => part.range(), - Self::FString(part) => part.range(), + Self::FString { part, .. } => part.range(), } } } -pub(super) struct FormatString<'a> { - string: &'a AnyString<'a>, - layout: StringLayout, -} - -#[derive(Default, Copy, Clone, Debug)] -pub enum StringLayout { - #[default] - Default, - DocString, - /// An implicit concatenated string in a binary like (e.g. `a + b` or `a < b`) expression. - /// - /// Formats the implicit concatenated string parts without the enclosing group because the group - /// is added by the binary like formatting. - ImplicitConcatenatedStringInBinaryLike, -} - -impl<'a> FormatString<'a> { - pub(super) fn new(string: &'a AnyString<'a>) -> Self { - Self { - string, - layout: StringLayout::Default, - } - } - - pub(super) fn with_layout(mut self, layout: StringLayout) -> Self { - self.layout = layout; - self - } -} - -impl<'a> Format> for FormatString<'a> { +impl Format> for AnyStringPart<'_> { fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { - let parent_docstring_quote_style = f.context().docstring(); - let locator = f.context().locator(); - let result = match self.layout { - StringLayout::Default => { - if self.string.is_implicit_concatenated() { - in_parentheses_only_group(&FormatStringContinuation::new(self.string)).fmt(f) - } else { - StringPart::from_source(self.string.range(), &locator) - .normalize( - self.string.quoting(&locator), - &locator, - f.options().quote_style(), - parent_docstring_quote_style, - ) - .fmt(f) - } - } - StringLayout::DocString => { - let string_part = StringPart::from_source(self.string.range(), &locator); - let normalized = string_part.normalize( - Quoting::CanChange, - &locator, - // Per PEP 8 and PEP 257, always prefer double quotes for docstrings - QuoteStyle::Double, - parent_docstring_quote_style, - ); - docstring::format(&normalized, f) - } - StringLayout::ImplicitConcatenatedStringInBinaryLike => { - FormatStringContinuation::new(self.string).fmt(f) + match self { + AnyStringPart::String { part, layout } => { + FormatStringLiteral::new(part, *layout).fmt(f) } - }; - // TODO(dhruvmanila): With PEP 701, comments can be inside f-strings. - // This is to mark all of those comments as formatted but we need to - // figure out how to handle them. Note that this needs to be done only - // after the f-string is formatted, so only for all the non-formatted - // comments. - if let AnyString::FString(fstring) = self.string { - let comments = f.context().comments(); - fstring.value.elements().for_each(|value| { - comments.mark_verbatim_node_comments_formatted(value.into()); - }); + AnyStringPart::Bytes(bytes_literal) => bytes_literal.format().fmt(f), + AnyStringPart::FString { part, quoting } => FormatFString::new(part, *quoting).fmt(f), } - result } } -struct FormatStringContinuation<'a> { +/// Formats any implicitly concatenated string. This could be any valid combination +/// of string, bytes or f-string literals. +pub(crate) struct FormatStringContinuation<'a> { string: &'a AnyString<'a>, } impl<'a> FormatStringContinuation<'a> { - fn new(string: &'a AnyString<'a>) -> Self { + pub(crate) fn new(string: &'a AnyString<'a>) -> Self { Self { string } } } @@ -254,24 +190,15 @@ impl<'a> FormatStringContinuation<'a> { impl Format> for FormatStringContinuation<'_> { fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { let comments = f.context().comments().clone(); - let locator = f.context().locator(); - let in_docstring = f.context().docstring(); - let quote_style = f.options().quote_style(); + let quoting = self.string.quoting(&f.context().locator()); let mut joiner = f.join_with(in_parentheses_only_soft_line_break_or_space()); - for part in self.string.parts() { - let normalized = StringPart::from_source(part.range(), &locator).normalize( - self.string.quoting(&locator), - &locator, - quote_style, - in_docstring, - ); - + for part in self.string.parts(quoting) { joiner.entry(&format_args![ line_suffix_boundary(), leading_comments(comments.leading(&part)), - normalized, + part, trailing_comments(comments.trailing(&part)) ]); } @@ -281,7 +208,7 @@ impl Format> for FormatStringContinuation<'_> { } #[derive(Debug)] -struct StringPart { +pub(crate) struct StringPart { /// The prefix. prefix: StringPrefix, @@ -293,7 +220,7 @@ struct StringPart { } impl StringPart { - fn from_source(range: TextRange, locator: &Locator) -> Self { + pub(crate) fn from_source(range: TextRange, locator: &Locator) -> Self { let string_content = locator.slice(range); let prefix = StringPrefix::parse(string_content); @@ -320,7 +247,7 @@ impl StringPart { /// snippet within the docstring. The quote style should correspond to the /// style of quotes used by said docstring. Normalization will ensure the /// quoting styles don't conflict. - fn normalize<'a>( + pub(crate) fn normalize<'a>( self, quoting: Quoting, locator: &'a Locator, @@ -412,7 +339,7 @@ impl StringPart { } #[derive(Debug)] -struct NormalizedString<'a> { +pub(crate) struct NormalizedString<'a> { prefix: StringPrefix, /// The quotes of the normalized string (preferred quotes) @@ -448,7 +375,7 @@ impl Format> for NormalizedString<'_> { bitflags! { #[derive(Copy, Clone, Debug, PartialEq, Eq)] - pub(super) struct StringPrefix: u8 { + pub(crate) struct StringPrefix: u8 { const UNICODE = 0b0000_0001; /// `r"test"` const RAW = 0b0000_0010; @@ -460,7 +387,7 @@ bitflags! { } impl StringPrefix { - pub(super) fn parse(input: &str) -> StringPrefix { + pub(crate) fn parse(input: &str) -> StringPrefix { let chars = input.chars(); let mut prefix = StringPrefix::empty(); @@ -485,7 +412,7 @@ impl StringPrefix { prefix } - pub(super) const fn text_len(self) -> TextSize { + pub(crate) const fn text_len(self) -> TextSize { TextSize::new(self.bits().count_ones()) } @@ -688,13 +615,13 @@ fn choose_quotes(input: &str, quotes: StringQuotes, preferred_quote: QuoteChar) } #[derive(Copy, Clone, Debug)] -pub(super) struct StringQuotes { +pub(crate) struct StringQuotes { triple: bool, quote_char: QuoteChar, } impl StringQuotes { - pub(super) fn parse(input: &str) -> Option { + pub(crate) fn parse(input: &str) -> Option { let mut chars = input.chars(); let quote_char = chars.next()?; @@ -708,7 +635,7 @@ impl StringQuotes { }) } - pub(super) const fn is_triple(self) -> bool { + pub(crate) const fn is_triple(self) -> bool { self.triple } From 6c224cec5202e1259340ef3af19c0fea62c6226e Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 14 Dec 2023 14:46:35 -0500 Subject: [PATCH 187/197] Deduplicate edits when quoting annotations (#9140) If you have multiple sub-expressions that need to be quoted, we'll generate the same edit twice. Closes https://github.com/astral-sh/ruff/issues/9135. --- .../fixtures/flake8_type_checking/quote.py | 7 +++ .../runtime_import_in_type_checking_block.rs | 17 +++--- .../rules/typing_only_runtime_import.rs | 3 +- ...mport-in-type-checking-block_quote.py.snap | 2 + ...ping-only-third-party-import_quote.py.snap | 56 +++++++++++++++++++ 5 files changed, 75 insertions(+), 10 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/quote.py b/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/quote.py index 67332e3010f24..c7540c3ecce1d 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/quote.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/quote.py @@ -65,3 +65,10 @@ def f(): def func(value: DataFrame): ... + + +def f(): + from pandas import DataFrame, Series + + def baz() -> DataFrame | Series: + ... diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs b/crates/ruff_linter/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs index 5eee0365e12fa..377b4ca7effa2 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; use anyhow::Result; +use itertools::Itertools; use rustc_hash::FxHashMap; use ruff_diagnostics::{Diagnostic, Fix, FixAvailability, Violation}; @@ -262,7 +263,7 @@ pub(crate) fn runtime_import_in_type_checking_block( /// Generate a [`Fix`] to quote runtime usages for imports in a type-checking block. fn quote_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) -> Result { - let mut quote_reference_edits = imports + let quote_reference_edits = imports .iter() .flat_map(|ImportBinding { binding, .. }| { binding.references.iter().filter_map(|reference_id| { @@ -280,14 +281,12 @@ fn quote_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) }) }) .collect::>>()?; - let quote_reference_edit = quote_reference_edits - .pop() - .expect("Expected at least one reference"); - Ok( - Fix::unsafe_edits(quote_reference_edit, quote_reference_edits).isolate(Checker::isolation( - checker.semantic().parent_statement_id(node_id), - )), - ) + + let mut rest = quote_reference_edits.into_iter().dedup(); + let head = rest.next().expect("Expected at least one reference"); + Ok(Fix::unsafe_edits(head, rest).isolate(Checker::isolation( + checker.semantic().parent_statement_id(node_id), + ))) } /// Generate a [`Fix`] to remove runtime imports from a type-checking block. diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs b/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs index cb3adaed08368..e868418fec4ec 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; use anyhow::Result; +use itertools::Itertools; use rustc_hash::FxHashMap; use ruff_diagnostics::{Diagnostic, DiagnosticKind, Fix, FixAvailability, Violation}; @@ -506,7 +507,7 @@ fn fix_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) -> add_import_edit .into_edits() .into_iter() - .chain(quote_reference_edits), + .chain(quote_reference_edits.into_iter().dedup()), ) .isolate(Checker::isolation( checker.semantic().parent_statement_id(node_id), diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_runtime-import-in-type-checking-block_quote.py.snap b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_runtime-import-in-type-checking-block_quote.py.snap index 0baeba9f62ec1..ae71c56c8195a 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_runtime-import-in-type-checking-block_quote.py.snap +++ b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_runtime-import-in-type-checking-block_quote.py.snap @@ -18,5 +18,7 @@ quote.py:64:28: TCH004 [*] Quote references to `pandas.DataFrame`. Import is in 66 |- def func(value: DataFrame): 66 |+ def func(value: "DataFrame"): 67 67 | ... +68 68 | +69 69 | diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_typing-only-third-party-import_quote.py.snap b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_typing-only-third-party-import_quote.py.snap index 9c43070c0f5b8..eb208bedce285 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_typing-only-third-party-import_quote.py.snap +++ b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_typing-only-third-party-import_quote.py.snap @@ -196,4 +196,60 @@ quote.py:54:24: TCH002 Move third-party import `pandas.DataFrame` into a type-ch | = help: Move into type-checking block +quote.py:71:24: TCH002 [*] Move third-party import `pandas.DataFrame` into a type-checking block + | +70 | def f(): +71 | from pandas import DataFrame, Series + | ^^^^^^^^^ TCH002 +72 | +73 | def baz() -> DataFrame | Series: + | + = help: Move into type-checking block + +ℹ Unsafe fix + 1 |+from typing import TYPE_CHECKING + 2 |+ + 3 |+if TYPE_CHECKING: + 4 |+ from pandas import DataFrame, Series +1 5 | def f(): +2 6 | from pandas import DataFrame +3 7 | +-------------------------------------------------------------------------------- +68 72 | +69 73 | +70 74 | def f(): +71 |- from pandas import DataFrame, Series +72 75 | +73 |- def baz() -> DataFrame | Series: + 76 |+ def baz() -> "DataFrame | Series": +74 77 | ... + +quote.py:71:35: TCH002 [*] Move third-party import `pandas.Series` into a type-checking block + | +70 | def f(): +71 | from pandas import DataFrame, Series + | ^^^^^^ TCH002 +72 | +73 | def baz() -> DataFrame | Series: + | + = help: Move into type-checking block + +ℹ Unsafe fix + 1 |+from typing import TYPE_CHECKING + 2 |+ + 3 |+if TYPE_CHECKING: + 4 |+ from pandas import DataFrame, Series +1 5 | def f(): +2 6 | from pandas import DataFrame +3 7 | +-------------------------------------------------------------------------------- +68 72 | +69 73 | +70 74 | def f(): +71 |- from pandas import DataFrame, Series +72 75 | +73 |- def baz() -> DataFrame | Series: + 76 |+ def baz() -> "DataFrame | Series": +74 77 | ... + From d1a7bc38ff41151db1143dec0c36a9fc0a909c3a Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 14 Dec 2023 20:03:09 -0500 Subject: [PATCH 188/197] Enable annotation quoting for multi-line expressions (#9142) Given: ```python x: DataFrame[ int ] = 1 ``` We currently wrap the annotation in single quotes, which leads to a syntax error: ```python x: "DataFrame[ int ]" = 1 ``` There are a few options for what to suggest for users here... Use triple quotes: ```python x: """DataFrame[ int ]""" = 1 ``` Or, use an implicit string concatenation (which may require parentheses): ```python x: ("DataFrame[" "int" "]") = 1 ``` The solution I settled on here is to use the `Generator`, which effectively means we write it out on a single line, like: ```python x: "DataFrame[int]" = 1 ``` It's kind of the "least opinionated" solution, but it does mean we'll expand to a very long line in some cases. Closes https://github.com/astral-sh/ruff/issues/9136. --- crates/ruff_diagnostics/src/edit.rs | 2 +- .../fixtures/flake8_type_checking/quote.py | 15 ++++ .../src/rules/flake8_type_checking/helpers.rs | 26 ++++--- .../runtime_import_in_type_checking_block.rs | 3 +- .../rules/typing_only_runtime_import.rs | 3 +- ...ping-only-third-party-import_quote.py.snap | 78 +++++++++++++++++++ 6 files changed, 113 insertions(+), 14 deletions(-) diff --git a/crates/ruff_diagnostics/src/edit.rs b/crates/ruff_diagnostics/src/edit.rs index 8c05474d21d39..5bd4e629b4c95 100644 --- a/crates/ruff_diagnostics/src/edit.rs +++ b/crates/ruff_diagnostics/src/edit.rs @@ -7,7 +7,7 @@ use ruff_text_size::{Ranged, TextRange, TextSize}; /// A text edit to be applied to a source file. Inserts, deletes, or replaces /// content at a given location. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Edit { /// The start location of the edit. diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/quote.py b/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/quote.py index c7540c3ecce1d..de3d609d07444 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/quote.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/quote.py @@ -72,3 +72,18 @@ def f(): def baz() -> DataFrame | Series: ... + + +def f(): + from pandas import DataFrame, Series + + def baz() -> ( + DataFrame | + Series + ): + ... + + class C: + x: DataFrame[ + int + ] = 1 diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs b/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs index 1fc4ade6fda9a..2eaab9dd27788 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs @@ -5,7 +5,7 @@ use ruff_diagnostics::Edit; use ruff_python_ast::call_path::from_qualified_name; use ruff_python_ast::helpers::{map_callable, map_subscript}; use ruff_python_ast::{self as ast, Expr}; -use ruff_python_codegen::Stylist; +use ruff_python_codegen::{Generator, Stylist}; use ruff_python_semantic::{ Binding, BindingId, BindingKind, NodeId, ResolvedReference, SemanticModel, }; @@ -215,6 +215,7 @@ pub(crate) fn quote_annotation( semantic: &SemanticModel, locator: &Locator, stylist: &Stylist, + generator: Generator, ) -> Result { let expr = semantic.expression(node_id).expect("Expression not found"); if let Some(parent_id) = semantic.parent_expression_id(node_id) { @@ -224,7 +225,7 @@ pub(crate) fn quote_annotation( // If we're quoting the value of a subscript, we need to quote the entire // expression. For example, when quoting `DataFrame` in `DataFrame[int]`, we // should generate `"DataFrame[int]"`. - return quote_annotation(parent_id, semantic, locator, stylist); + return quote_annotation(parent_id, semantic, locator, stylist, generator); } } Some(Expr::Attribute(parent)) => { @@ -232,7 +233,7 @@ pub(crate) fn quote_annotation( // If we're quoting the value of an attribute, we need to quote the entire // expression. For example, when quoting `DataFrame` in `pd.DataFrame`, we // should generate `"pd.DataFrame"`. - return quote_annotation(parent_id, semantic, locator, stylist); + return quote_annotation(parent_id, semantic, locator, stylist, generator); } } Some(Expr::Call(parent)) => { @@ -240,7 +241,7 @@ pub(crate) fn quote_annotation( // If we're quoting the function of a call, we need to quote the entire // expression. For example, when quoting `DataFrame` in `DataFrame()`, we // should generate `"DataFrame()"`. - return quote_annotation(parent_id, semantic, locator, stylist); + return quote_annotation(parent_id, semantic, locator, stylist, generator); } } Some(Expr::BinOp(parent)) => { @@ -248,27 +249,30 @@ pub(crate) fn quote_annotation( // If we're quoting the left or right side of a binary operation, we need to // quote the entire expression. For example, when quoting `DataFrame` in // `DataFrame | Series`, we should generate `"DataFrame | Series"`. - return quote_annotation(parent_id, semantic, locator, stylist); + return quote_annotation(parent_id, semantic, locator, stylist, generator); } } _ => {} } } - let annotation = locator.slice(expr); - // If the annotation already contains a quote, avoid attempting to re-quote it. For example: // ```python // from typing import Literal // // Set[Literal["Foo"]] // ``` - if annotation.contains('\'') || annotation.contains('"') { + let text = locator.slice(expr); + if text.contains('\'') || text.contains('"') { return Err(anyhow::anyhow!("Annotation already contains a quote")); } - // If we're quoting a name, we need to quote the entire expression. + // Quote the entire expression. let quote = stylist.quote(); - let annotation = format!("{quote}{annotation}{quote}"); - Ok(Edit::range_replacement(annotation, expr.range())) + let annotation = generator.expr(expr); + + Ok(Edit::range_replacement( + format!("{quote}{annotation}{quote}"), + expr.range(), + )) } diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs b/crates/ruff_linter/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs index 377b4ca7effa2..7f43ebbfd548d 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/rules/runtime_import_in_type_checking_block.rs @@ -274,6 +274,7 @@ fn quote_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) checker.semantic(), checker.locator(), checker.stylist(), + checker.generator(), )) } else { None @@ -282,7 +283,7 @@ fn quote_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) }) .collect::>>()?; - let mut rest = quote_reference_edits.into_iter().dedup(); + let mut rest = quote_reference_edits.into_iter().unique(); let head = rest.next().expect("Expected at least one reference"); Ok(Fix::unsafe_edits(head, rest).isolate(Checker::isolation( checker.semantic().parent_statement_id(node_id), diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs b/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs index e868418fec4ec..2ad9753362d11 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs @@ -494,6 +494,7 @@ fn fix_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) -> checker.semantic(), checker.locator(), checker.stylist(), + checker.generator(), )) } else { None @@ -507,7 +508,7 @@ fn fix_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) -> add_import_edit .into_edits() .into_iter() - .chain(quote_reference_edits.into_iter().dedup()), + .chain(quote_reference_edits.into_iter().unique()), ) .isolate(Checker::isolation( checker.semantic().parent_statement_id(node_id), diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_typing-only-third-party-import_quote.py.snap b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_typing-only-third-party-import_quote.py.snap index eb208bedce285..3a4417a661d87 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_typing-only-third-party-import_quote.py.snap +++ b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__quote_typing-only-third-party-import_quote.py.snap @@ -223,6 +223,8 @@ quote.py:71:24: TCH002 [*] Move third-party import `pandas.DataFrame` into a typ 73 |- def baz() -> DataFrame | Series: 76 |+ def baz() -> "DataFrame | Series": 74 77 | ... +75 78 | +76 79 | quote.py:71:35: TCH002 [*] Move third-party import `pandas.Series` into a type-checking block | @@ -251,5 +253,81 @@ quote.py:71:35: TCH002 [*] Move third-party import `pandas.Series` into a type-c 73 |- def baz() -> DataFrame | Series: 76 |+ def baz() -> "DataFrame | Series": 74 77 | ... +75 78 | +76 79 | + +quote.py:78:24: TCH002 [*] Move third-party import `pandas.DataFrame` into a type-checking block + | +77 | def f(): +78 | from pandas import DataFrame, Series + | ^^^^^^^^^ TCH002 +79 | +80 | def baz() -> ( + | + = help: Move into type-checking block + +ℹ Unsafe fix + 1 |+from typing import TYPE_CHECKING + 2 |+ + 3 |+if TYPE_CHECKING: + 4 |+ from pandas import DataFrame, Series +1 5 | def f(): +2 6 | from pandas import DataFrame +3 7 | +-------------------------------------------------------------------------------- +75 79 | +76 80 | +77 81 | def f(): +78 |- from pandas import DataFrame, Series +79 82 | +80 83 | def baz() -> ( +81 |- DataFrame | +82 |- Series + 84 |+ "DataFrame | Series" +83 85 | ): +84 86 | ... +85 87 | +86 88 | class C: +87 |- x: DataFrame[ +88 |- int +89 |- ] = 1 + 89 |+ x: "DataFrame[int]" = 1 + +quote.py:78:35: TCH002 [*] Move third-party import `pandas.Series` into a type-checking block + | +77 | def f(): +78 | from pandas import DataFrame, Series + | ^^^^^^ TCH002 +79 | +80 | def baz() -> ( + | + = help: Move into type-checking block + +ℹ Unsafe fix + 1 |+from typing import TYPE_CHECKING + 2 |+ + 3 |+if TYPE_CHECKING: + 4 |+ from pandas import DataFrame, Series +1 5 | def f(): +2 6 | from pandas import DataFrame +3 7 | +-------------------------------------------------------------------------------- +75 79 | +76 80 | +77 81 | def f(): +78 |- from pandas import DataFrame, Series +79 82 | +80 83 | def baz() -> ( +81 |- DataFrame | +82 |- Series + 84 |+ "DataFrame | Series" +83 85 | ): +84 86 | ... +85 87 | +86 88 | class C: +87 |- x: DataFrame[ +88 |- int +89 |- ] = 1 + 89 |+ x: "DataFrame[int]" = 1 From 25b23614114954f7353978ca3749d369f9a1b864 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Fri, 15 Dec 2023 11:18:40 +0900 Subject: [PATCH 189/197] Extend `can_omit_optional_parentheses` documentation (#9127) ## Summary Add some more documentation to `can_omit_optional_parentheses` because it is realy hard to understand. Restrict the `Attribute` and `None` `OperatorPrecedence` branches to ensure they only get applyied to the intended nodes. ## Test Plan Ecosystem check reports no differences. The compatibility index remains unchanged. --- .../src/expression/mod.rs | 50 +++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index 335941316cfde..7d858694c0436 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -528,6 +528,7 @@ impl<'ast> IntoFormat> for Expr { /// * The expression contains at least one parenthesized sub expression (optimization to avoid unnecessary work) /// /// This mimics Black's [`_maybe_split_omitting_optional_parens`](https://github.com/psf/black/blob/d1248ca9beaf0ba526d265f4108836d89cf551b7/src/black/linegen.py#L746-L820) +#[allow(clippy::if_same_then_else)] fn can_omit_optional_parentheses(expr: &Expr, context: &PyFormatContext) -> bool { let mut visitor = CanOmitOptionalParenthesesVisitor::new(context); visitor.visit_subexpression(expr); @@ -535,11 +536,54 @@ fn can_omit_optional_parentheses(expr: &Expr, context: &PyFormatContext) -> bool if !visitor.any_parenthesized_expressions { // Only use the more complex IR when there is any expression that we can possibly split by false - } else if visitor.max_precedence == OperatorPrecedence::None { - true } else if visitor.max_precedence_count > 1 { false - } else if visitor.max_precedence == OperatorPrecedence::Attribute { + } else if visitor.max_precedence == OperatorPrecedence::None && expr.is_lambda_expr() { + // Micha: This seems to exclusively apply for lambda expressions where the body ends in a subscript. + // Subscripts are excluded by default because breaking them looks odd, but it seems to be fine for lambda expression. + // + // ```python + // mapper = lambda x: dict_with_default[ + // np.nan if isinstance(x, float) and np.isnan(x) else x + // ] + // ``` + // + // to prevent that it gets formatted as: + // + // ```python + // mapper = ( + // lambda x: dict_with_default[ + // np.nan if isinstance(x, float) and np.isnan(x) else x + // ] + // ) + // ``` + // I think we should remove this check in the future and instead parenthesize the body of the lambda expression: + // + // ```python + // mapper = lambda x: ( + // dict_with_default[ + // np.nan if isinstance(x, float) and np.isnan(x) else x + // ] + // ) + // ``` + true + } else if visitor.max_precedence == OperatorPrecedence::Attribute + && (expr.is_lambda_expr() || expr.is_named_expr_expr()) + { + // A single method call inside a named expression (`:=`) or as the body of a lambda function: + // ```python + // kwargs["open_with"] = lambda path, _: fsspec.open( + // path, "wb", **(storage_options or {}) + // ).open() + // + // if ret := subprocess.run( + // ["git", "rev-parse", "--short", "HEAD"], + // cwd=package_dir, + // capture_output=True, + // encoding="ascii", + // errors="surrogateescape", + // ).stdout: + // ``` true } else { fn is_parenthesized(expr: &Expr, context: &PyFormatContext) -> bool { From c8d6958d15fb15e9ce7817cf2cb7e91666f59904 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Fri, 15 Dec 2023 11:45:13 +0900 Subject: [PATCH 190/197] Add new `with` and `match` sequence test cases (#9128) ## Summary Add new test cases for `with_item` and `match` sequence that demonstrate how long headers break. Removes one use of `optional_parentheses` in a position where it is know that the parentheses always need to be added. ## Test Plan cargo test --- .../resources/test/fixtures/ruff/statement/match.py | 5 +++++ .../resources/test/fixtures/ruff/statement/with.py | 4 ++++ .../ruff_python_formatter/src/statement/stmt_with.rs | 8 +++----- .../tests/snapshots/format@statement__match.py.snap | 12 ++++++++++++ .../tests/snapshots/format@statement__with.py.snap | 10 ++++++++++ 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/match.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/match.py index 3d9855a154738..f24f9416cc0ef 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/match.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/match.py @@ -578,3 +578,8 @@ def foo(): print("Buzz") case _: print(n) + +# Unparenthesized tuples +match x: + case Child(aaaaaaaaa, bbbbbbbbbbbbbbb, cccccc), Doc(aaaaa, bbbbbbbbbb, ddddddddddddd): + pass diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with.py index 4dc166009a363..b222747733fe9 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with.py @@ -303,3 +303,7 @@ if True: with anyio.CancelScope(shield=True) if get_running_loop() else contextlib.nullcontext(): pass + + +with Child(aaaaaaaaa, bbbbbbbbbbbbbbb, cccccc), Document(aaaaa, bbbbbbbbbb, ddddddddddddd): + pass diff --git a/crates/ruff_python_formatter/src/statement/stmt_with.rs b/crates/ruff_python_formatter/src/statement/stmt_with.rs index af2389279b559..06dc9a5f88f6b 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_with.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_with.rs @@ -6,9 +6,7 @@ use ruff_text_size::{Ranged, TextRange}; use crate::builders::parenthesize_if_expands; use crate::comments::SourceComment; -use crate::expression::parentheses::{ - in_parentheses_only_soft_line_break_or_space, optional_parentheses, parenthesized, -}; +use crate::expression::parentheses::parenthesized; use crate::other::commas; use crate::prelude::*; use crate::statement::clause::{clause_body, clause_header, ClauseHeader}; @@ -77,7 +75,7 @@ impl FormatNodeRule for FormatStmtWith { joiner.entry_with_line_separator( item, &item.format(), - in_parentheses_only_soft_line_break_or_space(), + soft_line_break_or_space(), ); } joiner.finish() @@ -87,7 +85,7 @@ impl FormatNodeRule for FormatStmtWith { // This is similar to `maybe_parenthesize_expression`, but we're not // dealing with an expression here, it's a `WithItem`. if comments.has_leading(item) || comments.has_trailing(item) { - optional_parentheses(&item.format()).fmt(f)?; + parenthesized("(", &item.format(), ")").fmt(f)?; } else { item.format().fmt(f)?; } diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__match.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__match.py.snap index 01e0715610701..dad7a3c526f8b 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__match.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__match.py.snap @@ -584,6 +584,11 @@ match n % 3, n % 5: print("Buzz") case _: print(n) + +# Unparenthesized tuples +match x: + case Child(aaaaaaaaa, bbbbbbbbbbbbbbb, cccccc), Doc(aaaaa, bbbbbbbbbb, ddddddddddddd): + pass ``` ## Output @@ -1210,6 +1215,13 @@ match n % 3, n % 5: print("Buzz") case _: print(n) + +# Unparenthesized tuples +match x: + case Child(aaaaaaaaa, bbbbbbbbbbbbbbb, cccccc), Doc( + aaaaa, bbbbbbbbbb, ddddddddddddd + ): + pass ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__with.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__with.py.snap index 7b2280c6caf31..62018dfe4e1d4 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__with.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__with.py.snap @@ -309,6 +309,10 @@ if True: if True: with anyio.CancelScope(shield=True) if get_running_loop() else contextlib.nullcontext(): pass + + +with Child(aaaaaaaaa, bbbbbbbbbbbbbbb, cccccc), Document(aaaaa, bbbbbbbbbb, ddddddddddddd): + pass ``` ## Output @@ -640,6 +644,12 @@ if True: shield=True ) if get_running_loop() else contextlib.nullcontext(): pass + + +with Child(aaaaaaaaa, bbbbbbbbbbbbbbb, cccccc), Document( + aaaaa, bbbbbbbbbb, ddddddddddddd +): + pass ``` From db38078ca3e724f3fa62cfd800ce4e73833ebe00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joffrey=20Bluth=C3=A9?= Date: Fri, 15 Dec 2023 11:47:19 +0100 Subject: [PATCH 191/197] Document link between import sorting and formatter (#9117) --- docs/formatter.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/formatter.md b/docs/formatter.md index 8c8537946862d..547f32eee25da 100644 --- a/docs/formatter.md +++ b/docs/formatter.md @@ -392,3 +392,15 @@ flag. Black promotes some of its preview styling to stable at the end of each year. Ruff will similarly implement formatting changes under the [`preview`](https://docs.astral.sh/ruff/settings/#preview) flag, promoting them to stable through minor releases, in accordance with our [versioning policy](https://github.com/astral-sh/ruff/discussions/6998#discussioncomment-7016766). + +## Sorting imports + +Currently, the Ruff formatter does not sort imports. In order to both sort imports and format, +call the Ruff linter and then the formatter: + +```shell +ruff check --select I --fix . +ruff format . +``` + +A unified command for both linting and formatting is [planned](https://github.com/astral-sh/ruff/issues/8232). From 3ce145c47669645c9031ec42ef9b339835e548c9 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Fri, 15 Dec 2023 08:19:35 -0500 Subject: [PATCH 192/197] release: switch to Cargo's default (#9031) This sets `lto = "thin"` instead of using "fat" LTO, and sets `codegen-units = 16`. These are the defaults for Cargo's `release` profile, and I think it may give us faster iteration times, especially when benchmarking. The point of this PR is to see what kind of impact this has on benchmarks. It is expected that benchmarks may regress to some extent. I did some quick ad hoc experiments to quantify this change in compile times. Namely, I ran: cargo build --profile release -p ruff_cli Then I ran touch crates/ruff_python_formatter/src/expression/string/docstring.rs (because that's where i've been working lately) and re-ran cargo build --profile release -p ruff_cli This last command is what I timed, since it reflects how much time one has to wait between making a change and getting a compiled artifact. Here are my results: * With status quo `release` profile, build takes 77s * with `release` but `lto = "thin"`, build takes 41s * with `release`, but `lto = false`, build takes 19s * with `release`, but `lto = false` **and** `codegen-units = 16`, build takes 7s * with `release`, but `lto = "thin"` **and** `codegen-units = 16`, build takes 16s (i believe this is the default `release` configuration) This PR represents the last option. It's not the fastest to compile, but it's nearly a whole minute faster! The idea is that with `codegen-units = 16`, we still make use of parallelism, but keep _some_ level of LTO on to try and re-gain what we lose by increasing the number of codegen units. --- CONTRIBUTING.md | 10 ++++----- Cargo.toml | 21 +++++++++++++++---- crates/ruff_python_parser/src/lexer/cursor.rs | 1 + 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2d4ecb9b449fb..d79da233ebbab 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -556,10 +556,10 @@ examples. #### Linux -Install `perf` and build `ruff_benchmark` with the `release-debug` profile and then run it with perf +Install `perf` and build `ruff_benchmark` with the `profiling` profile and then run it with perf ```shell -cargo bench -p ruff_benchmark --no-run --profile=release-debug && perf record --call-graph dwarf -F 9999 cargo bench -p ruff_benchmark --profile=release-debug -- --profile-time=1 +cargo bench -p ruff_benchmark --no-run --profile=profiling && perf record --call-graph dwarf -F 9999 cargo bench -p ruff_benchmark --profile=profiling -- --profile-time=1 ``` You can also use the `ruff_dev` launcher to run `ruff check` multiple times on a repository to @@ -567,8 +567,8 @@ gather enough samples for a good flamegraph (change the 999, the sample rate, an of checks, to your liking) ```shell -cargo build --bin ruff_dev --profile=release-debug -perf record -g -F 999 target/release-debug/ruff_dev repeat --repeat 30 --exit-zero --no-cache path/to/cpython > /dev/null +cargo build --bin ruff_dev --profile=profiling +perf record -g -F 999 target/profiling/ruff_dev repeat --repeat 30 --exit-zero --no-cache path/to/cpython > /dev/null ``` Then convert the recorded profile @@ -598,7 +598,7 @@ cargo install cargo-instruments Then run the profiler with ```shell -cargo instruments -t time --bench linter --profile release-debug -p ruff_benchmark -- --profile-time=1 +cargo instruments -t time --bench linter --profile profiling -p ruff_benchmark -- --profile-time=1 ``` - `-t`: Specifies what to profile. Useful options are `time` to profile the wall time and `alloc` diff --git a/Cargo.toml b/Cargo.toml index 304162dba62ac..aad3c664465ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,7 +88,20 @@ rc_mutex = "warn" rest_pat_in_fully_bound_structs = "warn" [profile.release] -lto = "fat" +# Note that we set these explicitly, and these values +# were chosen based on a trade-off between compile times +# and runtime performance[1]. +# +# [1]: https://github.com/astral-sh/ruff/pull/9031 +lto = "thin" +codegen-units = 16 + +# Some crates don't change as much but benefit more from +# more expensive optimization passes, so we selectively +# decrease codegen-units in some cases. +[profile.release.package.ruff_python_parser] +codegen-units = 1 +[profile.release.package.ruff_python_ast] codegen-units = 1 [profile.dev.package.insta] @@ -102,8 +115,8 @@ opt-level = 3 [profile.dev.package.ruff_python_parser] opt-level = 1 -# Use the `--profile release-debug` flag to show symbols in release mode. -# e.g. `cargo build --profile release-debug` -[profile.release-debug] +# Use the `--profile profiling` flag to show symbols in release mode. +# e.g. `cargo build --profile profiling` +[profile.profiling] inherits = "release" debug = 1 diff --git a/crates/ruff_python_parser/src/lexer/cursor.rs b/crates/ruff_python_parser/src/lexer/cursor.rs index 91c7d30c53b05..26f3bb8a5b402 100644 --- a/crates/ruff_python_parser/src/lexer/cursor.rs +++ b/crates/ruff_python_parser/src/lexer/cursor.rs @@ -120,6 +120,7 @@ impl<'a> Cursor<'a> { } /// Eats symbols while predicate returns true or until the end of file is reached. + #[inline] pub(super) fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) { // It was tried making optimized version of this for eg. line comments, but // LLVM can inline all of this and compile it down to fast iteration over bytes. From cd3c2f773ff4dac76b5447f0e1fd71f7134a96b0 Mon Sep 17 00:00:00 2001 From: konsti Date: Fri, 15 Dec 2023 15:15:46 +0100 Subject: [PATCH 193/197] Prevent invalid utf8 indexing in cell magic detection (#9146) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The example below used to panic because we tried to split at 2 bytes in the 4-bytes character `转`. ```python def sample_func(xx): """ 转置 (transpose) """ return xx.T ``` Fixes #9145 Fixes https://github.com/astral-sh/ruff-vscode/issues/362 The second commit is a small test refactoring. --- .../jupyter/cell/unicode_magic_gh9145.json | 19 +++++ crates/ruff_notebook/src/cell.rs | 79 +++++++++---------- crates/ruff_notebook/src/notebook.rs | 28 ++++--- 3 files changed, 72 insertions(+), 54 deletions(-) create mode 100644 crates/ruff_notebook/resources/test/fixtures/jupyter/cell/unicode_magic_gh9145.json diff --git a/crates/ruff_notebook/resources/test/fixtures/jupyter/cell/unicode_magic_gh9145.json b/crates/ruff_notebook/resources/test/fixtures/jupyter/cell/unicode_magic_gh9145.json new file mode 100644 index 0000000000000..38455b3c3df65 --- /dev/null +++ b/crates/ruff_notebook/resources/test/fixtures/jupyter/cell/unicode_magic_gh9145.json @@ -0,0 +1,19 @@ +{ + "execution_count": null, + "cell_type": "code", + "id": "1", + "metadata": {}, + "outputs": [], + "source": [ + "def sample_func(xx):\n", + " \"\"\"\n", + " 转置 (transpose)\n", + " \"\"\"\n", + " return xx.T", + "# https://github.com/astral-sh/ruff-vscode/issues/362", + "DEFAULT_SYSTEM_PROMPT = (", + " \"Ты — Сайга, русскоязычный автоматический ассистент. \"", + " \"Ты разговариваешь с людьми и помогаешь им.\"", + ")" + ] +} diff --git a/crates/ruff_notebook/src/cell.rs b/crates/ruff_notebook/src/cell.rs index caa4cb3204a03..eefc18918b5cb 100644 --- a/crates/ruff_notebook/src/cell.rs +++ b/crates/ruff_notebook/src/cell.rs @@ -171,48 +171,43 @@ impl Cell { // Detect cell magics (which operate on multiple lines). lines.any(|line| { - line.split_whitespace().next().is_some_and(|first| { - if first.len() < 2 { - return false; - } - let (token, command) = first.split_at(2); - // These cell magics are special in that the lines following them are valid - // Python code and the variables defined in that scope are available to the - // rest of the notebook. - // - // For example: - // - // Cell 1: - // ```python - // x = 1 - // ``` - // - // Cell 2: - // ```python - // %%time - // y = x - // ``` - // - // Cell 3: - // ```python - // print(y) # Here, `y` is available. - // ``` - // - // This is to avoid false positives when these variables are referenced - // elsewhere in the notebook. - token == "%%" - && !matches!( - command, - "capture" - | "debug" - | "prun" - | "pypy" - | "python" - | "python3" - | "time" - | "timeit" - ) - }) + let Some(first) = line.split_whitespace().next() else { + return false; + }; + if first.len() < 2 { + return false; + } + let Some(command) = first.strip_prefix("%%") else { + return false; + }; + // These cell magics are special in that the lines following them are valid + // Python code and the variables defined in that scope are available to the + // rest of the notebook. + // + // For example: + // + // Cell 1: + // ```python + // x = 1 + // ``` + // + // Cell 2: + // ```python + // %%time + // y = x + // ``` + // + // Cell 3: + // ```python + // print(y) # Here, `y` is available. + // ``` + // + // This is to avoid false positives when these variables are referenced + // elsewhere in the notebook. + !matches!( + command, + "capture" | "debug" | "prun" | "pypy" | "python" | "python3" | "time" | "timeit" + ) }) } } diff --git a/crates/ruff_notebook/src/notebook.rs b/crates/ruff_notebook/src/notebook.rs index 7c9e8356b79d3..ddc558ba21b87 100644 --- a/crates/ruff_notebook/src/notebook.rs +++ b/crates/ruff_notebook/src/notebook.rs @@ -421,17 +421,18 @@ mod tests { )); } - #[test_case(Path::new("markdown.json"), false; "markdown")] - #[test_case(Path::new("only_magic.json"), true; "only_magic")] - #[test_case(Path::new("code_and_magic.json"), true; "code_and_magic")] - #[test_case(Path::new("only_code.json"), true; "only_code")] - #[test_case(Path::new("cell_magic.json"), false; "cell_magic")] - #[test_case(Path::new("valid_cell_magic.json"), true; "valid_cell_magic")] - #[test_case(Path::new("automagic.json"), false; "automagic")] - #[test_case(Path::new("automagics.json"), false; "automagics")] - #[test_case(Path::new("automagic_before_code.json"), false; "automagic_before_code")] - #[test_case(Path::new("automagic_after_code.json"), true; "automagic_after_code")] - fn test_is_valid_code_cell(path: &Path, expected: bool) -> Result<()> { + #[test_case("markdown", false)] + #[test_case("only_magic", true)] + #[test_case("code_and_magic", true)] + #[test_case("only_code", true)] + #[test_case("cell_magic", false)] + #[test_case("valid_cell_magic", true)] + #[test_case("automagic", false)] + #[test_case("automagics", false)] + #[test_case("automagic_before_code", false)] + #[test_case("automagic_after_code", true)] + #[test_case("unicode_magic_gh9145", true)] + fn test_is_valid_code_cell(cell: &str, expected: bool) -> Result<()> { /// Read a Jupyter cell from the `resources/test/fixtures/jupyter/cell` directory. fn read_jupyter_cell(path: impl AsRef) -> Result { let path = notebook_path("cell").join(path); @@ -439,7 +440,10 @@ mod tests { Ok(serde_json::from_str(&source_code)?) } - assert_eq!(read_jupyter_cell(path)?.is_valid_code_cell(), expected); + assert_eq!( + read_jupyter_cell(format!("{cell}.json"))?.is_valid_code_cell(), + expected + ); Ok(()) } From 82731b819410a8c172e752e9755c67ab3643b50b Mon Sep 17 00:00:00 2001 From: konsti Date: Fri, 15 Dec 2023 18:02:15 +0100 Subject: [PATCH 194/197] Fix panic in D208 with multibyte indent (#9147) Fix #9080 Example, where `[]` is a 2 byte non-breaking space: ``` def f(): """ Docstring header ^^^^ Real indentation is 4 chars docstring body, over-indented ^^^^^^ Over-indentation is 6 - 4 = 2 chars due to this line [] [] docstring body 2, further indented ^^^^^ We take these 4 chars/5 bytes to match the docstring ... ^^^ ... and these 2 chars/3 bytes to remove the `over_indented_size` ... ^^ ... but preserve this real indent ``` --- .../resources/test/fixtures/pydocstyle/D.py | 9 ++++++- .../src/rules/pydocstyle/rules/indent.rs | 18 ++++++++++--- ...__rules__pydocstyle__tests__D208_D.py.snap | 18 +++++++++++++ ...__rules__pydocstyle__tests__D213_D.py.snap | 25 ++++++++++++++++++- 4 files changed, 65 insertions(+), 5 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D.py b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D.py index 724490934ffaf..617231c5c81a9 100644 --- a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D.py +++ b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D.py @@ -713,5 +713,12 @@ def retain_extra_whitespace_not_overindented(): This is not overindented This is overindented, but since one line is not overindented this should not raise - And so is this, but it we should preserve the extra space on this line relative + And so is this, but it we should preserve the extra space on this line relative + """ + + +def inconsistent_indent_byte_size(): + """There's a non-breaking space (2-bytes) after 3 spaces (https://github.com/astral-sh/ruff/issues/9080). + +     Returns: """ diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs index 1c2ced8bd1b0d..c91565837f9ad 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs @@ -254,14 +254,26 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { Edit::range_deletion(TextRange::at(line.start(), line_indent.text_len())) } else { // Convert the character count to an offset within the source. + // Example, where `[]` is a 2 byte non-breaking space: + // ``` + // def f(): + // """ Docstring header + // ^^^^ Real indentation is 4 chars + // docstring body, over-indented + // ^^^^^^ Over-indentation is 6 - 4 = 2 chars due to this line + // [] [] docstring body 2, further indented + // ^^^^^ We take these 4 chars/5 bytes to match the docstring ... + // ^^^ ... and these 2 chars/3 bytes to remove the `over_indented_size` ... + // ^^ ... but preserve this real indent + // ``` let offset = checker .locator() - .after(line.start() + indent.text_len()) + .after(line.start()) .chars() - .take(over_indented_size) + .take(docstring.indentation.chars().count() + over_indented_size) .map(TextLen::text_len) .sum::(); - let range = TextRange::at(line.start(), indent.text_len() + offset); + let range = TextRange::at(line.start(), offset); Edit::range_replacement(indent, range) }; diagnostic.set_fix(Fix::safe_edit(edit)); diff --git a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D.py.snap b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D.py.snap index caa57c1faa72d..5048d030c7dcd 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D.py.snap +++ b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D.py.snap @@ -411,4 +411,22 @@ D.py:707:1: D208 [*] Docstring is over-indented 709 709 | 710 710 | +D.py:723:1: D208 [*] Docstring is over-indented + | +721 | """There's a non-breaking space (2-bytes) after 3 spaces (https://github.com/astral-sh/ruff/issues/9080). +722 | +723 |     Returns: + | D208 +724 | """ + | + = help: Remove over-indentation + +ℹ Safe fix +720 720 | def inconsistent_indent_byte_size(): +721 721 | """There's a non-breaking space (2-bytes) after 3 spaces (https://github.com/astral-sh/ruff/issues/9080). +722 722 | +723 |-     Returns: + 723 |+ Returns: +724 724 | """ + diff --git a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D213_D.py.snap b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D213_D.py.snap index e0f3516e76c32..0253bc44cd427 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D213_D.py.snap +++ b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D213_D.py.snap @@ -662,7 +662,7 @@ D.py:712:5: D213 [*] Multi-line docstring summary should start at the second lin 713 | | 714 | | This is not overindented 715 | | This is overindented, but since one line is not overindented this should not raise -716 | | And so is this, but it we should preserve the extra space on this line relative +716 | | And so is this, but it we should preserve the extra space on this line relative 717 | | """ | |_______^ D213 | @@ -679,4 +679,27 @@ D.py:712:5: D213 [*] Multi-line docstring summary should start at the second lin 714 715 | This is not overindented 715 716 | This is overindented, but since one line is not overindented this should not raise +D.py:721:5: D213 [*] Multi-line docstring summary should start at the second line + | +720 | def inconsistent_indent_byte_size(): +721 | """There's a non-breaking space (2-bytes) after 3 spaces (https://github.com/astral-sh/ruff/issues/9080). + | _____^ +722 | | +723 | |     Returns: +724 | | """ + | |_______^ D213 + | + = help: Insert line break and indentation after opening quotes + +ℹ Safe fix +718 718 | +719 719 | +720 720 | def inconsistent_indent_byte_size(): +721 |- """There's a non-breaking space (2-bytes) after 3 spaces (https://github.com/astral-sh/ruff/issues/9080). + 721 |+ """ + 722 |+ There's a non-breaking space (2-bytes) after 3 spaces (https://github.com/astral-sh/ruff/issues/9080). +722 723 | +723 724 |     Returns: +724 725 | """ + From 6ecf844214203694e8d08a0f05a14dca60c454a9 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 15 Dec 2023 13:01:32 -0500 Subject: [PATCH 195/197] Add base-class inheritance detection to flake8-django rules (#9151) ## Summary As elsewhere, this only applies to classes defined within the same file. Closes https://github.com/astral-sh/ruff/issues/9150. --- .../test/fixtures/flake8_django/DJ012.py | 18 ++++ .../src/checkers/ast/analyze/statement.rs | 20 +--- .../rules/all_with_model_form.rs | 31 +++--- .../rules/exclude_with_model_form.rs | 26 ++--- .../src/rules/flake8_django/rules/helpers.rs | 12 +-- .../rules/model_without_dunder_str.rs | 61 ++++-------- .../rules/unordered_body_content_in_model.rs | 97 +++++++++---------- ..._flake8_django__tests__DJ012_DJ012.py.snap | 8 ++ .../src/rules/flake8_type_checking/helpers.rs | 57 ++--------- .../ruff_python_semantic/src/analyze/class.rs | 57 +++++++++++ .../ruff_python_semantic/src/analyze/mod.rs | 1 + 11 files changed, 189 insertions(+), 199 deletions(-) create mode 100644 crates/ruff_python_semantic/src/analyze/class.rs diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_django/DJ012.py b/crates/ruff_linter/resources/test/fixtures/flake8_django/DJ012.py index a0f8d9da221a0..20d3e4078ba96 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_django/DJ012.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_django/DJ012.py @@ -127,3 +127,21 @@ def get_absolute_url(self): pass middle_name = models.CharField(max_length=32) + + +class BaseModel(models.Model): + pass + + +class StrBeforeFieldInheritedModel(BaseModel): + """Model with `__str__` before fields.""" + + class Meta: + verbose_name = "test" + verbose_name_plural = "tests" + + def __str__(self): + return "foobar" + + first_name = models.CharField(max_length=32) + diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 5fb77629a28c8..714ae3e4e3943 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -397,27 +397,13 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { flake8_django::rules::nullable_model_string_field(checker, body); } if checker.enabled(Rule::DjangoExcludeWithModelForm) { - if let Some(diagnostic) = flake8_django::rules::exclude_with_model_form( - checker, - arguments.as_deref(), - body, - ) { - checker.diagnostics.push(diagnostic); - } + flake8_django::rules::exclude_with_model_form(checker, class_def); } if checker.enabled(Rule::DjangoAllWithModelForm) { - if let Some(diagnostic) = - flake8_django::rules::all_with_model_form(checker, arguments.as_deref(), body) - { - checker.diagnostics.push(diagnostic); - } + flake8_django::rules::all_with_model_form(checker, class_def); } if checker.enabled(Rule::DjangoUnorderedBodyContentInModel) { - flake8_django::rules::unordered_body_content_in_model( - checker, - arguments.as_deref(), - body, - ); + flake8_django::rules::unordered_body_content_in_model(checker, class_def); } if !checker.source_type.is_stub() { if checker.enabled(Rule::DjangoModelWithoutDunderStr) { diff --git a/crates/ruff_linter/src/rules/flake8_django/rules/all_with_model_form.rs b/crates/ruff_linter/src/rules/flake8_django/rules/all_with_model_form.rs index 8e97c68c2ca0f..8083575e2a59c 100644 --- a/crates/ruff_linter/src/rules/flake8_django/rules/all_with_model_form.rs +++ b/crates/ruff_linter/src/rules/flake8_django/rules/all_with_model_form.rs @@ -1,7 +1,6 @@ -use ruff_python_ast::{self as ast, Arguments, Expr, Stmt}; - use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::{self as ast, Expr, Stmt}; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -48,21 +47,12 @@ impl Violation for DjangoAllWithModelForm { } /// DJ007 -pub(crate) fn all_with_model_form( - checker: &Checker, - arguments: Option<&Arguments>, - body: &[Stmt], -) -> Option { - if !arguments.is_some_and(|arguments| { - arguments - .args - .iter() - .any(|base| is_model_form(base, checker.semantic())) - }) { - return None; +pub(crate) fn all_with_model_form(checker: &mut Checker, class_def: &ast::StmtClassDef) { + if !is_model_form(class_def, checker.semantic()) { + return; } - for element in body { + for element in &class_def.body { let Stmt::ClassDef(ast::StmtClassDef { name, body, .. }) = element else { continue; }; @@ -83,12 +73,18 @@ pub(crate) fn all_with_model_form( match value.as_ref() { Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { if value == "__all__" { - return Some(Diagnostic::new(DjangoAllWithModelForm, element.range())); + checker + .diagnostics + .push(Diagnostic::new(DjangoAllWithModelForm, element.range())); + return; } } Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => { if value == "__all__".as_bytes() { - return Some(Diagnostic::new(DjangoAllWithModelForm, element.range())); + checker + .diagnostics + .push(Diagnostic::new(DjangoAllWithModelForm, element.range())); + return; } } _ => (), @@ -96,5 +92,4 @@ pub(crate) fn all_with_model_form( } } } - None } diff --git a/crates/ruff_linter/src/rules/flake8_django/rules/exclude_with_model_form.rs b/crates/ruff_linter/src/rules/flake8_django/rules/exclude_with_model_form.rs index 41661892bb9d6..d1211c566210a 100644 --- a/crates/ruff_linter/src/rules/flake8_django/rules/exclude_with_model_form.rs +++ b/crates/ruff_linter/src/rules/flake8_django/rules/exclude_with_model_form.rs @@ -1,7 +1,6 @@ -use ruff_python_ast::{self as ast, Arguments, Expr, Stmt}; - use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::{self as ast, Expr, Stmt}; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -46,21 +45,12 @@ impl Violation for DjangoExcludeWithModelForm { } /// DJ006 -pub(crate) fn exclude_with_model_form( - checker: &Checker, - arguments: Option<&Arguments>, - body: &[Stmt], -) -> Option { - if !arguments.is_some_and(|arguments| { - arguments - .args - .iter() - .any(|base| is_model_form(base, checker.semantic())) - }) { - return None; +pub(crate) fn exclude_with_model_form(checker: &mut Checker, class_def: &ast::StmtClassDef) { + if !is_model_form(class_def, checker.semantic()) { + return; } - for element in body { + for element in &class_def.body { let Stmt::ClassDef(ast::StmtClassDef { name, body, .. }) = element else { continue; }; @@ -76,10 +66,12 @@ pub(crate) fn exclude_with_model_form( continue; }; if id == "exclude" { - return Some(Diagnostic::new(DjangoExcludeWithModelForm, target.range())); + checker + .diagnostics + .push(Diagnostic::new(DjangoExcludeWithModelForm, target.range())); + return; } } } } - None } diff --git a/crates/ruff_linter/src/rules/flake8_django/rules/helpers.rs b/crates/ruff_linter/src/rules/flake8_django/rules/helpers.rs index c857bec150c11..0318de183970a 100644 --- a/crates/ruff_linter/src/rules/flake8_django/rules/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_django/rules/helpers.rs @@ -1,17 +1,17 @@ -use ruff_python_ast::Expr; +use ruff_python_ast::{self as ast, Expr}; -use ruff_python_semantic::SemanticModel; +use ruff_python_semantic::{analyze, SemanticModel}; /// Return `true` if a Python class appears to be a Django model, based on its base classes. -pub(super) fn is_model(base: &Expr, semantic: &SemanticModel) -> bool { - semantic.resolve_call_path(base).is_some_and(|call_path| { +pub(super) fn is_model(class_def: &ast::StmtClassDef, semantic: &SemanticModel) -> bool { + analyze::class::any_over_body(class_def, semantic, &|call_path| { matches!(call_path.as_slice(), ["django", "db", "models", "Model"]) }) } /// Return `true` if a Python class appears to be a Django model form, based on its base classes. -pub(super) fn is_model_form(base: &Expr, semantic: &SemanticModel) -> bool { - semantic.resolve_call_path(base).is_some_and(|call_path| { +pub(super) fn is_model_form(class_def: &ast::StmtClassDef, semantic: &SemanticModel) -> bool { + analyze::class::any_over_body(class_def, semantic, &|call_path| { matches!( call_path.as_slice(), ["django", "forms", "ModelForm"] | ["django", "forms", "models", "ModelForm"] diff --git a/crates/ruff_linter/src/rules/flake8_django/rules/model_without_dunder_str.rs b/crates/ruff_linter/src/rules/flake8_django/rules/model_without_dunder_str.rs index 9228d04753e4e..0baaeafb347f6 100644 --- a/crates/ruff_linter/src/rules/flake8_django/rules/model_without_dunder_str.rs +++ b/crates/ruff_linter/src/rules/flake8_django/rules/model_without_dunder_str.rs @@ -1,10 +1,9 @@ -use ruff_python_ast::{self as ast, Arguments, Expr, Stmt}; - use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::is_const_true; +use ruff_python_ast::identifier::Identifier; +use ruff_python_ast::{self as ast, Expr, Stmt}; use ruff_python_semantic::SemanticModel; -use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -52,57 +51,39 @@ impl Violation for DjangoModelWithoutDunderStr { } /// DJ008 -pub(crate) fn model_without_dunder_str( - checker: &mut Checker, - ast::StmtClassDef { - name, - arguments, - body, - .. - }: &ast::StmtClassDef, -) { - if !is_non_abstract_model(arguments.as_deref(), body, checker.semantic()) { +pub(crate) fn model_without_dunder_str(checker: &mut Checker, class_def: &ast::StmtClassDef) { + if !is_non_abstract_model(class_def, checker.semantic()) { return; } - if has_dunder_method(body) { + if has_dunder_method(class_def) { return; } - checker - .diagnostics - .push(Diagnostic::new(DjangoModelWithoutDunderStr, name.range())); + checker.diagnostics.push(Diagnostic::new( + DjangoModelWithoutDunderStr, + class_def.identifier(), + )); } -fn has_dunder_method(body: &[Stmt]) -> bool { - body.iter().any(|val| match val { - Stmt::FunctionDef(ast::StmtFunctionDef { name, .. }) => { - if name == "__str__" { - return true; - } - false - } +/// Returns `true` if the class has `__str__` method. +fn has_dunder_method(class_def: &ast::StmtClassDef) -> bool { + class_def.body.iter().any(|val| match val { + Stmt::FunctionDef(ast::StmtFunctionDef { name, .. }) => name == "__str__", _ => false, }) } -fn is_non_abstract_model( - arguments: Option<&Arguments>, - body: &[Stmt], - semantic: &SemanticModel, -) -> bool { - let Some(Arguments { args: bases, .. }) = arguments else { - return false; - }; - - if is_model_abstract(body) { - return false; +/// Returns `true` if the class is a non-abstract Django model. +fn is_non_abstract_model(class_def: &ast::StmtClassDef, semantic: &SemanticModel) -> bool { + if class_def.bases().is_empty() || is_model_abstract(class_def) { + false + } else { + helpers::is_model(class_def, semantic) } - - bases.iter().any(|base| helpers::is_model(base, semantic)) } /// Check if class is abstract, in terms of Django model inheritance. -fn is_model_abstract(body: &[Stmt]) -> bool { - for element in body { +fn is_model_abstract(class_def: &ast::StmtClassDef) -> bool { + for element in &class_def.body { let Stmt::ClassDef(ast::StmtClassDef { name, body, .. }) = element else { continue; }; diff --git a/crates/ruff_linter/src/rules/flake8_django/rules/unordered_body_content_in_model.rs b/crates/ruff_linter/src/rules/flake8_django/rules/unordered_body_content_in_model.rs index 01a63d4e342f9..635527dcaf014 100644 --- a/crates/ruff_linter/src/rules/flake8_django/rules/unordered_body_content_in_model.rs +++ b/crates/ruff_linter/src/rules/flake8_django/rules/unordered_body_content_in_model.rs @@ -1,9 +1,8 @@ use std::fmt; -use ruff_python_ast::{self as ast, Arguments, Expr, Stmt}; - use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::{self as ast, Expr, Stmt}; use ruff_python_semantic::SemanticModel; use ruff_text_size::Ranged; @@ -79,6 +78,50 @@ impl Violation for DjangoUnorderedBodyContentInModel { } } +/// DJ012 +pub(crate) fn unordered_body_content_in_model( + checker: &mut Checker, + class_def: &ast::StmtClassDef, +) { + if !helpers::is_model(class_def, checker.semantic()) { + return; + } + + // Track all the element types we've seen so far. + let mut element_types = Vec::new(); + let mut prev_element_type = None; + for element in &class_def.body { + let Some(element_type) = get_element_type(element, checker.semantic()) else { + continue; + }; + + // Skip consecutive elements of the same type. It's less noisy to only report + // violations at type boundaries (e.g., avoid raising a violation for _every_ + // field declaration that's out of order). + if prev_element_type == Some(element_type) { + continue; + } + + prev_element_type = Some(element_type); + + if let Some(&prev_element_type) = element_types + .iter() + .find(|&&prev_element_type| prev_element_type > element_type) + { + let diagnostic = Diagnostic::new( + DjangoUnorderedBodyContentInModel { + element_type, + prev_element_type, + }, + element.range(), + ); + checker.diagnostics.push(diagnostic); + } else { + element_types.push(element_type); + } + } +} + #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] enum ContentType { FieldDeclaration, @@ -140,53 +183,3 @@ fn get_element_type(element: &Stmt, semantic: &SemanticModel) -> Option None, } } - -/// DJ012 -pub(crate) fn unordered_body_content_in_model( - checker: &mut Checker, - arguments: Option<&Arguments>, - body: &[Stmt], -) { - if !arguments.is_some_and(|arguments| { - arguments - .args - .iter() - .any(|base| helpers::is_model(base, checker.semantic())) - }) { - return; - } - - // Track all the element types we've seen so far. - let mut element_types = Vec::new(); - let mut prev_element_type = None; - for element in body { - let Some(element_type) = get_element_type(element, checker.semantic()) else { - continue; - }; - - // Skip consecutive elements of the same type. It's less noisy to only report - // violations at type boundaries (e.g., avoid raising a violation for _every_ - // field declaration that's out of order). - if prev_element_type == Some(element_type) { - continue; - } - - prev_element_type = Some(element_type); - - if let Some(&prev_element_type) = element_types - .iter() - .find(|&&prev_element_type| prev_element_type > element_type) - { - let diagnostic = Diagnostic::new( - DjangoUnorderedBodyContentInModel { - element_type, - prev_element_type, - }, - element.range(), - ); - checker.diagnostics.push(diagnostic); - } else { - element_types.push(element_type); - } - } -} diff --git a/crates/ruff_linter/src/rules/flake8_django/snapshots/ruff_linter__rules__flake8_django__tests__DJ012_DJ012.py.snap b/crates/ruff_linter/src/rules/flake8_django/snapshots/ruff_linter__rules__flake8_django__tests__DJ012_DJ012.py.snap index 5f15655232937..79e5d7e39539e 100644 --- a/crates/ruff_linter/src/rules/flake8_django/snapshots/ruff_linter__rules__flake8_django__tests__DJ012_DJ012.py.snap +++ b/crates/ruff_linter/src/rules/flake8_django/snapshots/ruff_linter__rules__flake8_django__tests__DJ012_DJ012.py.snap @@ -54,4 +54,12 @@ DJ012.py:129:5: DJ012 Order of model's inner classes, methods, and fields does n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DJ012 | +DJ012.py:146:5: DJ012 Order of model's inner classes, methods, and fields does not follow the Django Style Guide: field declaration should come before `Meta` class + | +144 | return "foobar" +145 | +146 | first_name = models.CharField(max_length=32) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DJ012 + | + diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs b/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs index 2eaab9dd27788..1f548896057b9 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/helpers.rs @@ -1,13 +1,12 @@ use anyhow::Result; -use rustc_hash::FxHashSet; use ruff_diagnostics::Edit; use ruff_python_ast::call_path::from_qualified_name; -use ruff_python_ast::helpers::{map_callable, map_subscript}; +use ruff_python_ast::helpers::map_callable; use ruff_python_ast::{self as ast, Expr}; use ruff_python_codegen::{Generator, Stylist}; use ruff_python_semantic::{ - Binding, BindingId, BindingKind, NodeId, ResolvedReference, SemanticModel, + analyze, Binding, BindingKind, NodeId, ResolvedReference, SemanticModel, }; use ruff_source_file::Locator; use ruff_text_size::Ranged; @@ -59,57 +58,17 @@ pub(crate) fn runtime_required_class( false } +/// Return `true` if a class is a subclass of a runtime-required base class. fn runtime_required_base_class( class_def: &ast::StmtClassDef, base_classes: &[String], semantic: &SemanticModel, ) -> bool { - fn inner( - class_def: &ast::StmtClassDef, - base_classes: &[String], - semantic: &SemanticModel, - seen: &mut FxHashSet, - ) -> bool { - class_def.bases().iter().any(|expr| { - // If the base class is itself runtime-required, then this is too. - // Ex) `class Foo(BaseModel): ...` - if semantic - .resolve_call_path(map_subscript(expr)) - .is_some_and(|call_path| { - base_classes - .iter() - .any(|base_class| from_qualified_name(base_class) == call_path) - }) - { - return true; - } - - // If the base class extends a runtime-required class, then this does too. - // Ex) `class Bar(BaseModel): ...; class Foo(Bar): ...` - if let Some(id) = semantic.lookup_attribute(map_subscript(expr)) { - if seen.insert(id) { - let binding = semantic.binding(id); - if let Some(base_class) = binding - .kind - .as_class_definition() - .map(|id| &semantic.scopes[*id]) - .and_then(|scope| scope.kind.as_class()) - { - if inner(base_class, base_classes, semantic, seen) { - return true; - } - } - } - } - false - }) - } - - if base_classes.is_empty() { - return false; - } - - inner(class_def, base_classes, semantic, &mut FxHashSet::default()) + analyze::class::any_over_body(class_def, semantic, &|call_path| { + base_classes + .iter() + .any(|base_class| from_qualified_name(base_class) == call_path) + }) } fn runtime_required_decorators( diff --git a/crates/ruff_python_semantic/src/analyze/class.rs b/crates/ruff_python_semantic/src/analyze/class.rs new file mode 100644 index 0000000000000..3efc01ff33754 --- /dev/null +++ b/crates/ruff_python_semantic/src/analyze/class.rs @@ -0,0 +1,57 @@ +use rustc_hash::FxHashSet; + +use ruff_python_ast as ast; +use ruff_python_ast::call_path::CallPath; +use ruff_python_ast::helpers::map_subscript; + +use crate::{BindingId, SemanticModel}; + +/// Return `true` if any base class of a class definition matches a predicate. +pub fn any_over_body( + class_def: &ast::StmtClassDef, + semantic: &SemanticModel, + func: &dyn Fn(CallPath) -> bool, +) -> bool { + fn inner( + class_def: &ast::StmtClassDef, + semantic: &SemanticModel, + func: &dyn Fn(CallPath) -> bool, + seen: &mut FxHashSet, + ) -> bool { + class_def.bases().iter().any(|expr| { + // If the base class itself matches the pattern, then this does too. + // Ex) `class Foo(BaseModel): ...` + if semantic + .resolve_call_path(map_subscript(expr)) + .is_some_and(func) + { + return true; + } + + // If the base class extends a class that matches the pattern, then this does too. + // Ex) `class Bar(BaseModel): ...; class Foo(Bar): ...` + if let Some(id) = semantic.lookup_attribute(map_subscript(expr)) { + if seen.insert(id) { + let binding = semantic.binding(id); + if let Some(base_class) = binding + .kind + .as_class_definition() + .map(|id| &semantic.scopes[*id]) + .and_then(|scope| scope.kind.as_class()) + { + if inner(base_class, semantic, func, seen) { + return true; + } + } + } + } + false + }) + } + + if class_def.bases().is_empty() { + return false; + } + + inner(class_def, semantic, func, &mut FxHashSet::default()) +} diff --git a/crates/ruff_python_semantic/src/analyze/mod.rs b/crates/ruff_python_semantic/src/analyze/mod.rs index f0fb3844e30c6..0376f63c39f43 100644 --- a/crates/ruff_python_semantic/src/analyze/mod.rs +++ b/crates/ruff_python_semantic/src/analyze/mod.rs @@ -1,3 +1,4 @@ +pub mod class; pub mod function_type; pub mod imports; pub mod logging; From 2c6b534e1f8dec1abe12c3f55ecdb1a0bd197db7 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Sat, 16 Dec 2023 00:05:38 -0600 Subject: [PATCH 196/197] Update ecosystem check headers to show unchanged project count (#9157) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of displaying the total completed project count in the "changed" section of a header, we now separately calculated the changed and unchanged count to make the header message nice and clear. e.g. > ℹ️ ecosystem check **detected format changes**. (+1772 -1859 lines in 239 files in 26 projects; 6 project errors; 9 projects unchanged) and > ℹ️ ecosystem check **detected linter changes**. (+4598 -5023 violations, +0 -40 fixes in 13 projects; 4 project errors; 24 projects unchanged) Previously, it would have included the unchanged count in the first project count. --- python/ruff-ecosystem/ruff_ecosystem/check.py | 13 ++++++++++++- python/ruff-ecosystem/ruff_ecosystem/format.py | 16 +++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/python/ruff-ecosystem/ruff_ecosystem/check.py b/python/ruff-ecosystem/ruff_ecosystem/check.py index fe5ea0c246434..89d4320570858 100644 --- a/python/ruff-ecosystem/ruff_ecosystem/check.py +++ b/python/ruff-ecosystem/ruff_ecosystem/check.py @@ -52,6 +52,8 @@ def markdown_check_result(result: Result) -> str: """ Render a `ruff check` ecosystem check result as markdown. """ + projects_with_changes = 0 + # Calculate the total number of rule changes all_rule_changes = RuleChanges() project_diffs = { @@ -63,6 +65,9 @@ def markdown_check_result(result: Result) -> str: project_rule_changes[project] = changes = RuleChanges.from_diff(diff) all_rule_changes.update(changes) + if diff: + projects_with_changes += 1 + lines: list[str] = [] total_removed = all_rule_changes.total_removed_violations() total_added = all_rule_changes.total_added_violations() @@ -88,11 +93,17 @@ def markdown_check_result(result: Result) -> str: change_summary = ( f"{markdown_plus_minus(total_added, total_removed)} violations, " f"{markdown_plus_minus(total_added_fixes, total_removed_fixes)} fixes " - f"in {len(result.completed)} projects" + f"in {projects_with_changes} projects" ) if error_count: s = "s" if error_count != 1 else "" change_summary += f"; {error_count} project error{s}" + + unchanged_projects = len(result.completed) - projects_with_changes + if unchanged_projects: + s = "s" if unchanged_projects != 1 else "" + change_summary += f"; {unchanged_projects} project{s} unchanged" + lines.append( f"\u2139\ufe0f ecosystem check **detected linter changes**. ({change_summary})" ) diff --git a/python/ruff-ecosystem/ruff_ecosystem/format.py b/python/ruff-ecosystem/ruff_ecosystem/format.py index 2a15e62920e95..b448c208da81d 100644 --- a/python/ruff-ecosystem/ruff_ecosystem/format.py +++ b/python/ruff-ecosystem/ruff_ecosystem/format.py @@ -28,6 +28,7 @@ def markdown_format_result(result: Result) -> str: lines: list[str] = [] total_lines_removed = total_lines_added = 0 total_files_modified = 0 + projects_with_changes = 0 error_count = len(result.errored) patch_sets: list[PatchSet] = [] @@ -39,6 +40,9 @@ def markdown_format_result(result: Result) -> str: patch_sets.append(patch_set) total_files_modified += len(patch_set.modified_files) + if comparison.diff: + projects_with_changes += 1 + if total_lines_removed == 0 and total_lines_added == 0 and error_count == 0: return "\u2705 ecosystem check detected no format changes." @@ -51,11 +55,21 @@ def markdown_format_result(result: Result) -> str: ) else: s = "s" if total_files_modified != 1 else "" - changes = f"+{total_lines_added} -{total_lines_removed} lines in {total_files_modified} file{s} in {len(result.completed)} projects" + changes = ( + f"+{total_lines_added} -{total_lines_removed} lines " + f"in {total_files_modified} file{s} in " + f"{projects_with_changes} projects" + ) + if error_count: s = "s" if error_count != 1 else "" changes += f"; {error_count} project error{s}" + unchanged_projects = len(result.completed) - projects_with_changes + if unchanged_projects: + s = "s" if unchanged_projects != 1 else "" + changes += f"; {unchanged_projects} project{s} unchanged" + lines.append( f"\u2139\ufe0f ecosystem check **detected format changes**. ({changes})" ) From 0029b4fd07f2c23cb8e0e4ce005c56ba1dfc4141 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Sat, 16 Dec 2023 00:14:17 -0600 Subject: [PATCH 197/197] Fix ecosystem format line changed counts (#9158) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were erroneously including patch headers so for each _file_ changed we could include an extra added and removed line e.g. we counted the diff in the following as +4 -4 instead of +3 -3. ```diff diff --git a/tests/test_param_include_in_schema.py b/tests/test_param_include_in_schema.py index 26201e9..f461947 100644 --- a/tests/test_param_include_in_schema.py +++ b/tests/test_param_include_in_schema.py @@ -9,14 +9,14 @@ app = FastAPI() @app.get("/hidden_cookie") async def hidden_cookie( - hidden_cookie: Optional[str] = Cookie(default=None, include_in_schema=False) + hidden_cookie: Optional[str] = Cookie(default=None, include_in_schema=False), ): return {"hidden_cookie": hidden_cookie} @app.get("/hidden_header") async def hidden_header( - hidden_header: Optional[str] = Header(default=None, include_in_schema=False) + hidden_header: Optional[str] = Header(default=None, include_in_schema=False), ): return {"hidden_header": hidden_header} @@ -28,7 +28,7 @@ async def hidden_path(hidden_path: str = Path(include_in_schema=False)): @app.get("/hidden_query") async def hidden_query( - hidden_query: Optional[str] = Query(default=None, include_in_schema=False) + hidden_query: Optional[str] = Query(default=None, include_in_schema=False), ): return {"hidden_query": hidden_query} ``` Tested with a single project locally e.g. > ℹ️ ecosystem check **detected format changes**. (+65 -65 lines in 39 files in 1 projects) > >
tiangolo/fastapi (+65 -65 lines across 39 files) instead of > ℹ️ ecosystem check **detected format changes**. (+104 -104 lines in 39 files in 1 projects) > >
tiangolo/fastapi (+104 -104 lines across 39 files) --- python/ruff-ecosystem/ruff_ecosystem/types.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/ruff-ecosystem/ruff_ecosystem/types.py b/python/ruff-ecosystem/ruff_ecosystem/types.py index 687ab31ce82b4..e9b9664aeea44 100644 --- a/python/ruff-ecosystem/ruff_ecosystem/types.py +++ b/python/ruff-ecosystem/ruff_ecosystem/types.py @@ -32,11 +32,15 @@ def __init__(self, lines: Iterable[str], leading_spaces: int = 0) -> None: line[2:] for line in self.lines if line.startswith("+" + " " * leading_spaces) + # Do not include patch headers + and not line.startswith("+++") ) self.removed = list( line[2:] for line in self.lines if line.startswith("-" + " " * leading_spaces) + # Do not include patch headers + and not line.startswith("---") ) def __bool__(self) -> bool: