You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add Context.prefix — a String field, default "" — that the expression compiler prepends to every generated class name when non-empty.
Opt-in, per-test. A test that's hard to debug because the decompiled output in compiled/<className>.java gets overwritten by some other test compiling a class with the same name sets context.prefix = "myTest_" on its own Context before compiling expressions. Its decompiled artifacts land at compiled/myTest_F.java, compiled/myTest_operandF0001.java, compiled/myTest_a.java, etc., surviving any later test that compiles a plain F, operandF0001, or a.
Every other test runs unchanged. Production paths run unchanged. Nothing systematic. Used only when a specific test acts up.
Implementation
Context.java
Add the field next to the other simple public configuration fields (near saveClasses):
/** * Prefix prepended to every generated class name when this Context compiles * an Expression. Default empty string — no effect, behavior identical to * never having touched this field. * * <p>Used on a per-test basis when a test's decompiled output in * {@code compiled/<className>.java} keeps getting overwritten by another * test compiling a class with the same simple name. A problematic test * sets this on its own Context before compilation, and its generated * classes get unique file names that survive subsequent test runs. */publicStringprefix = "";
Expression.java
In the one site that finalizes this.className before it gets used for ClassWriter, descriptor formatting, registration keys, and the ExpressionClassLoader's decompiled-source write path, prepend context.prefix:
Applied early enough that every downstream consumer of className sees the prefixed string. Sites that build "L" + className + ";" descriptors, sites that GETFIELD/PUTFIELD with className as the owner, the ExpressionClassLoader's findClass lookup, compiled/<className>.java file writing — all consume className after this point and don't need to know about the prefix.
Same prefix applied uniformly within one Context means every string that has to match another string within the test still matches.
Class-name strings are longer when prefix is set. Trace-log lines for that test get longer. Cosmetic.
The prefix has to be a legal Java identifier prefix. No spaces, no slashes, no dots. The compiler does not validate this — if the user supplies garbage, the bytecode emit fails loudly at class-load time. Not worth defensive checking for a debug-only knob.
Two tests setting the same prefix on different Contexts will collide. Same way two tests not setting any prefix collide today. Use a unique prefix per problematic test; that's the whole point.
Production behavior unchanged. Field defaults to empty string, expression compiler prepends nothing, every code path is byte-identical to today when the field is left alone.
Out of scope
Systematic per-test prefixing across the entire suite. Not doing this. The capability exists for individual problematic tests.
JUnit TestWatcher integration, thread-locals, automatic derivation from test name. None of that. Test sets the field directly on its own Context.
Package-based isolation, decompiled-output subdirectories, FQN handling. None of that.
Files touched
src/main/java/arb/expressions/Context.java — one field, one javadoc block.
src/main/java/arb/expressions/Expression.java — one line at the className-finalization site.
Two lines of code change. No tests required — used only when a test needs it, and at that point the test itself exercises the capability.
Proposal
Add
Context.prefix— aStringfield, default""— that the expression compiler prepends to every generated class name when non-empty.Opt-in, per-test. A test that's hard to debug because the decompiled output in
compiled/<className>.javagets overwritten by some other test compiling a class with the same name setscontext.prefix = "myTest_"on its own Context before compiling expressions. Its decompiled artifacts land atcompiled/myTest_F.java,compiled/myTest_operandF0001.java,compiled/myTest_a.java, etc., surviving any later test that compiles a plainF,operandF0001, ora.Every other test runs unchanged. Production paths run unchanged. Nothing systematic. Used only when a specific test acts up.
Implementation
Context.javaAdd the field next to the other simple public configuration fields (near
saveClasses):Expression.javaIn the one site that finalizes
this.classNamebefore it gets used for ClassWriter, descriptor formatting, registration keys, and the ExpressionClassLoader's decompiled-source write path, prependcontext.prefix:Applied early enough that every downstream consumer of
classNamesees the prefixed string. Sites that build"L" + className + ";"descriptors, sites that GETFIELD/PUTFIELD withclassNameas the owner, the ExpressionClassLoader'sfindClasslookup,compiled/<className>.javafile writing — all consumeclassNameafter this point and don't need to know about the prefix.Same prefix applied uniformly within one Context means every string that has to match another string within the test still matches.
Use
A problematic test:
That's it.
Ramifications
Class-name strings are longer when prefix is set. Trace-log lines for that test get longer. Cosmetic.
The prefix has to be a legal Java identifier prefix. No spaces, no slashes, no dots. The compiler does not validate this — if the user supplies garbage, the bytecode emit fails loudly at class-load time. Not worth defensive checking for a debug-only knob.
Two tests setting the same prefix on different Contexts will collide. Same way two tests not setting any prefix collide today. Use a unique prefix per problematic test; that's the whole point.
No effect on the function-mapping cache invariant (issue Decouple operand-class-name allocation from intermediate-variable field-name counter in NAryOperationNode #1019's tripwire). The prefix is applied uniformly to every class name within a single Context, so
operandClassNameand the parent's field-name string still share a counter-derived suffix and remain identity-equal as strings within the test. The cache continues to work as today.Production behavior unchanged. Field defaults to empty string, expression compiler prepends nothing, every code path is byte-identical to today when the field is left alone.
Out of scope
Files touched
src/main/java/arb/expressions/Context.java— one field, one javadoc block.src/main/java/arb/expressions/Expression.java— one line at the className-finalization site.Two lines of code change. No tests required — used only when a test needs it, and at that point the test itself exercises the capability.