svoid tok_swappableFunctions(LS tok) { jreplace(tok, "swappable static", "static swappable"); jreplace(tok, "pswappable ", "persistently swappable $2"); jreplace(tok, "persistent swappable ", "persistently swappable $3"); jreplace(tok, "transient swappable ", "swappable $3"); int i; while ((i = jfind_any(tok, "swappable (", "swappable <", "swappable .", "swappable [")) >= 0) { // left-scan for modifiers int iModEnd = i; bool persistently = eqGet(tok, i-2, "persistently"); if (persistently) iModEnd -= 2; int iMod = leftScanModifiers(tok, iModEnd); S modifiers = joinSubList(tok, iMod, iModEnd); // scan annotations int iAnnot = iMod; bool atOverride = subListEquals(tok, iAnnot-4, "@", "", "Override"); if (atOverride) iAnnot -= 4; // scan return type, find function name int iEndOfType = tok_findEndOfType(tok, i+2); S returnType = joinSubList(tok, i+2, iEndOfType-1); S name = assertIdentifier(tok.get(iEndOfType)); int iArgs = iEndOfType+2; assertEquals("(", get(tok, iArgs)); try { int iCurly = indexOf(tok, iEndOfType, "{"); int iArgsEnd = lastIndexOf(tok, iCurly, ")"); assertTrue(iArgsEnd >= 0); S throwsClauses = joinSubList(tok, iArgsEnd+1, iCurly-1); // TODO LS tokArgs = subList(tok, iArgs+1, iArgsEnd); LPairS args = tok_typesAndNamesOfParams(tokArgs); S args1 = join(tokArgs); S args2 = joinWithComma(pairsB(args)); bool isVoidMethod = eq(returnType, "void"); LS types = pairsA(args); if (!isVoidMethod) types.add(returnType); S typeParams = joinWithComma(map(type -> tok_varArgTypeToArray(tok_toNonPrimitiveTypes(type)), types)); // TODO: modifiers S base = name + "_base", fallback = name + "_fallback"; S mods = modifiers + (persistently || containsJavaToken(modifiers, "static") ? "" : "transient "); S mainFunctionModifiers = modifiers; S baseFunctionModifiers = modifiers; if (atOverride) mainFunctionModifiers = "@Override " + mainFunctionModifiers; S src; if (isVoidMethod) if (empty(args)) // no args, returning void src = mods + "Runnable \*name*/;\n" + "\*mainFunctionModifiers*/\*returnType*/ \*name*/(\*args1*/) { if (\*name*/ != null) \*name*/.run(); else \*base*/(\*args2*/); }\n" + "final \*modifiers*/\*returnType*/ \*fallback*/(Runnable _f, \*args1*/) { if (_f != null) _f.run(); else \*base*/(); }\n" + "\*baseFunctionModifiers*/\*returnType*/ \*base*/(\*args1*/) {"; else { // args, returning void S varType = "IVF\*l(args)*/<\*typeParams*/>"; src = "\*mods*/ \*varType*/ \*name*/;\n" + "\*mainFunctionModifiers*/\*returnType*/ \*name*/(\*args1*/) { if (\*name*/ != null) \*name*/.get(\*args2*/); else \*base*/(\*args2*/); }\n" + "final \*modifiers*/\*returnType*/ \*fallback*/(\*varType*/ _f, \*args1*/) { if (_f != null) _f.get(\*args2*/); else \*base*/(\*args2*/); }\n" + "\*baseFunctionModifiers*/\*returnType*/ \*base*/(\*args1*/) {"; } else { // zero or more args, not returning void S varType = "IF\*l(args)*/<\*typeParams*/>"; src = "\*mods*/ \*varType*/ \*name*/;\n" + "\*mainFunctionModifiers*/\*returnType*/ \*name*/(\*args1*/) { ret \*name*/ != null ? \*name*/.get(\*args2*/) : \*base*/(\*args2*/); }\n" + "final \*modifiers*/\*returnType*/ \*fallback*/(\*varType*/ _f, \*args1*/) { ret _f != null ? _f.get(\*args2*/) : \*base*/(\*args2*/); }\n" + "\*baseFunctionModifiers*/\*returnType*/ \*base*/(\*args1*/) {"; } replaceTokens_reTok(tok, iAnnot, iCurly+1, src); } catch e { fail("Was processing function " + name, e); } } }