@@ -128,6 +128,15 @@ private List<String> uniqueMatches(String output, String regex, int group) {
128128 return result ;
129129 }
130130
131+ private int countMatches (String output , String regex ) {
132+ Matcher matcher = Pattern .compile (regex ).matcher (output );
133+ int result = 0 ;
134+ while (matcher .find ()) {
135+ result ++;
136+ }
137+ return result ;
138+ }
139+
131140 private String singleMatch (String output , String regex , int group ) {
132141 Matcher matcher = Pattern .compile (regex ).matcher (output );
133142 assertTrue ("Expected pattern to occur: " + regex , matcher .find ());
@@ -173,6 +182,11 @@ private String compileLuaWithRunArgs(String testName, boolean withStdLib, String
173182
174183 private String compileLuaWithCUs (String testName , boolean withStdLib , List <CU > extraCUs , String ... lines ) {
175184 RunArgs runArgs = new RunArgs ().with ("-lua" , "-inline" , "-localOptimizations" , "-stacktraces" );
185+ return compileLuaWithCUs (testName , withStdLib , extraCUs , runArgs , lines );
186+ }
187+
188+ private String compileLuaWithCUs (String testName , boolean withStdLib , List <CU > extraCUs ,
189+ RunArgs runArgs , String ... lines ) {
176190 WurstGui gui = new WurstGuiCliImpl ();
177191 WurstCompilerJassImpl compiler = new WurstCompilerJassImpl (null , gui , null , runArgs );
178192 List <CU > inputs = new ArrayList <>();
@@ -2475,12 +2489,72 @@ public void luaFunctionRefWrapperForwardsVarargs() throws IOException {
24752489 " ForForce(f, () -> skip)"
24762490 );
24772491 String compiled = Files .toString (new File ("test-output/lua/LuaTranslationTests_luaFunctionRefWrapperForwardsVarargs.lua" ), Charsets .UTF_8 );
2478- assertTrue (compiled .contains ("xpcall(function (...)" ));
2492+ assertContainsRegex (compiled , "function\\ s+__wurst_callback_[A-Za-z0-9_]+\\ (\\ .\\ .\\ .\\ )" );
2493+ assertFalse (compiled .contains ("xpcall(function (...)" ));
2494+ assertContainsRegex (compiled ,
2495+ "xpcall\\ ([A-Za-z0-9_]+, __wurst_callback_error[A-Za-z0-9_]*, \\ .\\ .\\ .\\ )" );
24792496 assertTrue (compiled .contains (", ...)" ));
24802497 assertFalse (compiled .contains ("local temp = ..." ));
24812498 assertFalse (compiled .contains ("ForForce(f, function (...) \n \t \t \t local tempRes" ));
24822499 }
24832500
2501+ @ Test
2502+ public void luaFunctionRefsReuseOneAdapterAndPreserveSingleReturn () {
2503+ String compiled = compileLuaWithCUs (
2504+ "LuaTranslationTests_luaFunctionRefsReuseOneAdapterAndPreserveSingleReturn" ,
2505+ false ,
2506+ Collections .emptyList (),
2507+ new RunArgs ().with ("-lua" , "-inline" , "-localOptimizations" ),
2508+ "type boolexpr extends handle" ,
2509+ "package Test" ,
2510+ "@extern native Condition(code callback) returns boolexpr" ,
2511+ "function predicate() returns boolean" ,
2512+ " return true" ,
2513+ "init" ,
2514+ " let first = Condition(function predicate)" ,
2515+ " let second = Condition(function predicate)"
2516+ );
2517+
2518+ List <String > adapters = uniqueMatches (compiled ,
2519+ "function\\ s+(__wurst_callback_predicate[A-Za-z0-9_]*)\\ (\\ .\\ .\\ .\\ )" , 1 );
2520+ assertEquals ("one adapter must serve every reference to the same function:\n " + compiled ,
2521+ 1 , adapters .size ());
2522+ String adapter = adapters .get (0 );
2523+ assertEquals ("both Condition calls must reference the cached adapter" , 2 ,
2524+ countMatches (compiled , "Condition\\ (" + Pattern .quote (adapter ) + "\\ )" ));
2525+ String adapterBody = getFunctionBody (compiled , adapter );
2526+ assertTrue (adapterBody .contains ("_, result = xpcall(predicate," ));
2527+ assertTrue (adapterBody .contains ("return result" ));
2528+ assertFalse ("callback sites must not allocate anonymous wrappers" , compiled .contains ("Condition(function (" ));
2529+ }
2530+
2531+ @ Test
2532+ public void luaFunctionRefAdapterTracksLateClassFunctionRename () {
2533+ String compiled = compileLuaWithCUs (
2534+ "LuaTranslationTests_luaFunctionRefAdapterTracksLateClassFunctionRename" ,
2535+ false ,
2536+ Collections .emptyList (),
2537+ new RunArgs ().with ("-lua" ),
2538+ "package Test" ,
2539+ "@extern native consume(code callback)" ,
2540+ "@extern native CallbackOwner_staticCallback()" ,
2541+ "class CallbackOwner" ,
2542+ " function start()" ,
2543+ " consume(function staticCallback)" ,
2544+ " private static function staticCallback()" ,
2545+ " consume(function staticCallback)" ,
2546+ "init" ,
2547+ " CallbackOwner_staticCallback()" ,
2548+ " new CallbackOwner().start()"
2549+ );
2550+
2551+ String callbackName = singleMatch (compiled ,
2552+ "function\\ s+(CallbackOwner_[A-Za-z0-9_]*staticCallback[A-Za-z0-9_]*)\\ (\\ )" , 1 );
2553+ assertTrue ("adapter must track the class callback's final name:\n " + compiled ,
2554+ compiled .contains ("xpcall(" + callbackName + "," ));
2555+ assertFalse (compiled .contains ("xpcall(staticCallback," ));
2556+ }
2557+
24842558 @ Test
24852559 public void luaFunctionRefStacktraceHandlerUsesWurstStackPosition () throws IOException {
24862560 CU errorHandling = new CU ("ErrorHandling.wurst" , String .join ("\n " ,
0 commit comments