Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ public class DictionaryManager {

private static boolean initialized;

static {
// Trigger the default dictionary load (built-in classpath resources only, via the
// no-arg DictionaryPreferences defaults - no environment/filesystem dependence) as part
// of class initialization, not just on first explicit call. This lets AOT tooling (e.g.
// GraalVM native-image's --initialize-at-build-time) bake the parsed dictionaries into
// the build-time heap snapshot instead of re-parsing them on every process start.
// initDictionaries() is otherwise unchanged and remains safe/idempotent to call directly.
initDictionaries();
}

private DictionaryManager(DictionaryPreferences prefs) {
fPrefs = prefs;
init();
Expand Down
19 changes: 17 additions & 2 deletions cfml.parsing/src/main/java/cfml/parsing/CFMLParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,16 @@ public class CFMLParser {
CFScriptStatementVisitor scriptVisitor = new CFScriptStatementVisitor();
CFSCRIPTLexer lexer = null;
CFSCRIPTParser parser = null;


// Callers (e.g. CFLint scanning a file's <cfset>/<cfif> tags one at a time) frequently
// re-parse textually-identical short expressions many times over - common boilerplate like
// "var result = StructNew()" can repeat dozens of times in one file. Cache the parse tree by
// source text and re-run the (cheap) visitor on a hit, skipping the expensive lex/parse/ATN
// simulation. We deliberately do NOT cache/share the resulting CFExpression itself - it has
// mutable state (CFParsedStatement.setParent()) that callers rely on per-use, so every hit
// gets a fresh visit() over the cached (read-only) parse tree instead.
private final Map<String, CfmlExpressionContext> exprTreeCache = new HashMap<>();

public void clearDFA() {
if (parser != null)
parser.getInterpreter().clearDFA();
Expand Down Expand Up @@ -124,7 +133,12 @@ public CFExpression parseCFMLExpression(String _infix, ANTLRErrorListener errorR
if (errorReporter == null) {
errorReporter = this.errorReporter;
}


final CfmlExpressionContext cachedTree = exprTreeCache.get(_infix);
if (cachedTree != null) {
return expressionVisitor.visit(cachedTree);
}

final CharStream input = CharStreams.fromString(_infix);
if (lexer == null) {
lexer = new CFSCRIPTLexer(input);
Expand Down Expand Up @@ -170,6 +184,7 @@ public CFExpression parseCFMLExpression(String _infix, ANTLRErrorListener errorR
}
}
if (expressionContext != null) {
exprTreeCache.put(_infix, expressionContext);
return expressionVisitor.visit(expressionContext);
} else
return null;
Expand Down
Loading