-
Notifications
You must be signed in to change notification settings - Fork 0
Implement ANTLR v4 Rust runtime #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
72 commits
Select commit
Hold shift + click to select a range
8c385c4
Implement clean-room ANTLR Rust runtime
tinovyatkin 455f1d8
Add ANTLR runtime testsuite harness
tinovyatkin f9414cc
Improve lexer runtime-testsuite conformance
tinovyatkin 045fd3e
Run parser runtime-testsuite smoke descriptors
tinovyatkin 6561448
Improve parser runtime-testsuite conformance
tinovyatkin ab5f34e
Expand parser runtime testsuite coverage
tinovyatkin 1cdc314
Add lexer target action support
tinovyatkin 4a206a5
Support parser token label text actions
tinovyatkin 3dec6da
Support parser after stdout actions
tinovyatkin 906b560
Build nested trees for parser actions
tinovyatkin 574a45c
Support labeled parse tree after actions
tinovyatkin 2189e07
Shape left-recursive parse trees
tinovyatkin e34456e
Support parser runtime helper actions
tinovyatkin 11634c6
Support parser no-op target templates
tinovyatkin 1856b80
Support parser member no-op templates
tinovyatkin ace3320
Report parser mismatch diagnostics
tinovyatkin 8072b64
Support single-token parser recovery
tinovyatkin 661ae48
Render target token actions and lexer predicates
tinovyatkin b5d4a2e
Render parser expected-token init actions
tinovyatkin 5336c22
Render alt-numbered parse trees
tinovyatkin 96cb00a
Support position-adjusting lexer template
tinovyatkin fada78d
Render non-greedy if-else text actions
tinovyatkin 7c1a701
Evaluate parser lookahead predicates
tinovyatkin d57e6f5
Admit extraneous input diagnostics
tinovyatkin d7def9b
Recover mismatched parse-tree tokens
tinovyatkin 1f5e291
Honor parser decision order for actions
tinovyatkin 7df5b0f
Admit ordered parser predicates
tinovyatkin 0db15c5
Support parser LTEquals predicates
tinovyatkin e3ac4e3
Support AppendStr token text actions
tinovyatkin 2e976f9
Support runtime listener templates
tinovyatkin f6d41ca
Support left recursion return value actions
tinovyatkin 7a3a1fb
Admit common label compile-check templates
tinovyatkin f37d2da
Support selected semantic predicate templates
tinovyatkin 0c7359b
Support parser rule argument predicates
tinovyatkin 79fb57e
Support parser member target templates
tinovyatkin 8f9e0ea
Admit multi-token deletion before loop diagnostic
tinovyatkin 0c9b827
Preserve inherited recovery expectations at loop decisions
tinovyatkin 458acaf
Recover by deleting tokens at decision contexts
tinovyatkin f62189f
Recover through repeated loop token deletion
tinovyatkin 585d3e7
Buffer lexer diagnostics for parser recovery order
tinovyatkin 619b787
Report no viable LL parser alternatives
tinovyatkin 422cf75
Handle empty complement parser diagnostics
tinovyatkin c12944e
Report no viable failed predicates
tinovyatkin 0ad5e71
Run basic composite grammar descriptors
tinovyatkin 4bf9d38
Filter mixed grammar action templates
tinovyatkin 4833fe3
Handle composite parser import actions
tinovyatkin ea8f1fb
Capture parser rule return actions
tinovyatkin 4e789bd
Respect lexer action ownership
tinovyatkin e063753
Admit LL prediction mode
tinovyatkin ec18ecc
Support parser ambiguity diagnostics
tinovyatkin 39b766a
Evaluate boolean member predicates
tinovyatkin d15decd
Record lexer DFA dumps
tinovyatkin 1149df8
Support lexer column predicates
tinovyatkin 2819e12
Support SLL prediction mode
tinovyatkin 2555d06
Complete semantic lexer DFA fixtures
tinovyatkin 28cf079
Recover failed child parser rules
tinovyatkin 64e0bd4
Handle EOF unwind recovery
tinovyatkin 083e0d2
Support predicate fail options
tinovyatkin 23bd14d
Enable full context runtime cases
tinovyatkin 695bef7
Default runtime testsuite inputs
tinovyatkin 50add82
Prepare crate publication
tinovyatkin 435f4ee
Use BSD license and crate name
tinovyatkin 086e198
Fix README JSON example
tinovyatkin 1cec68a
Adopt stricter Clippy policy
tinovyatkin c3f39ac
Add GitHub Actions workflows
tinovyatkin 6510a2b
Add copy paste detection workflow
tinovyatkin 4855190
Extract shared generator helpers
tinovyatkin 410e955
Address PR review feedback
tinovyatkin 42bd95e
Document antlr-ng metadata workflow
tinovyatkin 1a98bd3
Address PR review findings
tinovyatkin c128f43
Address follow-up review findings
tinovyatkin 0b66e33
Address parser review follow-ups
tinovyatkin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| # Complexity thresholds | ||
| allowed-idents-below-min-chars = ["..", "id", "x", "y", "z", "i", "j", "k", "n", "m"] | ||
| cognitive-complexity-threshold = 15 | ||
| excessive-nesting-threshold = 8 | ||
| min-ident-chars-threshold = 2 | ||
| single-char-binding-names-threshold = 3 | ||
| too-many-arguments-threshold = 6 | ||
| # The generator and runtime-testsuite harness still contain a few deliberately | ||
| # dense functions. Keep this inherited strict-policy threshold explicit so new | ||
| # jumbo helpers fail Clippy without forcing premature splits in those modules. | ||
| too-many-lines-threshold = 476 | ||
| trivial-copy-size-limit = 16 | ||
| type-complexity-threshold = 300 | ||
|
|
||
| avoid-breaking-exported-api = false | ||
|
|
||
| # Testing allowances | ||
| allow-dbg-in-tests = true | ||
| allow-expect-in-tests = true | ||
| allow-print-in-tests = true | ||
| allow-unwrap-in-tests = true | ||
| suppress-restriction-lint-in-const = true | ||
|
|
||
| # Trait implementations | ||
| allow-renamed-params-for = ["core::fmt::Debug", "core::fmt::Display", "futures_sink::Sink", "serde::de::Visitor", ".."] | ||
|
|
||
| # Documentation | ||
| doc-valid-idents = [ | ||
| "..", | ||
| "ANTLR", | ||
| "CodeQL", | ||
| "CPython", | ||
| "FastAPI", | ||
| "IPython", | ||
| "LangChain", | ||
| "LibCST", | ||
| "McCabe", | ||
| "NumPy", | ||
| "SCREAMING_SNAKE_CASE", | ||
| "SQLAlchemy", | ||
| "StackOverflow", | ||
| "PyCharm", | ||
| "SNMPv1", | ||
| "SNMPv2", | ||
| "SNMPv3", | ||
| "PyFlakes", | ||
| "GraphQL", | ||
| "gRPC", | ||
| "WebSocket", | ||
| "PostgreSQL", | ||
| "MySQL", | ||
| "SQLite", | ||
| "MongoDB", | ||
| "Redis", | ||
| "Kubernetes", | ||
| "GitHub", | ||
| "GitLab", | ||
| ] | ||
|
|
||
| disallowed-names = ["foo", "bar", "baz", "tmp", "qux", "temp", "test", "dummy"] | ||
|
|
||
| disallowed-types = [ | ||
| { path = "std::collections::HashMap", reason = "Non-deterministic iter - use indexmap::IndexMap instead" }, | ||
| { path = "std::collections::HashSet", reason = "Non-deterministic iter - use indexmap::IndexSet instead" }, | ||
| { path = "std::sync::Once", reason = "Use std::sync::OnceLock for lazy initialization (available since 1.70)" }, | ||
| { path = "rand::rngs::ThreadRng", reason = "ThreadRng is inherently non-deterministic; use a fixed-seed or hash-based approach instead." }, | ||
| ] | ||
|
|
||
| disallowed-methods = [ | ||
| { path = "rand::random", reason = "Use a deterministic hash (e.g. via a cryptographic hasher like Sha256) instead of `rand::random`." }, | ||
| { path = "rand::Rng::gen", reason = "Use a deterministic hash (e.g. via Sha256) rather than generating random bytes at runtime.", allow-invalid = true }, | ||
|
|
||
| { path = "str::to_ascii_lowercase", reason = "Avoid hidden allocation; use an explicit conversion helper." }, | ||
| { path = "str::to_ascii_uppercase", reason = "Avoid hidden allocation; use an explicit conversion helper." }, | ||
| { path = "str::to_lowercase", reason = "Avoid hidden allocation; use an explicit conversion helper." }, | ||
| { path = "str::to_uppercase", reason = "Avoid hidden allocation; use an explicit conversion helper." }, | ||
| { path = "str::replace", reason = "Avoid hidden allocation in hot paths." }, | ||
| { path = "str::replacen", reason = "Avoid hidden allocation in hot paths." }, | ||
|
|
||
| { path = "std::mem::forget", reason = "future::scope is unsafe when used with forget" }, | ||
| { path = "futures::executor::block_on", reason = "block_on can cause deadlock easily" }, | ||
| { path = "async_std::task::block_on", reason = "block_on can cause deadlock easily" }, | ||
| { path = "pollster::block_on", reason = "block_on can cause deadlock easily" }, | ||
|
|
||
| { path = "std::time::Instant::now", reason = "Do not use current date/time in code that must be deterministic" }, | ||
| { path = "namada_core::time::DateTimeUtc::now", reason = "Do not use current date/time in code that must be deterministic" }, | ||
| { path = "wasmtimer::std::Instant", reason = "Do not use current date/time in code that must be deterministic" }, | ||
|
|
||
| { path = "std::iter::Iterator::for_each", reason = "prefer `for` for side-effects" }, | ||
|
|
||
| { path = "std::option::Option::unwrap", reason = "use `expect` with descriptive message or handle None case" }, | ||
| { path = "std::result::Result::unwrap", reason = "use `expect` with descriptive message or handle error case" }, | ||
| { path = "std::panic::catch_unwind", reason = "panics are not for control flow - use Result" }, | ||
| { path = "std::process::exit", reason = "return Result from main() instead of exiting" }, | ||
| { path = "std::thread::sleep", reason = "use async sleep in async contexts, or document why blocking is needed" }, | ||
| { path = "std::mem::transmute", reason = "use safe alternatives like bytemuck or zerocopy" }, | ||
| { path = "std::mem::uninitialized", reason = "deprecated - use MaybeUninit" }, | ||
| { path = "std::mem::zeroed", reason = "use MaybeUninit::zeroed or Default::default" }, | ||
|
|
||
| { path = "tokio::task::spawn_blocking", reason = "document why blocking is necessary - consider async alternatives" }, | ||
| ] | ||
|
|
||
| ignore-interior-mutability = [] | ||
|
|
||
| allowed-duplicate-crates = [] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| name: ANTLR Runtime Testsuite | ||
|
|
||
| on: | ||
| pull_request: | ||
| push: | ||
| branches: | ||
| - main | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| env: | ||
| ANTLR_VERSION: 4.13.2 | ||
| ANTLR4_JAR: /tmp/antlr-cleanroom/tools/antlr-4.13.2-complete.jar | ||
| ANTLR4_RUNTIME_TESTSUITE: /tmp/antlr-cleanroom/antlr4-upstream/runtime-testsuite | ||
| CARGO_TERM_COLOR: always | ||
|
|
||
| jobs: | ||
| runtime-testsuite: | ||
| name: Runtime Testsuite | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 90 | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Install stable Rust | ||
| run: | | ||
| rustup toolchain install stable --profile minimal --no-self-update | ||
| rustup default stable | ||
|
|
||
| - name: Install Java | ||
| uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 | ||
| with: | ||
| distribution: temurin | ||
| java-version: "21" | ||
|
|
||
| - name: Prepare ANTLR runtime testsuite | ||
| run: | | ||
| set -euxo pipefail | ||
| mkdir -p /tmp/antlr-cleanroom/tools | ||
| curl --fail --location --output "${ANTLR4_JAR}" \ | ||
| "https://www.antlr.org/download/antlr-${ANTLR_VERSION}-complete.jar" | ||
| git clone --depth 1 --branch "${ANTLR_VERSION}" \ | ||
| https://github.com/antlr/antlr4.git \ | ||
| /tmp/antlr-cleanroom/antlr4-upstream | ||
|
|
||
| - name: Run ANTLR runtime testsuite | ||
| run: cargo run --locked --quiet --bin antlr4-runtime-testsuite |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| name: CI | ||
|
|
||
| on: | ||
| pull_request: | ||
| push: | ||
| branches: | ||
| - main | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| env: | ||
| CARGO_TERM_COLOR: always | ||
|
|
||
| jobs: | ||
| check: | ||
| name: Clippy and Unit Tests | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Install stable Rust | ||
| run: | | ||
| rustup toolchain install stable --profile minimal --component clippy --no-self-update | ||
| rustup default stable | ||
|
|
||
| - name: Run Clippy | ||
| run: cargo clippy --locked --all-targets --all-features -- -D warnings | ||
|
|
||
| - name: Run unit tests | ||
| run: cargo test --locked |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,178 @@ | ||
| name: Copy/Paste Detection | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: | ||
| - main | ||
| paths: | ||
| - "**/*.rs" | ||
| - "!target/**" | ||
| - ".github/workflows/cpd.yml" | ||
|
|
||
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
|
|
||
| concurrency: | ||
| group: cpd-${{ github.event.pull_request.number || github.run_id }} | ||
| cancel-in-progress: true | ||
|
|
||
| env: | ||
| PMD_VERSION: 7.20.0 | ||
| CPD_TOKENS: "100" | ||
| COMMENT_MARKER: <!-- cpd-report --> | ||
|
|
||
| jobs: | ||
| cpd: | ||
| name: Copy/Paste Detection | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 | ||
| with: | ||
| fetch-depth: 0 | ||
| persist-credentials: false | ||
|
|
||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| - name: Determine changed Rust files | ||
| id: changed | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| BASE_SHA=$(git merge-base "origin/${GITHUB_BASE_REF}" HEAD) | ||
|
|
||
| git diff --name-only --diff-filter=d "$BASE_SHA" HEAD -- "*.rs" \ | ||
| | grep -Ev "^target/" \ | ||
| > changed-files.txt || true | ||
|
|
||
| COUNT=$(wc -l < changed-files.txt | tr -d " ") | ||
| echo "count=$COUNT" >> "$GITHUB_OUTPUT" | ||
| echo "Changed Rust files ($COUNT):" | ||
| cat changed-files.txt || true | ||
|
|
||
| - name: Setup Java | ||
| if: steps.changed.outputs.count != '0' | ||
| uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 | ||
| with: | ||
| distribution: temurin | ||
| java-version: "21" | ||
|
|
||
| - name: Setup PMD | ||
| if: steps.changed.outputs.count != '0' | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| curl -fL "https://github.com/pmd/pmd/releases/download/pmd_releases%2F${PMD_VERSION}/pmd-dist-${PMD_VERSION}-bin.zip" -o pmd.zip | ||
| unzip -q pmd.zip | ||
| rm pmd.zip | ||
|
|
||
| - name: Run CPD | ||
| id: cpd | ||
| shell: bash | ||
| run: | | ||
| set -uo pipefail | ||
|
|
||
| if [ "${{ steps.changed.outputs.count }}" = "0" ]; then | ||
| : > cpd-report.md | ||
| echo "duplications=0" >> "$GITHUB_OUTPUT" | ||
| echo "No changed Rust files." | ||
| exit 0 | ||
| fi | ||
|
|
||
| # PMD CPD exit codes: | ||
| # 0 - no duplications | ||
| # 4 - duplications found | ||
| # 5 - recoverable errors, for example a file failed to lex | ||
| set +e | ||
| "pmd-bin-${PMD_VERSION}/bin/pmd" cpd \ | ||
| --language rust \ | ||
| --minimum-tokens "${CPD_TOKENS}" \ | ||
| --file-list changed-files.txt \ | ||
| --format markdown \ | ||
| > cpd-report.md 2> cpd-stderr.log | ||
| STATUS=$? | ||
| set -e | ||
|
|
||
| if [ "$STATUS" -ne 0 ] && [ "$STATUS" -ne 4 ] && [ "$STATUS" -ne 5 ]; then | ||
| echo "PMD CPD errored (status $STATUS):" | ||
| cat cpd-stderr.log | ||
| exit "$STATUS" | ||
| fi | ||
|
|
||
| if [ -s cpd-stderr.log ]; then | ||
| echo "=== PMD stderr ===" | ||
| cat cpd-stderr.log | ||
| fi | ||
|
|
||
| sed -i "s|${GITHUB_WORKSPACE}/||g" cpd-report.md | ||
|
|
||
| awk ' | ||
| BEGIN { open = 0 } | ||
| /^```$/ { | ||
| if (open == 0) { print "```rust"; open = 1 } | ||
| else { print "```"; open = 0 } | ||
| next | ||
| } | ||
| { print } | ||
| ' cpd-report.md > cpd-report.tagged.md | ||
| mv cpd-report.tagged.md cpd-report.md | ||
|
|
||
| DUP_COUNT=$(grep -c "^Found a " cpd-report.md || true) | ||
| echo "duplications=${DUP_COUNT:-0}" >> "$GITHUB_OUTPUT" | ||
|
|
||
| echo "=== Report ===" | ||
| cat cpd-report.md | ||
|
|
||
| - name: Build comment body | ||
| shell: bash | ||
| env: | ||
| CHANGED_COUNT: ${{ steps.changed.outputs.count }} | ||
| DUP_COUNT: ${{ steps.cpd.outputs.duplications }} | ||
| run: | | ||
| set -euo pipefail | ||
| { | ||
| echo "${COMMENT_MARKER}" | ||
| echo "## Copy/Paste Detection" | ||
| echo "" | ||
| if [ "${DUP_COUNT:-0}" = "0" ]; then | ||
| echo "No duplications found in ${CHANGED_COUNT} changed Rust file(s) (threshold: ${CPD_TOKENS} tokens)." | ||
| else | ||
| echo "Found **${DUP_COUNT}** duplication(s) across ${CHANGED_COUNT} changed Rust file(s) (threshold: ${CPD_TOKENS} tokens)." | ||
| echo "" | ||
| echo "<details>" | ||
| echo "<summary>Show duplications</summary>" | ||
| echo "" | ||
| cat cpd-report.md | ||
| echo "" | ||
| echo "</details>" | ||
| fi | ||
| } > comment-body.md | ||
|
|
||
| SIZE=$(wc -c < comment-body.md) | ||
| if [ "$SIZE" -gt 60000 ]; then | ||
| head -c 60000 comment-body.md > comment-body.trunc.md | ||
| printf "\n\n_(report truncated; full output in workflow logs)_\n" >> comment-body.trunc.md | ||
| mv comment-body.trunc.md comment-body.md | ||
| fi | ||
|
|
||
| cat comment-body.md | ||
|
|
||
| - name: Post sticky PR comment | ||
| if: github.event.pull_request.head.repo.full_name == github.repository | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| PR_NUMBER: ${{ github.event.pull_request.number }} | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| BODY=$(cat comment-body.md) | ||
|
|
||
| COMMENT_ID=$(gh api "repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \ | ||
| --paginate -q ".[] | select(.body | startswith(\"${COMMENT_MARKER}\")) | .id" | head -1) | ||
|
|
||
| if [ -n "$COMMENT_ID" ]; then | ||
| gh api "repos/${{ github.repository }}/issues/comments/${COMMENT_ID}" \ | ||
| -X PATCH -f body="$BODY" | ||
| else | ||
| gh pr comment "$PR_NUMBER" --body "$BODY" | ||
| fi | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.