Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
315 changes: 280 additions & 35 deletions src/parser.rs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
source: src/parser.rs
expression: contexts
---
[
(
0,
0,
6,
"1+2",
),
(
0,
0,
1,
"1",
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
source: src/parser.rs
expression: "(root.alt_number(), root.context_alt_number(), root.text())"
---
(
0,
2,
"x<EOF>",
)
10 changes: 10 additions & 0 deletions tools/parse-bench/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ The script regenerates parsers into `target/parse-bench`, builds:
- a Go ANTLR runner using `github.com/antlr4-go/antlr/v4`,
- a tree-sitter runner using `tree-sitter-language-pack`.

Rust generation keeps the pinned `JavaParser.g4` unchanged, including its
`JavaParserBase` option and both semantic predicates. The generated benchmark
parser uses the source compiler's historical `assume-true` policy for those
target-language helpers, matching downstream generation while retaining the
predicate metadata that controls runtime routing. Python and Go still use the
equivalent portable rewrite because that grammars-v4 revision does not provide
`JavaParserBase` implementations for those targets. The
`issue-174-return-expression.java` fixture guards the resulting Java
method-body performance path.

The output table reports `min` and `avg` parse time per fixture and a relative
ratio against `rust-antlr` for the same fixture.
Use `--rust-generated-only` for Adaptive LL delivery evidence so the Rust
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class C {
int m() {
return 1;
}
}
10 changes: 10 additions & 0 deletions tools/parse-bench/fixtures/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@
"lex"
]
},
{
"language": "java",
"path": "java/issue-174-return-expression.java",
"source": "repository regression benchmark for issue #174",
"license": "BSD-3-Clause",
"description": "Minimal Java method-body return expression that exposes predicate-aware interpreted-rule routing regressions.",
"phases": [
"parse"
]
},
{
"language": "java",
"path": "java/mojang-data-result.java",
Expand Down
37 changes: 23 additions & 14 deletions tools/parse-bench/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ def predicate_replacement(match: re.Match[str]) -> str:
return grammar.replace("this.", "l.")


def transform_java(grammar_dir: Path) -> None:
def transform_java_for_portable_target(grammar_dir: Path) -> None:
parser = grammar_dir / "JavaParser.g4"
text = parser.read_text()
text = text.replace(" superClass = JavaParserBase;\n", "")
Expand All @@ -274,6 +274,25 @@ def transform_java(grammar_dir: Path) -> None:
parser.write_text(text)


def prepare_runtime_grammar(
spec: LanguageSpec,
grammars_v4: Path,
target: Path,
runtime: str,
) -> None:
copy_grammar(spec, grammars_v4, target)
if spec.name == "csharp":
if runtime == "python-antlr":
transform_csharp_python(target)
elif runtime == "go-antlr":
transform_csharp_go(target)
elif spec.name == "java" and runtime != "rust-antlr":
# The pinned grammars-v4 revision has no Python or Go JavaParserBase.
# Keep their equivalent portable rewrite, but retain the untouched
# predicates for Rust so this benchmark covers runtime semantic routing.
transform_java_for_portable_target(target)


def generate_antlr(
antlr_jar: Path,
spec: LanguageSpec,
Expand Down Expand Up @@ -1217,9 +1236,7 @@ def prepare_work(
for spec in specs:
if "rust-antlr" in runtimes:
base_grammar = work_dir / "grammars" / spec.name / "base"
copy_grammar(spec, args.grammars_v4, base_grammar)
if spec.name == "java":
transform_java(base_grammar)
prepare_runtime_grammar(spec, args.grammars_v4, base_grammar, "rust-antlr")
generate_rust_modules(
spec,
base_grammar,
Expand All @@ -1230,22 +1247,14 @@ def prepare_work(

if "python-antlr" in runtimes:
py_grammar = work_dir / "grammars" / spec.name / "python"
copy_grammar(spec, args.grammars_v4, py_grammar)
if spec.name == "csharp":
transform_csharp_python(py_grammar)
if spec.name == "java":
transform_java(py_grammar)
prepare_runtime_grammar(spec, args.grammars_v4, py_grammar, "python-antlr")
py_lang_gen = py_gen
generate_antlr(args.antlr_jar, spec, py_grammar, py_lang_gen, "Python3")
prepare_python_support(spec, args.grammars_v4, py_lang_gen)

if "go-antlr" in runtimes:
go_grammar = work_dir / "grammars" / spec.name / "go"
copy_grammar(spec, args.grammars_v4, go_grammar)
if spec.name == "csharp":
transform_csharp_go(go_grammar)
if spec.name == "java":
transform_java(go_grammar)
prepare_runtime_grammar(spec, args.grammars_v4, go_grammar, "go-antlr")
go_gen = work_dir / "generated" / spec.name / "go"
package_name = go_package_name(spec)
generate_antlr(args.antlr_jar, spec, go_grammar, go_gen, "Go", package_name)
Expand Down
46 changes: 46 additions & 0 deletions tools/parse-bench/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,52 @@ def test_allows_disjoint_and_nested_work_directories(self) -> None:
self.assertTrue(marker.exists())


class RuntimeGrammarPreparationTests(unittest.TestCase):
JAVA_PARSER = """parser grammar JavaParser;
options {
tokenVocab = JavaLexer;
superClass = JavaParserBase;
}
annotationFieldValue:
{ this.IsNotIdentifierAssign() }? annotationValue
| identifier '=' annotationValue
;
recordComponentList
: recordComponent (',' recordComponent)* { this.DoLastRecordComponent() }?
;
"""

def prepare_java(self, root: Path, runtime: str) -> str:
grammar_source = root / "grammars-v4" / "java" / "java"
grammar_source.mkdir(parents=True)
(grammar_source / "JavaLexer.g4").write_text("lexer grammar JavaLexer;\n")
(grammar_source / "JavaParser.g4").write_text(self.JAVA_PARSER)
target = root / runtime
RUN.prepare_runtime_grammar(
RUN.LANGUAGES["java"],
root / "grammars-v4",
target,
runtime,
)
return (target / "JavaParser.g4").read_text()

def test_rust_java_grammar_preserves_superclass_and_predicates(self) -> None:
with tempfile.TemporaryDirectory() as temp:
parser = self.prepare_java(Path(temp), "rust-antlr")

self.assertEqual(parser, self.JAVA_PARSER)

def test_portable_java_targets_remove_unavailable_base_predicates(self) -> None:
for runtime in ("python-antlr", "go-antlr"):
with self.subTest(runtime=runtime), tempfile.TemporaryDirectory() as temp:
parser = self.prepare_java(Path(temp), runtime)

self.assertNotIn("superClass = JavaParserBase", parser)
self.assertNotIn("IsNotIdentifierAssign", parser)
self.assertNotIn("DoLastRecordComponent", parser)
self.assertIn("identifier '=' annotationValue", parser)


class RustCodegenFlagsTests(unittest.TestCase):
def test_combines_native_and_profile_generation(self) -> None:
self.assertEqual(
Expand Down
Loading