Skip to content

Commit cdf947b

Browse files
committed
checkpoint: pre-yolo 20260329-143828
1 parent 7031310 commit cdf947b

35 files changed

Lines changed: 16035 additions & 3 deletions
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# ANTLR Full AST Migration Design
2+
3+
**Date:** 2026-03-29
4+
**Status:** Approved
5+
**Scope:** Replace all regex-based detectors with ANTLR AST parsing for 8 non-JVM languages
6+
7+
## Overview
8+
9+
Migrate all 91 regex-based detectors to ANTLR AST-based parsing. Full replacement, not hybrid. Every detector walks a parse tree instead of matching regex patterns. Fallback to regex with warning log when ANTLR parsing fails on malformed code.
10+
11+
## Why
12+
13+
- Maximum detection quality — proper scoping, type info, decorator resolution
14+
- Less boilerplate — AST walking is cleaner than regex pattern engineering
15+
- Maintainable — adding a new detector means walking a tree, not crafting fragile patterns
16+
- Future-proof — ANTLR has 200+ language grammars, adding new languages is trivial
17+
- Consistent — same pattern across all languages (JavaParser for Java, ANTLR for everything else)
18+
19+
## Tech Stack
20+
21+
- ANTLR 4.13.2 runtime + maven plugin
22+
- `.g4` grammar files from official grammars-v4 repository
23+
- Generated Java lexers/parsers/visitors at build time
24+
- ThreadLocal parser instances for virtual thread safety
25+
26+
## Languages & Grammars
27+
28+
| Language | Grammar Source | Detectors to Migrate |
29+
|---|---|---|
30+
| TypeScript/JS | grammars-v4/typescript + javascript | 14 |
31+
| Python | grammars-v4/python (Python3) | 12 |
32+
| Go | grammars-v4/golang | 4 |
33+
| C# | grammars-v4/csharp | 4 |
34+
| Rust | grammars-v4/rust | 3 |
35+
| Kotlin | grammars-v4/kotlin | 3 |
36+
| Scala | grammars-v4/scala | 2 |
37+
| C++ | grammars-v4/cpp (CPP14) | 2 |
38+
| Shell/Bash | grammars-v4/bash | 3 |
39+
| **Total** | | **47 detectors** |
40+
41+
Note: Config/infra detectors (YAML, JSON, XML, etc.) stay as AbstractStructuredDetector — they parse data structures, not programming languages. Auth detectors that scan multiple languages stay regex (they match patterns across any language). Generic imports detector stays regex.
42+
43+
## Directory Structure
44+
45+
```
46+
src/main/antlr4/io/github/randomcodespace/iq/grammar/
47+
typescript/TypeScriptLexer.g4, TypeScriptParser.g4
48+
python/Python3Lexer.g4, Python3Parser.g4
49+
golang/GoLexer.g4, GoParser.g4
50+
csharp/CSharpLexer.g4, CSharpParser.g4
51+
rust/RustLexer.g4, RustParser.g4
52+
kotlin/KotlinLexer.g4, KotlinParser.g4
53+
scala/ScalaLexer.g4, ScalaParser.g4
54+
cpp/CPP14Lexer.g4, CPP14Parser.g4
55+
bash/BashLexer.g4, BashParser.g4
56+
```
57+
58+
Generated output: `target/generated-sources/antlr4/io/github/randomcodespace/iq/grammar/`
59+
60+
## Base Class
61+
62+
```java
63+
public abstract class AbstractAntlrDetector extends AbstractRegexDetector {
64+
65+
// Template method: try ANTLR, fall back to regex with warning
66+
@Override
67+
public DetectorResult detect(DetectorContext ctx) {
68+
try {
69+
ParseTree tree = parse(ctx);
70+
if (tree != null) {
71+
return detectWithAst(tree, ctx);
72+
}
73+
} catch (Exception e) {
74+
log.warn("ANTLR parse failed for {}, falling back to regex: {}",
75+
ctx.filePath(), e.getMessage());
76+
}
77+
return detectWithRegex(ctx);
78+
}
79+
80+
protected abstract ParseTree parse(DetectorContext ctx);
81+
protected abstract DetectorResult detectWithAst(ParseTree tree, DetectorContext ctx);
82+
protected DetectorResult detectWithRegex(DetectorContext ctx) {
83+
return DetectorResult.empty(); // Override if regex fallback needed
84+
}
85+
}
86+
```
87+
88+
### Language-specific parser helpers
89+
90+
```java
91+
// Per-language helper classes for common AST operations
92+
public class TypeScriptAstHelper {
93+
private static final ThreadLocal<TypeScriptParser> PARSER = ...;
94+
95+
public static ParseTree parse(String content) { ... }
96+
public static List<ClassDecl> findClasses(ParseTree tree) { ... }
97+
public static List<FunctionDecl> findFunctions(ParseTree tree) { ... }
98+
public static List<ImportDecl> findImports(ParseTree tree) { ... }
99+
public static List<Decorator> findDecorators(ParseTree tree) { ... }
100+
}
101+
```
102+
103+
One helper per language. Detectors for that language share the helper.
104+
105+
## Detector Rewrite Pattern
106+
107+
Each detector:
108+
1. Extends `AbstractAntlrDetector`
109+
2. Implements `parse()` — delegates to language helper
110+
3. Implements `detectWithAst()` — walks the AST for framework-specific patterns
111+
4. Optionally overrides `detectWithRegex()` — existing regex logic as fallback
112+
113+
## Fallback Behavior
114+
115+
When ANTLR parse fails:
116+
1. Log warning: `"ANTLR parse failed for {file}, falling back to regex: {error}"`
117+
2. Execute regex fallback (existing logic, unchanged)
118+
3. Result from regex is returned — never lose coverage
119+
120+
This ensures we never produce fewer results than the current regex-only approach.
121+
122+
## Thread Safety
123+
124+
ANTLR parsers are NOT thread-safe. Use ThreadLocal per language:
125+
126+
```java
127+
private static final ThreadLocal<TypeScriptLexer> LEXER =
128+
ThreadLocal.withInitial(() -> new TypeScriptLexer(null));
129+
private static final ThreadLocal<TypeScriptParser> PARSER =
130+
ThreadLocal.withInitial(() -> new TypeScriptParser(null));
131+
```
132+
133+
Reset input stream per parse call. Same pattern as JavaParser ThreadLocal.
134+
135+
## Maven Configuration
136+
137+
```xml
138+
<dependency>
139+
<groupId>org.antlr</groupId>
140+
<artifactId>antlr4-runtime</artifactId>
141+
<version>4.13.2</version>
142+
</dependency>
143+
144+
<plugin>
145+
<groupId>org.antlr</groupId>
146+
<artifactId>antlr4-maven-plugin</artifactId>
147+
<version>4.13.2</version>
148+
<executions>
149+
<execution>
150+
<goals><goal>antlr4</goal></goals>
151+
</execution>
152+
</executions>
153+
<configuration>
154+
<visitor>true</visitor>
155+
<listener>true</listener>
156+
</configuration>
157+
</plugin>
158+
```
159+
160+
## Testing
161+
162+
Each migrated detector keeps existing tests plus:
163+
- **AST-specific test** — verify AST path produces correct nodes/edges
164+
- **Fallback test** — malformed code triggers regex fallback + warning logged
165+
- **Parity test** — AST results >= regex results on same input
166+
167+
## Performance
168+
169+
- ANTLR parsing: ~2-5x slower than regex per file
170+
- Total pipeline impact: ~10-20% slower analysis time
171+
- Offset by: higher quality detection, fewer false negatives
172+
- Virtual threads absorb some overhead via parallelism
173+
174+
## What Stays Unchanged
175+
176+
- Java detectors — already use JavaParser (better than ANTLR for Java)
177+
- Config detectors — use AbstractStructuredDetector (YAML/JSON/XML parsing)
178+
- Auth detectors — scan multiple languages with cross-language regex patterns
179+
- Generic imports detector — simple cross-language regex
180+
- IaC detectors — Terraform/Bicep/Dockerfile use regex (no ANTLR grammar needed)

pom.xml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@
113113
<version>3.28.0</version>
114114
</dependency>
115115

116+
<!-- ANTLR Runtime -->
117+
<dependency>
118+
<groupId>org.antlr</groupId>
119+
<artifactId>antlr4-runtime</artifactId>
120+
<version>4.13.2</version>
121+
</dependency>
122+
116123
<!-- Testing -->
117124
<dependency>
118125
<groupId>org.springframework.boot</groupId>
@@ -156,6 +163,22 @@
156163
</configuration>
157164
</plugin>
158165

166+
<plugin>
167+
<groupId>org.antlr</groupId>
168+
<artifactId>antlr4-maven-plugin</artifactId>
169+
<version>4.13.2</version>
170+
<executions>
171+
<execution>
172+
<goals><goal>antlr4</goal></goals>
173+
</execution>
174+
</executions>
175+
<configuration>
176+
<visitor>true</visitor>
177+
<listener>true</listener>
178+
<treatWarningsAsErrors>false</treatWarningsAsErrors>
179+
</configuration>
180+
</plugin>
181+
159182
<plugin>
160183
<groupId>org.apache.maven.plugins</groupId>
161184
<artifactId>maven-enforcer-plugin</artifactId>

0 commit comments

Comments
 (0)