import java.util.*; import java.util.zip.*; import java.util.List; import java.util.regex.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; import java.util.concurrent.locks.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.text.*; import javax.swing.table.*; import java.io.*; import java.net.*; import java.lang.reflect.*; import java.lang.ref.*; import java.lang.management.*; import java.security.*; import java.security.spec.*; import java.awt.*; import java.awt.event.*; import java.awt.image.*; import javax.imageio.*; import java.math.*; // We don't use #1006722 anymore // (but it's still listed in #7!?) // TODO: deprecate (remove) the "f <id>" syntax // TODO: skip ifclass blocks in findFunctionInvocations. // after main loop completes (including standard functions+ // classes), run tok_ifclass and if any change, run main loop // again. // This will allow clean handling of functions like "unnull" // which right now _always_ include Symbol (because unnull // references emptySymbol inside an ifclass Symbol block). // Note: Before editing this, transpile #7 // Use 'Very fresh' (R-transpile doesn't seem to work) or Q/M if you haven't screwed yourself currently // by making your transpiler unable to transpile itself... or // something // Note: Don't try hijackPrint, it doesn't seem to work in here // (because of the way it is called by e.g. transpileForServer_returnPair?) /* functions to possibly edit when creating/changing JavaX constructs: tok_pingify */ // new JavaParser includes import com.github.javaparser.*; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.*; import com.github.javaparser.ast.visitor.*; import com.github.javaparser.Problem; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.EnumDeclaration; import com.github.javaparser.ast.stmt.LocalClassDeclarationStmt; import com.github.javaparser.printer.*; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.text.NumberFormat; import java.nio.charset.Charset; import javax.imageio.metadata.*; import javax.imageio.stream.*; import static x30_pkg.x30_util.DynamicObject; import java.nio.file.Files; import java.nio.file.Path; class main { // JavaParser static CompilationUnit javaParseCompilationUnit(String java) { return javaParseCompilationUnit(java, false); } static CompilationUnit javaParseCompilationUnit(String java, boolean withComments) { JavaParser p = new JavaParser(); p.getParserConfiguration().setAttributeComments(withComments); ParseResult<CompilationUnit> r = p.parse(java); if (!r.isSuccessful()) throw fail(str(r)); return r.getResult().get(); } static String javaParser_makeAllPublic(String src, Object... __) { CompilationUnit cu = javaParseCompilationUnit(src); PrettyPrinterConfiguration ppconf = new PrettyPrinterConfiguration(); ppconf.setIndentSize(2); ppconf.setIndentType(PrettyPrinterConfiguration.IndentType.SPACES); ppconf.setPrintComments(false); javaParser_makeAllPublic_Visitor visitor = new javaParser_makeAllPublic_Visitor(); visitor.notTopLevelClassDecl = boolOptPar("notTopLevelClassDecl", __); visitor.visit(cu, null); return cu.toString(ppconf); } static class javaParser_makeAllPublic_Visitor extends VoidVisitorAdapter { boolean notTopLevelClassDecl = false; // don't make top-level class declaration public void makePublic(NodeList<com.github.javaparser.ast.Modifier> modifiers) { // XXX: does this work? modifiers.remove(com.github.javaparser.ast.Modifier.privateModifier()); modifiers.remove(com.github.javaparser.ast.Modifier.protectedModifier()); if (!modifiers.contains(com.github.javaparser.ast.Modifier.publicModifier())) modifiers.add(com.github.javaparser.ast.Modifier.publicModifier()); } public void visit(ClassOrInterfaceDeclaration n, Object arg) { Node parent = n.getParentNode().get(); if (!(parent instanceof LocalClassDeclarationStmt || parent instanceof CompilationUnit && neq(n.getName().asString(), "main"))) if (notTopLevelClassDecl) notTopLevelClassDecl = false; else makePublic(n.getModifiers()); super.visit(n, arg); } public void visit(FieldDeclaration n, Object arg) { makePublic(n.getModifiers()); super.visit(n, arg); } public void visit(ConstructorDeclaration n, Object arg) { Node parent = n.getParentNode().get(); if (!(parent instanceof EnumDeclaration)) makePublic(n.getModifiers()); super.visit(n, arg); } public void visit(MethodDeclaration n, Object arg) { NodeList<com.github.javaparser.ast.Modifier> m = n.getModifiers(); //print("Method found: " + n.getName() + " with modifiers: " + m + ", position: " + n.getRange()->begin); if (m.contains(com.github.javaparser.ast.Modifier.privateModifier()) && !m.contains(com.github.javaparser.ast.Modifier.staticModifier()) && !m.contains(com.github.javaparser.ast.Modifier.finalModifier())) m.add(com.github.javaparser.ast.Modifier.finalModifier()); makePublic(m); super.visit(n, arg); } } static String javaParser_reparse_keepComments(String src) { CompilationUnit cu = javaParseCompilationUnit(src, true); PrettyPrinterConfiguration ppconf = new PrettyPrinterConfiguration(); ppconf.setPrintComments(true); ppconf.setIndentSize(2); ppconf.setIndentType(PrettyPrinterConfiguration.IndentType.SPACES); return cu.toString(ppconf); } static String javaParser_makeAllPublic_keepComments(String src) { CompilationUnit cu = javaParseCompilationUnit(src); PrettyPrinterConfiguration ppconf = new PrettyPrinterConfiguration(); ppconf.setPrintComments(true); ppconf.setIndentSize(2); ppconf.setIndentType(PrettyPrinterConfiguration.IndentType.SPACES); new javaParser_makeAllPublic_Visitor().visit(cu, null); return cu.toString(ppconf); } static int findCodeTokens(List<String> tok, String... tokens) { return findCodeTokens(tok, 1, false, tokens); } static int findCodeTokens(List<String> tok, boolean ignoreCase, String... tokens) { return findCodeTokens(tok, 1, ignoreCase, tokens); } static int findCodeTokens(List<String> tok, int startIdx, boolean ignoreCase, String... tokens) { return findCodeTokens(tok, startIdx, ignoreCase, tokens, null); } static HashSet<String> findCodeTokens_specials = lithashset("*", "<quoted>", "<id>", "<int>", "\\*"); static int findCodeTokens_bails, findCodeTokens_nonbails; static interface findCodeTokens_Matcher { boolean get(String token); } static int findCodeTokens(List<String> tok, int startIdx, boolean ignoreCase, String[] tokens, Object condition) { int end = tok.size()-tokens.length*2+2, nTokens = tokens.length; int i = startIdx | 1; findCodeTokens_Matcher[] matchers = new findCodeTokens_Matcher[nTokens]; IContentsIndexedList2 indexedList = tok instanceof IContentsIndexedList2 ? (IContentsIndexedList2) tok : null; TreeSet<HasIndex> indices = null; int indicesOfs = 0; for (int j = 0; j < nTokens; j++) { String p = tokens[j]; findCodeTokens_Matcher matcher; if (p.equals("*")) matcher = t -> true; else if (p.equals("<quoted>")) matcher = t -> isQuoted(t); else if (p.equals("<id>")) matcher = t -> isIdentifier(t); else if (p.equals("<int>")) matcher = t -> isInteger(t); else if (p.equals("\\*")) matcher = t -> t.equals("*"); else if (ignoreCase) matcher = t -> eqic(p, t); else { matcher = t -> t.equals(p); if (indexedList != null) { TreeSet<HasIndex> indices2 = indexedList.indicesOf_treeSetOfHasIndex(p); if (indices2 == null) return -1; if (indices == null || indices2.size() < indices.size()) { // found shorter list indices = indices2; indicesOfs = j; } } } matchers[j] = matcher; } // go over shortest index if (indices != null) { int min = i+indicesOfs*2; SortedSet<HasIndex> tailSet = min == 1 ? indices : indices.tailSet(new HasIndex(min)); outer: for (HasIndex h : tailSet) { int idx = h.idx-indicesOfs*2; if (idx >= end) break; for (int j = 0; j < nTokens; j++) try { if (!matchers[j].get(tok.get(idx+j*2))) continue outer; } catch (IndexOutOfBoundsException e) { print("fct indicesOfs=" + indicesOfs + ", h=" + h + ", idx=" + idx); throw e; } if (condition == null || checkTokCondition(condition, tok, idx-1)) return idx; } return -1; } outer: for (; i < end; i += 2) { for (int j = 0; j < nTokens; j++) if (!matchers[j].get(tok.get(i+j*2))) continue outer; if (condition == null || checkTokCondition(condition, tok, i-1)) // pass N index return i; } return -1; } static boolean autoQuine = true; static int maxQuineLength = 80; static boolean assumeTriple = true; static boolean quickInstanceOfEnabled = false; // interferes with things static boolean debug_jreplace = false; // _registerThread usually costs nothing because we need // the registerWeakHashMap mechanism anyway for ping(). // Anyway - no forced functions for now :) static List<String> functionsToAlwaysInclude = ll( //"_registerThread", //"asRuntimeException" ); // classes with two type parameters that can written with just one // e.g. Pair<S> => Pair<S, S> static Set<String> pairClasses = lithashset("Pair", "Either", "Map", "AbstractMap", "HashMap", "TreeMap", "LinkedHashMap", "MultiMap", "CompactHashMap", "WrappedMap", "F1", "IF1", "AllOnAll", "AllOnAllWithUpdates", "MultiSetMap", "AutoMap", "ValueOnDemandMap", "NavigableMap", "SortedMap"); // classes with 3 type parameters that can written with just one // e.g. T3<S> => T3<S, S, S> static Set<String> tripleClasses = lithashset("T3", "IF2", "F2", "IVF3", "VF3"); static String transpilingSnippetID; //static new AtomicInteger varCount; static ThreadLocal<AtomicInteger> varCountByThread = new ThreadLocal(); static Map<String, String> snippetCache = syncMap(); static boolean useIndexedList2 = false, useTokenIndexedList = true; static boolean opt_javaTok = true; static boolean cacheStdFunctions = true, cacheStdClasses = true; static HashMap<Long, CachedInclude> cachedIncludes = new HashMap(); static ExecutorService executor; static List lclasses; static long startTime, lastPrint; // These variables have to be cleared manually for each transpilation static HashSet<Long> included = new HashSet(); static NavigableSet<String> definitions = ciSet(); static HashMap<String, String> rewrites = new HashMap(); static HashSet<String> shouldNotIncludeFunction = new HashSet(); // this verifies after the fact that the function was not included static HashSet<String> shouldNotIncludeClass = new HashSet(); static HashSet<String> doNotIncludeFunction = new HashSet(); // this actually prevents the function from being included static Map<String, String> functionToPackage = new HashMap(); static HashSet<String> doNotIncludeClass = new HashSet(); static HashSet<String> needLatest = new HashSet(); // this forces a function to be included static HashSet<String> addedFunctions = new HashSet(); static HashSet<String> addedClasses = new HashSet(); static HashSet<String> hardFunctionReferences = new HashSet(); static HashSet<String> mapLikeFunctions = new HashSet(); static HashSet<String> lambdaMapLikeFunctions = new HashSet(); static HashSet<String> curry1LikeFunctions = new HashSet(); static HashSet<String> mapMethodLikeFunctions = new HashSet(); static HashSet<String> nuLikeFunctions = new HashSet(); static HashSet<String> getLikeFunctions = new HashSet(); // name is slightly misleading. this turns a pre-argument into a fieldLambda static HashSet<String> lambdaMethod0LikeFunctions = new HashSet(); // we're getting better again with the names (maybe) static HashSet<String> lambda0LikeFunctions = new HashSet(); static Map<String, String> extraStandardFunctions; static boolean quickmainDone1, quickmainDone2; static TreeSet<String> libs = new TreeSet(); static String mainBaseClass, mainPackage, mainClassName; static boolean localStuffOnly = false; // for transpiling a fragment static boolean asInclude = false; // for transpiling an include (auto-close scopes, enable all standard class ifclass [todo]) static boolean allowMetaCode = false; // run any embedded meta code static List<String> metaPostBlocks, metaTransformers; static boolean dontPrintSource = false; static boolean dontLoadCachedIncludesFromVM = false; // for benchmarking static HashSet<String> haveClasses = new HashSet(); static class CachedInclude { String javax; Future<String> java; String realJava; long snippetID; CachedInclude() {} CachedInclude(long snippetID) { this.snippetID = snippetID;} String java() { return realJava != null ? realJava : getFuture(java); } Future<String> javaFuture() { return realJava != null ? nowFuture(realJava) : java; } void clean() { if (java != null) { realJava = getFuture(java); java = null; } } } public static void main(final String[] args) throws Exception { startTime = lastPrint = sysNow(); try { if (!dontLoadCachedIncludesFromVM) vmKeepWithProgramMD5_get("cachedIncludes"); } catch (Throwable __e) { _handleException(__e); } executor = Executors.newFixedThreadPool(numberOfCores()); transpilingSnippetID = or(getThreadLocal((ThreadLocal<String>) getOpt(javax(), "transpilingSnippetID")), transpilingSnippetID); //print(+transpilingSnippetID); transpileRaw_dontCopyFromCreator = true; final Object oldPrint = or(print_byThread().get(), "print_raw"); AutoCloseable __17 = tempInterceptPrint(new F1<String, Boolean>() { Boolean get(String s) { long now = sysNow(); long time = now-lastPrint; // -startTime; lastPrint = now; callF(oldPrint, "[" + formatInt(time/1000, 2) + ":" + formatInt(time % 1000, 3) + "] " + s); return false; } }); try { try { _main(); } finally { interceptPrintInThisThread(oldPrint); if (executor != null) executor.shutdown(); executor = null; localStuffOnly = false; asInclude = false; } } finally { _close(__17); }} static void _main() { try { if (sameSnippetID(programID(), defaultJavaXTranslatorID())) setDefaultJavaXTranslatorID("#7"); //reTok_modify_check = true; //if (useIndexedList) findCodeTokens_debug = true; javaTok_opt = opt_javaTok; //findCodeTokens_indexed = findCodeTokens_unindexed = 0; findCodeTokens_bails = findCodeTokens_nonbails = 0; javaTok_n = javaTok_elements = 0; String in = loadMainJava(); print("759 STARTING " + identityHashCode(main.class)); // clear things includeInMainLoaded_magicComment = null; included.clear(); definitions.clear(); rewrites.clear(); // XXX definitions.add("SymbolAsString"); shouldNotIncludeFunction.clear(); shouldNotIncludeClass.clear(); doNotIncludeFunction.clear(); functionToPackage.clear(); needLatest.clear(); doNotIncludeClass.clear(); addedFunctions.clear(); addedClasses.clear(); hardFunctionReferences.clear(); mapLikeFunctions = cloneHashSet(tok_mapLikeFunctions()); lambdaMapLikeFunctions = new HashSet(); curry1LikeFunctions = new HashSet(); mapMethodLikeFunctions = cloneHashSet(tok_mapMethodLikeFunctions()); nuLikeFunctions.clear(); getLikeFunctions.clear(); lambdaMethod0LikeFunctions.clear(); lambda0LikeFunctions.clear(); extraStandardFunctions = new HashMap(); libs.clear(); mainBaseClass = mainPackage = mainClassName = null; varCountByThread.set(null); quickmainDone1 = quickmainDone2 = false; metaPostBlocks = new ArrayList(); metaTransformers = new ArrayList(); dontPrintSource = false; defaultMaxQuineLength_value = defaultMaxQuineLength_defaultValue; debug_jreplace = false; haveClasses.clear(); //L ts = findTranslators(toLines(join(tok))); //print("Translators in source at start: " + structure(ts)); List<String> tok = jtok(in); try { tok_definitions(tok); // add m { } if (!localStuffOnly && !hasCodeTokens(tok, "m", "{") && !hasCodeTokens(tok, "main", "{") && !hasCodeTokens(tok, "class", "main")) { if (l(tok) == 1) tok = singlePlusList(first(tok), dropFirst(javaTok("m {}"))); else { replaceTokens_reTok(tok, 1, 2, "m {\n\n" + unnull(get(tok, 1))); replaceTokens_reTok(tok, l(tok)-2, l(tok)-1, unnull(get(tok, l(tok)-2)) + "}"); } tok_moveImportsUp(tok); } // standard translate //ts = findTranslators(toLines(join(tok))); //print("Translators in source: " + structure(ts)); if (tok_hasTranslators(tok)) tok = jtok(defaultTranslate(join(tok))); //print("end of default translate"); //print(join(tok)); //tok_autoCloseBrackets(tok); tok_metaTransformNow(tok); tok_processEarlyIncludes(tok); tok_earlyGeneralStuff(tok); tok = tok_processIncludes(tok); // before standard functions if (processConceptsDot(tok)) tok = tok_processIncludes(tok); tok = localStuff1(tok); if (!localStuffOnly) { int safety = 0; boolean same = false; do { // BIG LOOP ping(); List<String> before = cloneList(tok); // do the non-local stuff (flags and rewrites, things that correlate across includes like tok_selfType) // to allow crazy stuff like "nonStatic !include #someStaticClass" tok_processEarlyIncludes(tok); jreplace(tok, "nonStatic static", ""); tok_selfType(tok); tok_mainClassNameAndPackage(tok); tok_definitions(tok); tok_ifndef(tok); tok_ifdef(tok); defineMapLikes(tok); defineLambdaMapLikes(tok); defineCurry1Likes(tok); defineMapMethodLikes(tok); defineNuLikes(tok); defineXLikes(tok, "getLike", getLikeFunctions); defineXLikes(tok, "lambdaMethod0Like", lambdaMethod0LikeFunctions); defineXLikes(tok, "lambda0Like", lambda0LikeFunctions); if (tok_applyAllXLikeFunctions(tok)) { functionReferences(tok); lambdaReferences(tok); } tok_dropExtraCommas(tok); // from e.g. tok_applyMapMethodLikeFunctions tok_delegateTo(tok); tok_replaceWith(tok); tok_findAndClearRewrites(tok); tok_processRewrites(tok); tok_multiTypeArguments_v2(tok); // main bla(...) => mainClassName.bla(...) // or main ClassName => main.ClassName //jreplace(tok, "main <id>(", mainClassName() + ".$2("); grabImportedStaticFunctions(tok); jreplace_dyn_allowNull(tok, "main <id>", (_tok, cIdx, end) -> { String fname = _tok.get(cIdx+2); boolean isClass = haveClasses.contains(fname); printVars("expandMainRef", "fname", fname, "isClass", isClass); if (isClass || eqGet(_tok, cIdx+4, "(")) { String pkg = functionToPackage.get(fname); printVars("expandMainRef", "pkg", pkg); String call = "." + fname; return or(pkg, mainClassName()) + call; } return null; }); try { if (safety == 0) tok = quickmain(tok); } catch (Throwable e) { printSources(tok); rethrow(e); } tok_collectMetaPostBlocks(tok, metaPostBlocks); tok_collectTransformers(tok, metaTransformers); tok_metaTransformNow(tok); // Hack to allow DynModule to reimplement _registerThread /*if (tok.contains("DynModule") && !addedClasses.contains("DynModule")) addStandardClasses_v2(tok);*/ defineExtraSF(tok); tok = standardFunctions(tok); tok = stdstuff(tok); // all the keywords, standard String diff; long startTime = now(); //diff = unidiff(before, join(tok)); //print("unidiff: " + (now()-startTime) + " ms"); //same = eq(diff, ""); same = eq(tok, before); if (!same) { print("Not same " + safety + "."); //print(indent(2, diff)); } if (safety++ >= 10) { //print(unidiff(before, join(tok))); printSources(tok); throw fail("safety 10 error!"); } } while (!same); // END OF BIG LOOP print("Post."); if (mainBaseClass != null) { jreplace1(tok, "class main", "class main extends " + mainBaseClass); mainBaseClass = null; } print("moveImportsUp"); tok_moveImportsUp(tok); print("Indexing"); tok = indexTokenList(tok); // POST-PROCESSING after stdstuff loop if (transpilingSnippetID != null) jreplace_dyn(tok, "class whatever", new F2<List<String>, Integer, String>() { public String get(List<String> tok, Integer cIndex) { try { try { return "class " + stringToLegalIdentifier(getSnippetTitle(transpilingSnippetID)); } catch (Throwable __e) { _handleException(__e); } return "class Whatever"; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "pcall { ret \"class \" + stringToLegalIdentifier(getSnippetTitle(transpilingSni..."; }}); //print("Type<A, A>"); // Type<A> to Type<A, A> print("extendClasses"); tok = extendClasses(tok); print("libs"); libs(tok); print("sourceCodeLine"); sourceCodeLine(tok); tok_overridableFunctionDefs(tok, null); // escaping for lambdas //jreplace(tok, "-=>", "->"); // Stuff that depends on the list of inner classes (haveClasses) haveClasses = haveClasses_actual(tok); print("innerClassesVar"); innerClassesVar(tok, haveClasses); fillVar_transpilationDate(tok); haveClasses_addImported(tok, haveClasses); print("ifclass"); tok_ifclass(tok, haveClasses); print("slashCasts"); slashCasts(tok, haveClasses); print("newWithoutNew"); newWithoutNew(tok, haveClasses); if (!assumeTriple) { print("Triple"); if (tok.contains("Triple") && !haveClasses.contains("Triple")) { jreplace(tok, "Triple", "T3"); haveClasses.remove("Triple"); haveClasses.add("T3"); slashCasts(tok, lithashset("T3")); tok_quickInstanceOf(tok, lithashset("T3")); } } if (hasDef("SymbolAsString")) jreplace(tok, "Symbol", "String"); // using non-lazy version now for cleanImports print("classReferences"); expandClassReferences/*_lazy*/(tok, haveClasses); if (metaCodeAllowed()) runMetaPostBlocks(tok); // Error-checking print("Error-checking"); Set<String> functions = new HashSet(findFunctions(tok)); for (String f : hardFunctionReferences) if (!functions.contains(f)) throw fail("Function " + f + " requested, but not supplied"); print("autoImports"); tok = autoImports(tok); // faster to do it at the end if (hasDef("cleanImports")) tok_cleanImports(tok); if (includeInMainLoaded_magicComment != null) { int i = lastIndexOfStartingWith(tok, includeInMainLoaded_magicComment); if (i >= 0) tok.set(i, dropPrefix(includeInMainLoaded_magicComment, tok.get(i))); } print("definitions=" + sfu(definitions)); if (containsOneOf(definitions, "allpublic", "reparse", "PublicExceptTopClass")) { // Fire up the Java parser & pretty printer! print(containsIC(definitions, "allpublic")? "Making all public." : "Reparsing."); //try { String src = join(tok); try { if (containsIC(definitions, "allpublic")) src = javaParser_makeAllPublic(src); else if (containsIC(definitions, "PublicExceptTopClass")) src = javaParser_makeAllPublic(src, "notTopLevelClassDecl" , true); else if (containsIC(definitions, "keepComments")) src = javaParser_makeAllPublic_keepComments(src); else { print("javaParser_reparse_keepComments. size=" + l(src)); src = javaParser_reparse_keepComments(src); print("size=" + l(src)); } } catch (Throwable e) { String _src = src; String errorContext = extractAndPrintJavaParseError(_src, e); File f = transpilerErrorSourceFile(); saveTextFileVerbose(f, src); dontPrintSource = true; throw fail("Java parsing error:" + errorContext + innerMessage(e)); // drop the long nested parser stacktraces } tok = jtok(src); /*} catch e { S src = join(tok); if (!dontPrintSource) print(src); print(f2s(saveProgramTextFile("error.java", src))); throw rethrow(e); }*/ } // Do this after JavaParser (because it doesn't like package after class) if (mainPackage != null) { print("mainPackage"); tokPrepend(tok, 1, "package " + mainPackage + ";\n"); reTok(tok, 1, 2); } if (mainClassName != null) { print("mainClassName"); jreplace(tok, "class main", "class " + mainClassName); jreplace(tok, "main.class", mainClassName + ".class"); //tokPrepend(tok, 1, "class main {}\n"); // so main.class is generated and compiler sanity checks succeed. we can later skip it in the JavaXClassLoader } if (nempty(libs)) { print("Adding libs: " + libs); tok.add(concatMap_strings(new F1<String, String>() { public String get(String s) { try { return "\n!" + s; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "\"\\n!\" + s"; }}, libs)); } } // if (!localStuffOnly) } catch (Throwable e) { if (!dontPrintSource) printSources(tok); String src = join(tok); print(f2s(saveProgramTextFile("error.java", src))); throw rethrow(e); } /*if (useIndexedList) print("Indexed/unindexed lookups: " + findCodeTokens_indexed + "/" + findCodeTokens_unindexed + ", lists made: " + IndexedList2.instances); print("findCodeToken bails: " + findCodeTokens_bails + "/" + findCodeTokens_nonbails); print("javaToks: " + javaTok_n + "/" + javaTok_elements);*/ print("Saving."); // for dexcompile.php if (mainClassName != null) tokPrepend(tok, 0, "//FILENAME: " + (mainPackage != null ? mainPackage.replace(".", "/") + "/" : "") + mainClassName + ".java\n"); if (mainJava != null) mainJava = join(tok); else if (tok.contains("package")) splitJavaFiles(tok); else saveMainJava(tok); } catch (Exception __e) { throw rethrow(__e); } } static List<String> localStuff1(List<String> tok) { int safety = 0, i; boolean same = false; tok = indexTokenList(tok); tok_scopes(tok, "autoCloseScopes" , true); do { ping(); List<String> before = cloneList(tok); //print("localStuff loop " + safety); earlyStuff(tok); // EARLY local stuff goes here tok_dropMetaComments(tok); tok_earlyGeneralStuff(tok); conceptDeclarations(tok); tok_recordDecls(tok); tok = multilineStrings(tok); tok_singleQuoteIdentifiersToStringConstants(tok); tok_inStringEvals(tok); tok_listComprehensions(tok); tok_eventFunctions(tok); tok_for_single(tok); tok_for_unpair(tok); // Do this... //tok_doubleFor_v2(tok); tok_doubleFor_v3(tok); // ...before this tok_forUnnull(tok); tok_ifCast(tok); forPing(tok); tok_directSnippetRefs(tok); quicknu(tok); //tok_juxtaposeCalls(tok); jreplace(tok, "LLS", "L<LS>"); jreplace(tok, "LS", "L<S>"); jreplace(tok, "ES", "Ext<S>"); jreplace(tok, "ExtS", "Ext<S>"); jreplace(tok, "WeakRef", "WeakReference"); jreplace(tok, "dispose <id>;", "{ cleanUp($2); $2 = null; }"); tok_doPing(tok); replaceKeywordBlock(tok, "swing", "{ swing(r {", "}); }"); replaceKeywordBlock(tok, "androidUI", "{ androidUI(r {", "}); }"); replaceKeywordBlock(tok, "withDBLock", "{ withDBLock(r {", "}); }"); replaceKeywordBlock(tok, "afterwards", "temp tempAfterwards(r {", "});"); for (String keyword : ll("tokcondition", "tokCondition")) replaceKeywordBlock(tok, keyword, "new TokCondition { public bool get(final L<S> tok, final int i) {", "}}"); jreplace(tok, "synced <id>", "synchronized $2"); jreplace(tok, "sync <id>", "synchronized $2"); jreplace(tok, "synchronized {", "synchronized(this) {"); replaceKeywordBlock(tok, "answer", "static S answer(S s) {\nfinal new Matches m;\n", "\nret null;\n}"); replaceKeywordBlock(tok, "static-pcall", "static { pcall {", "}}"); replaceKeywordBlock(tok, "loading", "{ temp tempShowLoadingAnimation(); ", "}"); replaceKeywordPlusQuotedBlock(tok, "loading", new Object() { String[] get(List<String> tok, int i) { String text = tok.get(i+2); return new String[] { "{ temp tempShowLoadingAnimation(" + text + "); ", "}" }; }}); while ((i = jfind(tok, "visualize as")) >= 0) { int j = tok_findEndOfStatement(tok, i); // expression, rather tok.set(i+2, "{ ret"); tok.set(j-1, "; }"); reTok(tok, i, j); } for (String pat : ll("visual {", "visualize {")) jreplace(tok, pat, "public JComponent visualize() {", tokCondition_beginningOfMethodDeclaration()); jreplace(tok, "visualize2 {", "JComponent visualize2() {", tokCondition_beginningOfMethodDeclaration()); replaceKeywordBlock(tok, "start-thread-printDone", "start-thread {", "printDone(); }"); replaceKeywordBlock(tok, "start-thread", "start { thread \"Start\" { temp enter(); pcall {", "}}}"); jreplace(tok, "start {", "void start() ctex { super.start();", tokCondition_beginningOfMethodDeclaration()); var notVoidMethod = new TokCondition() { public boolean get(final List<String> tok, final int i) { return neqGet(tok, i-1, "void"); }}; // run { ... } => public void run() { ... } // same with close jreplace(tok, "run {", "public void run() {", notVoidMethod); jreplace(tok, "close {", "public void close() {", notVoidMethod); replaceKeywordBlock(tok, "html", "static O html(S uri, fMap<S, S> params) ctex " + "{\n", "}"); replaceKeywordBlock(tok, "afterVisualize", "visualize { JComponent _c = super.visualize();", "ret _c; }"); replaceKeywordBlock(tok, "enhanceFrame", "void enhanceFrame(Container f) { super.enhanceFrame(f);", "}"); if (assumeTriple) jreplace(tok, "Triple", "T3"); tok_shortFinals(tok); tok_moduleClassDecls(tok); jreplace(tok, "static sync", "static synchronized"); jreplace(tok, "sclass", "static class"); jreplace(tok, "fclass", "final class"); jreplace(tok, "fsclass", "final static class"); jreplace(tok, "srecord", "static record"); jreplace(tok, "strecord", "static transformable record"); jreplace(tok, "record noeq", "noeq record"); jreplace(tok, "asclass", "abstract static class"); jreplace(tok, "sinterface", "static interface"); jreplace(tok, "ssynchronized", "static synchronized"); jreplace(tok, "ssvoid", "static synchronized void"); jreplace(tok, "sbool", "static bool"); jreplace(tok, "fbool", "final bool"); jreplace(tok, "sint", "static int"); jreplace(tok, "snew", "static new"); jreplace(tok, "sv <id>", "static void $2"); jreplace(tok, "pvoid", "public void"); // "sS" => static S jreplace(tok, "sS", "static S"); // "sO" => static O jreplace(tok, "sO", "static O"); // "sL" => static L jreplace(tok, "sL", "static L"); // "toString {" => "public S toString() {" jreplace(tok, "toString {", "public S toString() {"); jreplace(tok, "Int", "Integer"); jreplace(tok, "Bool", "Boolean"); jreplace(tok, "BigInt", "BigInteger"); jreplace(tok, "Char", "Character"); jreplace(tok, "Sym", "Symbol"); jreplace(tok, "SymSym", "SymbolSymbol"); jreplace(tok, "SS", "Map<S>"); jreplace(tok, "SymbolSymbol", "Map<Symbol>"); jreplace(tok, "MapSO", "Map<S, O>"); jreplace(tok, "ByName<", "IF1<S, "); jreplace(tok, "ITransform<<id>>", "IF1<$3>"); jreplace(tok, "ITransform", "IF1"); jreplace(tok, "PairS", "Pair<S>"); jreplace(tok, "LPairS", "L<Pair<S>>"); jreplace(tok, "T3S", "T3<S>"); jreplace(tok, "F1S", "F1<S>"); jreplace(tok, "ItIt", "IterableIterator"); jreplace(tok, "CloseableItIt", "CloseableIterableIterator"); jreplace(tok, "class <id> > <id>", "class $2 extends $4", new TokCondition() { public boolean get(final List<String> tok, final int i) { String t = _get(tok, i+1+4*2); return eq(t, "{") || isIdentifier(t); }}); jreplace(tok, "class <id> > <id><<id>> {", "class $2 extends $4 $5 $6 $7 {"); jreplace(tok, "ISegmenter", "IF1<BufferedImage, L<Rect>>"); // IPred<A, B> => IF2<A, B, Bool> jreplace(tok, "IPred<<id>, <id>>", "IF2<$3, $5, Bool>"); // IPred<A> => IF1<A, Bool> jreplace(tok, "IPred<<id>>", "IF1<$3, Bool>"); jreplace(tok, "IPred<<id>[]>", "IF1<$3[], Bool>"); // Proposition => WithReasoning<S> (should we really define this?) jreplace(tok, "Proposition", "WithReasoning<S>"); replaceKeywordBlock(tok, "print exceptions", "{ try {", "} on fail __e { printStackTrace(__e); } }"); // "on fail {" => "catch (Throwable _e) { ... rethrow(_e); }" replaceKeywordBlock(tok, "on fail", "catch (Throwable _e) {", "\nthrow rethrow(_e); }"); // "on fail e {" => "catch (Throwable e) { ... rethrow(e); }" replaceKeywordBlock_dyn2_legacy(tok, "on fail <id>", new Object() { String[] get(List<String> tok, int iOpening, int iClosing) { String var = tok.get(iOpening-2); return new String[] { "catch (Throwable " + var + ") {", "\nthrow rethrow(" + var + "); }" }; } }); // "on fail Type e {" => "catch (Type e) { ... rethrow(e); }" replaceKeywordBlock_dyn2_legacy(tok, "on fail <id> <id>", new Object() { String[] get(List<String> tok, int iOpening, int iClosing) { String type = tok.get(iOpening-4); String var = tok.get(iOpening-2); return new String[] { "catch (" + type + " " + var + ") {", "\nthrow " + var + "; }" }; } }); // "catch {" => "catch (Throwable _e) {" jreplace(tok, "catch {", "catch (Throwable _e) {"); // "catch print e {" => "catch e { _handleException(e); " jreplace(tok, "catch print <id> {", "catch $3 { _handleException($3);"); // "catch print short e {" => "catch e { printExceptionShort(e); " jreplace(tok, "catch print short <id> {", "catch $4 { printExceptionShort($4);"); // "catch X e {" => "catch (X e) {" jreplace(tok, "catch <id> <id> {", "catch ($2 $3) {"); // "catch e {" => "catch (Throwable e) {" (if e is lowercase) jreplace(tok, "catch <id> {", "catch (Throwable $2) {", new TokCondition() { public boolean get(final List<String> tok, final int i) { String word = tok.get(i+3); return startsWithLowerCaseOrUnderscore(word); }}); jreplace(tok, "+ +", "+", new TokCondition() { public boolean get(final List<String> tok, final int i) { //printStructure("++: ", subList(tok, i-1, i+6)); if (empty(_get(tok, i+2))) return false; // no space between the pluses if (empty(_get(tok, i)) && eq("+", _get(tok, i-1))) return false; // an actual "++" at the left if (empty(_get(tok, i+4)) && eq("+", _get(tok, i+5))) return false; // an actual "++" at the right //print("doing it"); return true; }}); // single underscore (not allowed in Java anymore) to double underscore jreplace(tok, "_", "__"); // [stdEq] -> implementation of equals() and hashCode() jreplace(tok, "[stdEq]", "public bool equals(O o) { ret stdEq2(this, o); }\n" + "public int hashCode() { ret stdHash2(this); }"); // [stdToString] -> toString { ret stdToString(this); } jreplace(tok, "[stdToString]", "toString { ret stdToString(this); }"); // [concepts] "concept.field!" for dereferencing references // "<id>!", "?!" etc. jreplace(tok, "*!", "$1.get()", new TokCondition() { public boolean get(final List<String> tok, final int i) { String l = tok.get(i+1); if (!(isIdentifier(l) || eqOneOf(l, ")", "?"))) return false; if (tok.get(i+2).contains("\n")) return false; // no line break between <id> and ! if (nempty(tok.get(i+4))) return true; // space after = ok String t = _get(tok, i+5); if (t == null) return false; if (isIdentifier(t) || eqOneOf(t, "=", "(")) return false; return true; }}); jreplace(tok, "for (<id> :", "for (var $3 :"); jreplace(tok, "for (<id> <id>)", "for ($3 $4 : list($3))"); jreplace(tok, "for (final <id> <id>)", "for (final $4 $5 : list($4))"); jreplace(tok, "ret", "return", new TokCondition() { public boolean get(final List<String> tok, final int i) { if (eqGetOneOf(tok, i-1, "int", "return")) return false; String next = _get(tok, i+3); if (eq(next, ".")) return isInteger(_get(tok, i+5)); // e.g. "ret .1", but not "ret.bla" return !eqOneOf(next, "=", ")"); }}); // "continue unless", "break unless" for (String phrase : ll("continue unless", "break unless")) while ((i = jfind(tok, phrase)) >= 0) { String keyword = tok.get(i); int j = scanOverExpression(tok, getBracketMap(tok), i+4, ";"); replaceTokens(tok, i, i+4, "{ if (!("); tok.set(j, ")) " + keyword + "; }"); reTok(tok, i, j+1); } // S s = bla(), return if null; => S s = bla(); if (s == null) return; // same with continue, break while ((i = jfind(tok, ", <id> if null;", new TokCondition() { public boolean get(final List<String> tok, final int i) { return eqOneOf(tok.get(i+3), "return", "ret", "continue", "break"); }})) >= 0) { String cmd = tok.get(i+2); int j = tok_findBeginningOfStatement(tok, i); print("Found statement " + j + "/" + i + " - " + joinSubList(tok, j-1, i+5*2-1)); String var = getVarDeclarationName(subList(tok, j-1, i)); replaceTokens_reTok(tok, i, i+5*2-1, "; if (" + var + " == null) " + cmd + ";"); } // S s = bla(), return false if null; => S s = bla(); if (s == null) return false; // (with false being any identifier) while ((i = jfind(tok, ", return <id> if null;")) >= 0) { String returnValue = tok.get(i+4); int j = tok_findBeginningOfStatement(tok, i); String var = getVarDeclarationName(subList(tok, j-1, i)); replaceTokens_reTok(tok, i, i+6*2-1, "; if (" + var + " == null) return " + returnValue + ";"); } // "continue if", "break if" for (String phrase : ll("continue if", "break if")) while ((i = jfind(tok, phrase)) >= 0) { String keyword = tok.get(i); int j = scanOverExpression(tok, getBracketMap(tok), i+4, ";"); replaceTokens(tok, i, i+4, "{ if ("); tok.set(j, ") " + keyword + "; }"); reTok(tok, i, j+1); } // return unless set <var>; => { if (var) return; set var; } jreplace(tok, "return unless set <id>;", "{ if ($4) return; set $4; }"); // set x; => x = true; // yeah it doesn't save many characters, but I like it jreplace(tok, "set <id>;", "$2 = true;", new TokCondition() { public boolean get(final List<String> tok, final int i) { return !eqGet(tok, i-1, "unless"); }}); // set !x; => x = false; (did this one day and thought yes it makes sense in a way) jreplace(tok, "set !<id>;", "$3 = false;"); // unset x; => x = false; jreplace(tok, "unset <id>;", "$2 = false;"); // "return if" while ((i = jfind(tok, "return if")) >= 0) { int j = scanOverExpression(tok, getBracketMap(tok), i+4, ";"); replaceTokens(tok, i, i+4, "{ if ("); tok.set(j, ") return; }"); reTok(tok, i, j+1); } // "return unless" while ((i = jfind(tok, "return unless")) >= 0) { int j = scanOverExpression(tok, getBracketMap(tok), i+4, ";"); replaceTokens(tok, i, i+4, "{ if (!("); tok.set(j, ")) return; }"); reTok(tok, i, j+1); } tok_ifNullAssign(tok); // "return <id> if" // "return with <statement>" / "continue with <statement>" / "break with <statement>" while ((i = jfind(tok, "<id> with", new TokCondition() { public boolean get(final List<String> tok, final int i) { return eqOneOf(tok.get(i+1), "return", "continue", "break"); }})) >= 0) { // XXX int j = scanOverExpression(tok, getBracketMap(tok), i+4, ";"); int j = tok_findEndOfStatement(tok, i+4)-1; //print("Found statement: " + joinSubList(tok, i+4, j+1)); tok.set(j, "; " + tok.get(i) + "; }"); replaceTokens(tok, i, i+3, "{"); reTok(tok, i, j+1); } while ((i = jfind(tok, "return <id> if")) >= 0) { int j = scanOverExpression(tok, getBracketMap(tok), i+4, ";"); tok.set(j, ") return " + tok.get(i+2) + "; }"); replaceTokens(tok, i, i+6, "{ if ("); reTok(tok, i, j+1); } // return "bla" with <statement> while ((i = jfindOneOf(tok, "return <quoted> with", "return <id> with")) >= 0) { String result = tok.get(i+2); int j = scanOverExpression(tok, getBracketMap(tok), i+6, ";"); replaceTokens(tok, i, i+5, "{"); tok.set(j, "; return " + result + "; }"); reTok(tok, i, j+1); } tok_debugStatements(tok); // while not null (...) / if not null (...) while ((i = jfind_check("not", tok, "<id> not null (", new TokCondition() { public boolean get(final List<String> tok, final int i) { return eqOneOf(_get(tok, i+1), "if", "while"); }})) >= 0) { int closingBracket = findEndOfBracketPart(tok, i+6)-1; replaceTokens(tok, i+2, i+6, "("); tok.set(closingBracket, ") != null)"); reTok(tok, i, closingBracket+1); } // while null (...) / if null (...) while ((i = jfind_check("null", tok, "<id> null (", new TokCondition() { public boolean get(final List<String> tok, final int i) { return eqOneOf(_get(tok, i+1), "if", "while"); }})) >= 0) { int closingBracket = findEndOfBracketPart(tok, i+4)-1; replaceTokens(tok, i+2, i+4, "("); tok.set(closingBracket, ") == null)"); reTok(tok, i, closingBracket+1); } // Replace $1 with m.unq(0) etc. - caveat: this blocks identifiers $1, $2, ... for (i = 1; i < l(tok); i += 2) { String s = tok.get(i); if (s.startsWith("$")) { s = substring(s, 1); if (isInteger(s)) { tok.set(i, "m.unq(" + (parseInt(s)-1) + ")"); reTok(tok, i); } } } // instanceof trickery jreplace(tok, "is a <id>", "instanceof $3"); jreplace(tok, "!<id> instanceof <id>.<id>", "!($2 instanceof $4.$6)"); jreplace(tok, "!<id> instanceof <id>", "!($2 instanceof $4)"); jreplace(tok, "<id> !instanceof <id>", "!($1 instanceof $4)"); // map func1 func2 func3(...) => mapFGH(f func1, f func2, f func3, ...) jreplace(tok, "map <id> <id> <id>(", "mapFGH(f $2, f $3, f $4,"); // map func1 func2(...) => mapFG(f func1, f func2, ...) jreplace(tok, "map <id> <id>(", "mapFG(f $2, f $3,"); // "ref->bla" for dereferencing Concept.Ref or ThreadLocal or other // For lambdas, use SPACES on the left or right of the arrow! //jreplace(tok, "<id> ->", "$1.get()."); jreplace(tok, "->", ".get().", new TokCondition() { public boolean get(final List<String> tok, final int i) { return empty(tok.get(i)) // no space on left of arrow && empty(tok.get(i+2)) // no space inside of arrow && empty(tok.get(i+4)) // no space on right of arrow && !eq(_get(tok, i-1), "-"); // i-->0; }}); // shortened subconcept declaration (before star constructors!) shortenedSubconcepts(tok); tok_beaConceptDecls(tok); // "case" as a variable name ( => _case) caseAsVariableName(tok); // "do" as a function name ( => dO) tok_doAsMethodName(tok); // "continue" as a function name ( => _continue) continueAsFunctionName(tok); tok_extend(tok); jreplace(tok, "pn {", "p-noconsole {"); // Do these BEFORE awt replacement! ("p-awt" contains "awt" token) replaceKeywordBlock(tok, "r-awt", "r { awt {", "}}"); if (hasCodeTokens(tok, "p", "-")) tok_p_old(tok); replaceKeywordBlock(tok, "awt-messagebox", "awt { pcall-messagebox {", "}}"); replaceKeywordBlock(tok, "awt", "swingLater(r {", "});"); jreplace(tok, "p-android {", "set flag Android. p {"); unswing(tok); lockBlocks(tok); tok_switchTo(tok); // trim x; jreplace(tok, "trim <id>;", "$2 = trim($2);"); // iterate with index jreplace (tok, "for <id> over <id>:", "for (int $2 = 0; $2 < l($4); $2++)"); jreplace (tok, "for <id> backwards over <id>:", "for (int $2 = l($5)-1; $2 >= 0; $2--)"); jreplace (tok, "for <id>, <id> <id> over <id>: {", "for (int $2 = 0; $2 < l($7); $2++) { $4 $5 = $7.get($2);"); jreplace (tok, "for <id>, <id> <id> backwards over <id>: {", "for (int $2 = l($8)-1; $2 >= 0; $2--) { $4 $5 = $8.get($2);"); jreplace (tok, "for <id> to <id>:", "for (int $2 = 0; $2 < $4; $2++)"); jreplace (tok, "for <id> to <int>:", "for (int $2 = 0; $2 < $4; $2++)"); tok = expandShortTypes(tok); tok_equalsCast(tok); tok_equalsOptCast(tok); replaceKeywordBlock(tok, "r-thread-messagebox", "r-thread { pcall-messagebox {", "}}"); replaceKeywordBlock(tok, "thread-messagebox", "thread { pcall-messagebox {", "}}"); jreplace(tok, "rThread {", "r-thread {"); jreplace(tok, "rEnterThread {", "rThreadEnter {"); jreplace(tok, "rThreadEnter {", "r-thread { temp enter(); "); replaceKeywordBlock(tok, "r-thread", "runnableThread(r {", "})"); rNamedThread(tok); // only works in the scope of a DynModule jreplace(tok, "rEnter {", "r { temp enter(); "); replaceKeywordBlock(tok, "r-pcall", "r { pcall {", "}}"); replaceKeywordBlock(tok, "r-messagebox", "r { pcall-messagebox {", "}}"); jreplace(tok, "r <id> + r <id>", "r { $2(); $5(); }"); // runnable and r - now also with automatic toString if enabled for (String keyword : ll("runnable", "r")) { while ((i = jfind(tok, keyword + " {")) >= 0) { int idx = findCodeTokens(tok, i, false, "{"); int j = findEndOfBracketPart(tok, idx); List<String> contents = subList(tok, idx+1, j-1); replaceTokens(tok, i, j+1, "new Runnable {" + " public void run() ctex { " + tok_addSemicolon(contents) + "\n}" + (autoQuine ? tok_autoQuineFunc(contents) : "") + "}"); reTok(tok, i, j+1); } while ((i = jfind(tok, keyword + " <quoted> {")) >= 0) { int idx = findCodeTokens(tok, i, false, "{"); int j = findEndOfBracketPart(tok, idx); List<String> contents = subList(tok, idx+1, j-1); replaceTokens(tok, i, j+1, "new Runnable {" + " public void run() ctex { " + tok_addSemicolon(contents) + "\n}" + " toString { ret " + tok.get(i+2) + "; }" + (autoQuine ? tok_autoQuineFunc(contents, "_shortenedSourceCode") : "") + "}"); reTok(tok, i, j+1); } } replaceKeywordBlock(tok, "expectException", "{ bool __ok = false; try {", "} catch { __ok = true; } assertTrue(\"expected exception\", __ok); }"); while ((i = tok.indexOf("tex")) >= 0) { tok.set(i, "throws Exception"); tok = jtok(tok); } // shorter & smarter whiles jreplace(tok, "while true", "while (true)"); jreplace(tok, "while licensed", "while (licensed())"); jreplace(tok, "repeat {", "while (licensed()) {"); tok_repeatWithSleep(tok); // null; => return null; etc. Object cond = new TokCondition() { public boolean get(final List<String> tok, final int i) { return tok_tokenBeforeLonelyReturnValue(tok, i-1); }}; jreplace(tok, "null;", "return null;", cond); jreplace(tok, "false;", "return false;", cond); jreplace(tok, "true;", "return true;", cond); jreplace(tok, "this;", "return this;", cond); // ok <cmd> => ret "OK" with <cmd> jreplace(tok, "ok <id>", "return \"OK\" with $2"); replaceKeywordBlock(tok, "ok", "{", " return \"OK\"; }", new F2<List<String>, Integer, Boolean>() { public Boolean get(List<String> _tok, Integer nIdx) { try { return !eqGetOneOf(_tok, nIdx-1, "void", "svoid"); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "!eqGetOneOf(_tok, nIdx-1, \"void\", \"svoid\")"; }}); // "myFunction;" instead of "myFunction();" - quite rough // (isolated identifier as function call) cond = new TokCondition() { public boolean get(List<String> tok, int i) { String word = tok.get(i+3); //print("single word: " + word); return !eqOneOf(word, "break", "continue", "return", "else", "endifdef", "endif"); } }; for (String pre : litlist("}", ";")) jreplace(tok, pre + " <id>;", "$1 $2();", cond); // shorter match syntax for answer methods tok_expandIfQuoted(tok); jreplace(tok, "if <id> eq <quoted>", "if (eq($2, $4))"); tok_dropExtraCommas(tok); // additional translations (if necessary) jreplace(tok, "pcall ping {", "pcall { ping();"); replaceKeywordBlock(tok, ") pcall", ") { pcall {", "}}"); //jreplace(tok, "void <id> pcall {", "$1 $2() pcall {"); replaceKeywordBlock(tok, "pcall", "try {", "} catch (Throwable __e) { _handleException(__e); }"); replaceKeywordBlock(tok, "pcall-print", "try {", "} catch (Throwable __e) { printStackTrace(__e); }"); replaceKeywordBlock(tok, "pcall-short", "try {", "} catch (Throwable __e) { print(exceptionToStringShort(__e)); }"); replaceKeywordBlock(tok, "pcall-silent", "try {", "} catch (Throwable __e) { silentException(__e); }"); replaceKeywordBlock(tok, "pcall-messagebox", "try {", "} catch __e { messageBox(__e); }"); replaceKeywordBlock(tok, "pcall-infobox", "try {", "} catch __e { infoBox(__e); }"); tok = dialogHandler(tok); replaceKeywordBlock(tok, "exceptionToUser", "try {", "} catch (Throwable __e) { ret exceptionToUser(__e); }"); if (hasCodeTokens(tok, "twice", "{")) replaceKeywordBlock(tok, "twice", "for (int __twice = 0; __twice < 2; __twice++) {", "}"); while ((i = findCodeTokens(tok, "bench", "*", "{")) >= 0) { int j = findEndOfBracketPart(tok, i+4)-1; String time = makeVar("time"); String v = makeVar("bench"); String n = tok.get(i+2); tok.set(i, "{ long " + time + " = sysNow(); for (int " + v + " = 0; " + v + " < " + n + "; " + v + "++)"); tok.set(i+2, ""); tok.set(j, "} printBenchResult(sysNow()-" + time + ", " + n + "); }"); reTok(tok, i, j+1); } replaceKeywordBlockDyn(tok, "time", new Object() { String[] get() { String var = makeVar("startTime"); return new String[] { "{ long " + var + " = sysNow(); try { ", "} finally { " + var + " = sysNow()-" + var + "; saveTiming(" + var + "); } }"}; }}); // version without { } replaceKeywordBlockDyn(tok, "time2", new Object() { String[] get() { String var = makeVar("startTime"); return new String[] { "long " + var + " = sysNow(); ", " " + var + " = sysNow()-" + var + "; saveTiming(" + var + "); "}; }}); // time "bla" { // time msg { replaceKeywordPlusQuotedOrIDBlock(tok, "time", new Object() { String[] get(List<String> tok, int i) { String var = makeVar("startTime"); return new String[] { "long " + var + " = sysNow(); ", " done2_always(" + tok.get(i+2) + ", " + var + "); "}; }}); if (hasCodeTokens(tok, "assertFail", "{")) { String var = makeVar("oops"); replaceKeywordBlock(tok, "assertFail", "boolean " + var + " = false; try {", "\n" + var + " = true; } catch (Exception e) { /* ok */ } assertFalse(" + var + ");"); } replaceKeywordBlock(tok, "yo", "try {", "} catch (Exception " + makeVar("e") + ") { ret false; }", new TokCondition() { public boolean get(final List<String> tok, final int i) { return neqOneOf(_get(tok, i-1), "svoid", "void"); }}); replaceKeywordBlock(tok, "awtIfNecessary", "swingNowOrLater(r " + "{", "});"); ctex(tok); replaceKeywordBlock(tok, "actionListener", "new java.awt.event.ActionListener() { " + "public void actionPerformed(java.awt.event.ActionEvent _evt) { pcall-messagebox {", "}}}"); for (String keyword : ll("autocloseable", "autoCloseable")) /*replaceKeywordBlock(tok, keyword, "new AutoCloseable() { public void close() throws Exception {", "}}");*/ replaceKeywordBlock_dyn2_legacy(tok, keyword, new Object() { String[] get(List<String> tok, int iOpening, int iClosing) { List<String> contents = subList(tok, iOpening+1, iClosing); return new String[] { "new AutoCloseable() { toString { ret " + quote(shorten(defaultMaxQuineLength(), trimJoin(contents))) + "; } public void close() throws Exception {", "}}" }; } }); // try answer (string, test with nempty) while ((i = findCodeTokens(tok, "try", "answer")) >= 0) { int j = findEndOfStatement(tok, i); String v = makeVar(); boolean needCurly = !eqGet(tok, i-2, "{"); tok.set(i, (needCurly ? "{" : "") + " S " + v); tok.set(i+2, "="); tok.set(j-1, "; if (!empty(" + v + ")) ret " + v + "; " + (needCurly ? "}" : "")); reTok(tok, i, j); } // try bool[ean] (try answer with Bool type) while ((i = findCodeTokens(tok, "try", "boolean")) >= 0) { int j = findEndOfStatement(tok, i); String v = makeVar(); tok.set(i, "{ Bool " + v); tok.set(i+2, "="); tok.set(j-1, "; if (" + v + " != null) ret " + v + "; }"); reTok(tok, i, j); } // <statement>, print "..."; => { <statement>; print("..."); } while ((i = jfind(tok, ", print <quoted>;")) >= 0) { int j = tok_findBeginningOfStatement(tok, i); replaceTokens_reTok(tok, i, i+4*2-1, "; print(" + tok.get(i+4) + "); }"); tokPrepend_reTok(tok, j, "{ "); } // return if null <expression> => if (<expression> == null) return; while ((i = jfind(tok, "return if null")) >= 0) { int j = findEndOfStatement(tok, i); clearTokens(tok, i, i+2); tok.set(i+4, "(("); tok.set(j-1, ") == null) ret;"); reTok(tok, i, j); } // return optional (return if not null) while ((i = jfind_check("optional", tok, "return optional <id> =")) >= 0) { int j = findEndOfStatement(tok, i); String v = tok.get(i+4); clearTokens(tok, i+2, i+4); tok.set(i, "{"); tok.set(j-1, "; if (" + v + " != null) ret " + v + "; }"); reTok(tok, i, j); } // try object (return if not null) jreplace_dyn(tok, "try object (<id>)", (_tok, cIdx) -> { String type = _tok.get(cIdx+6); return "try object " + type + " " + makeVar() + " = (" + type + ")"; }); while ((i = jfind_check("object", tok, "try object")) >= 0) { int j = findEndOfStatement(tok, i); clearTokens(tok, i, i+3); boolean isDecl = isIdentifier(get(tok, i+4)) && isIdentifier(get(tok, i+6)) && eqGet(tok, i+8, "="); if (isDecl) { String v = get(tok, i+6); tok.set(i, "{"); tok.set(j-1, "; if (" + v + " != null) ret " + v + "; }"); } else { String v = makeVar(); tok.set(i, "{ O " + v + "="); tok.set(j-1, "; if (" + v + " != null) ret " + v + "; }"); } reTok(tok, i, j); } // try Int i = ...; (return if not null, shorter version of "try object") /*while ((i = jfind(tok, "try <id> <id> =")) >= 0) { int j = findEndOfStatement(tok, i); S type = tok.get(i+2), v = tok.get(i+4); tok.set(i, "{"); tok.set(j-1, "; if (" + v + " != null) ret " + v + "; }"); reTok(tok, i, j); }*/ while ((i = jfind(tok, "try <id>")) >= 0) { int iType = i+2, iVar = tok_findEndOfType(tok, iType); String v = tok.get(iVar); assertEquals("try object", "=", get(tok, iVar+2)); int j = findEndOfStatement(tok, iVar); tok.set(i, "{"); tok.set(j-1, "; if (" + v + " != null) ret " + v + "; }"); reTok(tok, i, j); } // debug print ...; => if (debug) print(...); while ((i = jfind(tok, "debug print")) >= 0) { int j = findEndOfStatement(tok, i); replaceTokens(tok, i, i+4, "if (debug) print("); tok.set(j-1, ");"); reTok(tok, i, j); } functionReferences(tok); tok_expandLPair(tok); tok_expandPairL(tok); tok_expandLT3(tok); tok_quicknew2(tok); // before temp blocks tok_varNamedLikeFunction(tok); tempBlocks(tok); // after quicknew2 for stuff like "temp new X x;" // X x = nu(+...) => X x = nu X(+...) jreplace(tok, "<id> <id> = nu(+", "$1 $2 = nu $1(+"); // X x = nu(a := ...) => X x = nu X(a := ...) jreplace(tok, "<id> <id> = nu(<id> :=", "$1 $2 = nu $1($6 :="); tok_expandVarCopies(tok); // AFTER the lines just above tok_replaceColonEqualsSyntax(tok); // ditto tok_unpair(tok); tok_cachedFunctions(tok); tok_simplyCachedFunctions(tok); tok_timedCachedFunctions(tok); tok_optPar(tok); throwFailEtc(tok); tok_typeAA(tok, pairClasses); tok_typeAAA(tok, tripleClasses); tok_typeAO(tok, litset("WithTrail")); // before star constructors so we can define star constructors in a macro tok_localMacro(tok); // do this after expanding sclass etc. tok = tok_expandStarConstructors(tok); tok_kiloConstants(tok); //tok_colonMessages(tok); while ((i = jfind(tok, "shit:")) >= 0) { int j = tok_findEndOfStatement(tok, i); tok.set(i+2, "("); tok.set(j-1, ");"); reTok(tok, i, j); } jreplace(tok, "shit(", "ret with print("); tok_virtualTypes(tok); tok_autoLongConstants(tok); // common misordering of type arguments jreplace(tok, "boolean <A>", "<A> boolean"); tok_unimplementedMethods(tok); tok_switchableFields(tok); tok_autoDisposeFields(tok); tok_shortVisualize(tok); tok_whileGreaterThan(tok); tok_ifThenEnd(tok); tok_autoInitVars(tok); tok_fixBadTypeParameterOrder(tok); // shortened method declarations BEFORE standardFunctions tok_svoidEtc(tok); jreplace(tok, "void <id> {", "$1 $2() {"); jreplace(tok, "void <id> thread {", "$1 $2() thread {"); jreplace(tok, "String <id> {", "$1 $2() {"); jreplace(tok, "Object <id> {", "$1 $2() {"); jreplace(tok, "List <id> {", "$1 $2() {"); namedThreads(tok); threads(tok); //tok_maxEquals(tok); tok_questionDot(tok); jreplace(tok, "if (<id>?!)", "if ($3 != null && $3!)"); tok_embeddedFunctions(tok); // quicknew for arrays jreplace(tok, "<id>[] <id> = new[", "$1[] $4 = new $1["); jreplace(tok, "<id>[] <id> = new {", "$1[] $4 = {"); jreplace(tok, "<id><<id>>[] <id> = new[", "$1 $2 $3 $4[] $7 = new $1["); jreplace(tok, "<id> ifNull =", "if ($1 == null) $1 ="); jreplace(tok, "class <id> extends <id><.<id>>", "class $2 extends $4<$2.$7>"); tok_once(tok); // must come before next line so you can combine them tok_ifRecordMatch(tok); jreplace(tok, "<id> ||=", "$1 = $1 ||"); // magicValue followed by a numerical constant jreplace(tok, "magicValue", "", (_tok, _i) -> { String t = _get(_tok, _i+3); return eqOneOf(t, ".", "-") || isInteger(t); }); lambdaReferences(tok); tok_returnSelf(tok); // Lua-like print statement jreplace(tok, "print <quoted>", "print($2);"); tok_tildeCalls(tok); tok_svoidEtc(tok); tok_swappableFunctions(tok); tok_optParLambda(tok); tok_runnableClasses(tok); tok_swapStatement(tok); tok_akaFunctionNames(tok); tok_defaultArguments(tok); tok_persistableClasses(tok); tok_transientClasses(tok); tok_shortMethodReferences(tok); jreplace(tok, "== null ?:", "== null ? null :"); jreplace(tok, "?:", "== null ? null :"); tok_orCase(tok); tok_beforeMethods(tok); tok_afterMethods(tok); tok_returnAsFunctionName(tok); tok_transpileGetSet(tok); tok_pcallPrefix(tok); tok_numberFunctionNames(tok); tok_castToStatements(tok); tok_optionalFields(tok); tok_getFromMap(tok); jreplace(tok, "for <id> : <id> {", "for (var $2 : $4) {"); tok_shortLambdas(tok); // end of local stuff tok_processMetaBlocks(tok, metaCodeAllowed()); if (metaCodeAllowed()) runMetaTransformers(tok); same = eq(tok, before); /*if (!same) print("local not same " + safety + " (" + l(tok) + " tokens)");*/ if (safety++ >= 10) { printSources(tok); throw fail("safety 10 error!"); } } while (!same); return tok; } static List<String> reTok_include(List<String> tok, int i, int j) { return reTok_modify(tok, i, j, "localStuff1"); } static List<String> includeInMainLoaded_reTok(List<String> tok, int i, int j) { return reTok_include(tok, i, j); } static List<String> stdstuff(List<String> tok) { //if (++level >= 10) fail("woot? 10"); print("stdstuff!"); int i; List<String> ts = new ArrayList(); tok_findTranslators(tok, ts); if (nempty(ts)) print("DROPPING TRANSLATORS: " + structure(ts)); print("quickmain"); tok = quickmain(tok); print("includes"); tok = tok_processIncludes(tok); print("conceptsDot"); if (processConceptsDot(tok)) tok = tok_processIncludes(tok); List<String> dontImports = tok_processDontImports(tok, definitions); for (String s : dontImports) doNotIncludeFunction.remove(afterLastDot(s)); //print('starConstructors); tok = tok_expandStarConstructors(tok); // drop Java 8 annotations since we're compiling for Java 7 jreplace(tok, "@Nullable", ""); // STANDARD CLASSES & INTERFACES print("standard classes"); haveClasses = addStandardClasses_v2(tok); tok_quickInstanceOf(tok, haveClasses); // concept-related stuff // auto-import concepts /*bool _a = tok_hasClassRef2(tok, "Concept") || tok_hasClassRef2(tok, "Concepts"), _b = !haveClasses.contains("Concept"); //print("auto-import: " + _a + ", " + _b); if (_a && _b) { print("Auto-including concepts."); if (shouldNotIncludeClass.contains("Concepts")) { print(join(tok)); fail("Unwanted concepts import"); } printStruct(haveClasses); tok = includeInMainLoaded(tok, "concepts."); reTok(tok, l(tok)-1, l(tok)); //processConceptsDot(tok); }*/ return tok; } // end of stdStuff! static List<String> multilineStrings(List<String> tok) { for (int i = 1; i < tok.size(); i += 2) { String t = tok.get(i); if (isQuoted(t)) if (t.startsWith("[") || t.contains("\r") || t.contains("\n")) tok.set(i, quote(unquote(t))); } return tok; } static List<String> quickmain(List<String> tok) { if (quickmainDone1 && quickmainDone2) return tok; int i = findCodeTokens(tok, "main", "{"); if (i < 0) i = findCodeTokens(tok, "m", "{"); if (i >= 0 && !(i-2 > 0 && tok.get(i-2).equals("class"))) { tokSet_reTok(tok, i, (definitions.contains("mainClassPublic") ? "public " : "") + "class main"); quickmainDone1 = true; } i = findCodeTokens(tok, "psvm", "{"); if (i < 0) i = findCodeTokens(tok, "p", "{"); if (i >= 0) { int idx = i+2; int j = findEndOfBracketPart(tok, idx)-1; List<String> contents = subList(tok, idx+1, j); //print("contents: " + sfu(contents)); tok.set(i, "public static void main(final String[] args) throws Exception"); replaceTokens(tok, idx+1, j, tok_addSemicolon(contents)); reTok(tok, i, j); quickmainDone2 = true; } return tok; } static String makeVar(String name) { AtomicInteger counter = varCountByThread.get(); if (counter == null) varCountByThread.set(counter = new AtomicInteger()); return "_" + name + "_" + getAndInc(counter); } static String makeVar() { return makeVar(""); } static List<String> rtq(List<String> tok, String id) { return runTranslatorQuick(tok, id); } static List<String> expandShortTypes(List<String> tok) { // replace <int> with <Integer> for (int i = 1; i+4 < tok.size(); i += 2) if (tok.get(i).equals("<") && litlist(">", ",").contains(tok.get(i+4))) { String type = tok.get(i+2); if (type.equals("int")) type = "Integer"; else if (type.equals("long")) type = "Long"; tok.set(i+2, type); } jreplace(tok, "O", "Object"); jreplace(tok, "S", "String"); jreplace(tok, "L", "List"); jreplace(tok, "Cl", "Collection"); // bool -> boolean if it's not a function name jreplace(tok, "bool", "boolean", new TokCondition() { public boolean get(final List<String> tok, final int i) { return neqGetOneOf(tok, i+3, "(", null); }}); jreplace(tok, "AtomicBool", "AtomicBoolean"); jreplace(tok, "AtomicInt", "AtomicInteger"); jreplace(tok, "LL< <id> >", "L<L<$3>>"); jreplace(tok, "LL< <id><<id>> >", "L<L<$3<$5>>>"); jreplace(tok, "LL<?>", "L<L<?>>"); jreplace(tok, "LL", "L<L>"); jreplace(tok, "LPt", "L<Pt>"); jreplace(tok, "Clusters< <id> >", "Map<$3, Collection<$3>>"); return tok; } static List<String> autoImports(List<String> tok) { HashSet<String> imports = new HashSet(tok_findImports(tok)); StringBuilder buf = new StringBuilder(); for (String c : standardImports()) if (!(imports.contains(c))) buf.append("import " + c + ";\n"); if (buf.length() == 0) return tok; tok.set(0, buf+tok.get(0)); return reTok(tok, 0, 1); } static List<String> tok_processIncludes(List<String> tok) { int safety = 0; while (hasCodeTokens(tok, "!", "include") && ++safety < 100) tok = tok_processIncludesSingle(tok); //tok_autoCloseBrackets(tok); return tok; } static void tok_processEarlyIncludes(List<String> tok) { int i; while ((i = jfind_check("include", tok, "!include early #<int>")) >= 0) { String id = tok.get(i+8); included.add(parseLong(id)); replaceTokens_reTok(tok, i, i+10, "\n" + cacheGet(id) + "\n"); } } static List<String> tok_processIncludesSingle(List<String> tok) { int i; while ((i = jfind_check("include", tok, "!include #<int>")) >= 0) { String id = tok.get(i+6); included.add(parseLong(id)); replaceTokens(tok, i, i+8, "\n" + cacheGet(id) + "\n"); reTok_include(tok, i, i+8); } while ((i = jfind_check("include", tok, "!include once #<int>")) >= 0) { String id = tok.get(i+8); boolean isNew = included.add(parseLong(id)); replaceTokens(tok, i, i+10, isNew ? "\n" + cacheGet(id) + "\n" : ""); reTok_include(tok, i, i+10); } return tok; } // ctex and various other error-related keyword blocks static void ctex(List<String> tok) { replaceKeywordBlock(tok, "ctex", "{ try {", "} catch (Exception __e) { throw rethrow(__e); } }"); for (String keyword : ll("null on exception", "null on error")) replaceKeywordBlock(tok, keyword, "{ try {", "} catch (Throwable __e) { return null; } }"); replaceKeywordBlock(tok, "false on exception", "{ try {", "} catch (Throwable __e) { return false; } }"); replaceKeywordBlock(tok, "try-OrError", "{ try {", "} catch (Throwable __e) { return OrError.error(__e); } }"); } static List<String> dialogHandler(List<String> tok) { return replaceKeywordBlock(tok, "dialogHandler", "new DialogHandler() {\n" + "public void run(final DialogIO io) {", "}}"); } static List<String> extendClasses(List<String> tok) { int i; while ((i = jfind(tok, "extend <id> {")) >= 0) { String className = tok.get(i+2); int idx = findCodeTokens(tok, i, false, "{"); int j = findEndOfBracketPart(tok, idx+2); String content = joinSubList(tok, idx+1, j-1); List<String> c = findInnerClassOfMain(tok, className); print("Extending class " + className); clearTokens(subList(tok, i, j+1)); if (c == null) { print("Warning: Can't extend class " + className + ", not found"); continue; } int startOfClass = indexOfSubList(tok, c); int endOfClass = startOfClass + l(c)-1; //print("Extending class " + className + " ==> " + join(subList(tok, startOfClass, endOfClass))); while (neq(tok.get(endOfClass), "}")) --endOfClass; //print("Extending class " + className + " ==> " + join(subList(tok, startOfClass, endOfClass))); tok.set(endOfClass, content + "\n" + tok.get(endOfClass)); doubleReTok(tok, i, j+1, endOfClass, endOfClass+1); } return tok; } // for ping / while ping static void forPing(List<String> tok) { int i; for (String keyword : ll("for", "fOr", "while")) while ((i = jfind(tok, keyword + " ping (")) >= 0) { int bracketEnd = findEndOfBracketPart(tok, i+4)-1; int iStatement = bracketEnd+2; int iEnd = findEndOfStatement(tok, iStatement); tok.set(i+2, ""); // turn into block if (!eq(get(tok, iStatement), "{")) { tok.set(iStatement, "{ " + tok.get(iStatement)); tok.set(iEnd-1, tok.get(iEnd-1) + " }"); } // add ping tok.set(iStatement, "{ ping(); " + dropPrefixTrim("{", tok.get(iStatement))); reTok(tok, i+2, iEnd); } } // lib 123 => !123 static void libs(List<String> tok) { int i; while ((i = jfind(tok, "lib <int>")) >= 0) { String id = tok.get(i+2); print("lib " + id); if (!libs.contains(id)) { libs.add(id); clearAllTokens(tok, i, i+3); /*tok.set(i, "!"); tok.set(i+1, "");*/ } else { print("...ignoring (duplicate)"); clearAllTokens(tok, i, i+3); reTok(tok, i, i+3); } } print("libs found: " + libs); } // sourceCodeLine() => 1234 static void sourceCodeLine(List<String> tok) { int i ; while ((i = jfind(tok, "sourceCodeLine()")) >= 0) { replaceTokens(tok, i, i+5, str(countChar(joinSubList(tok, 0, i), '\n')+1)); reTok(tok, i, i+5); } } // done before any other processing static void earlyStuff(List<String> tok) { int i; tok_processEarlyIncludes(tok); tok_scopes(tok, "autoCloseScopes" , asInclude); tok_autosemi(tok); tok_autoCloseBrackets(tok); jreplace(tok, "°", "()"); // Note: this makes the word "quine" a special operator // (unusable as a function name) while ((i = jfind(tok, "quine(")) >= 0) { int idx = findCodeTokens(tok, i, false, "("); int j = findEndOfBracketPart(tok, idx+2); tok.set(i, "new Quine"); tok.set(idx, "(" + quote(joinSubList(tok, idx+1, j-1)) + ", "); reTok(tok, i, idx+1); } jreplace_check("after", tok, "void <id> after super {", "void $2 { super.$2();"); replaceKeywordBlock(tok, "r-enter", "r { enter {", "}}"); // do this before func & voidfunc because otherwise they swallow it jreplace(tok, "enter {", "{ temp enter();"); tok_mutatorMethods(tok); // func keyword for lambdas - now automatically quines toString() if enabled replaceKeywordBlock(tok, "null", "{", "null; }"); // do func & voidfunc early to preserve original code as toString while ((i = jfind(tok, "func(")) >= 0) { int argsFrom = i+4, argsTo = findCodeTokens(tok, i, false, ")"); int idx = findCodeTokens(tok, argsTo, false, "{"); int j = findEndOfBracketPart(tok, idx); List<String> contents = subList(tok, idx+1, j-1); String returnType = "O"; if (eq(tok.get(argsTo+2), "-") && eq(tok.get(argsTo+4), ">")) returnType = tok_toNonPrimitiveTypes(joinSubList(tok, argsTo+6, idx-1)); String toString = autoQuine ? " public S toString() { ret " + quote(shorten(defaultMaxQuineLength(), trimJoin(contents))) + "; }" : ""; List<String> args = cloneSubList(tok, argsFrom-1, argsTo); tok_shortFinals(args); tok_toNonPrimitiveTypes(args); List<String> types = tok_typesOfParams(args); Object type = "O"; if (l(types) <= 3) type = "F" + l(types) + "<" + joinWithComma(types) + ", " + returnType + ">"; String body = tok_addReturn(contents); replaceTokens_reTok(tok, i, j, "new " + type + "() { public " + returnType + " get(" + trimJoin(args) + ") ctex { " + body + " }\n" + toString + "}"); } while ((i = jfind(tok, "voidfunc(")) >= 0) { int argsFrom = i+4, argsTo = findCodeTokens(tok, i, false, ")"); int idx = findCodeTokens(tok, argsTo, false, "{"); int j = findEndOfBracketPart(tok, idx); List<String> contents = subList(tok, idx+1, j-1); if (jcontains(subList(tok, argsTo+1, idx), "->")) throw fail("voidfunc with return type: " + joinSubList(tok, i, j+1)); List<String> args = cloneSubList(tok, argsFrom-1, argsTo); tok_shortFinals(args); tok_toNonPrimitiveTypes(args); List<String> types = tok_typesOfParams(args); Object type = "O"; if (l(types) <= 4) type = "VF" + l(types) + "<" + joinWithComma(types) + ">"; replaceTokens(tok, i, j, "new " + type + "() { public void get(" + trimJoin(args) + ") ctex { " + tok_addSemicolon(contents) + " }\n" + (autoQuine ? " public S toString() { ret " + quote(shorten(defaultMaxQuineLength(), trim(join(contents)))) + "; }" : "") + "}"); reTok(tok, i, j); } jreplace(tok, "func {", "func -> O {"); jreplace(tok, "f {", "f -> O {"); // swing -> S { ... } => swing(func -> S { ... }) while ((i = jfind(tok, "swing ->")) >= 0) { int bracket = findCodeTokens(tok, i, false, "{"); int j = findEndOfBracketPart(tok, bracket); tok.set(i, "swing(func"); tok.set(j-1, "})"); reTok(tok, i, j); } tok_qFunctions(tok); jreplace(tok, "func fullToString {", "func -> O fullToString {"); for (String keyword : ll(/*"f",*/ "func")) { while ((i = jfind(tok, keyword + " ->", new TokCondition() { public boolean get(final List<String> tok, final int i) { return isIdentifier(_get(tok, i+7)); // avoid lambda declaration like: f -> { ... } }})) >= 0) { // I think there is a bug here for something like func -> x { new x { } } int idx = findCodeTokens(tok, i, false, "{"); int j = findEndOfBracketPart(tok, idx); String returnType = tok_toNonPrimitiveTypes(joinSubList(tok, i+6, idx-1)); int quineLength = defaultMaxQuineLength(); if (eq(lastJavaToken(returnType), "fullToString")) { quineLength = Integer.MAX_VALUE; returnType = dropLastJavaTokenAndSpacing(returnType); } List<String> contents = subList(tok, idx+1, j-1); replaceTokens(tok, i, j, "new F0<" + returnType + ">() { public " + returnType + " get() ctex { " + tok_addReturn(contents) + " }\n" + (autoQuine ? " public S toString() { ret " + quote(shorten(quineLength, trimJoin(contents))) + "; }" : "") + "}"); reTok(tok, i, j); } } while ((i = jfind(tok, "time repeat * {")) >= 0) { int j = findEndOfBlock(tok, i+6)-1; tok.set(i, "time {"); tok.set(j, "}}"); reTok(tok, i, j+1); } // do this before "m {" stuff because "repeat m" [doesn't seem to work yet though) while ((i = findCodeTokens(tok, "repeat", "*", "{")) >= 0) { String v = makeVar("repeat"); tok.set(i, "for (int " + v + " = 0; " + v + " < " + tok.get(i+2) + "; " + v + "++)"); tok.set(i+2, ""); reTok(tok, i, i+3); } } static void throwFailEtc(List<String> tok) { boolean anyChange = false; for (int i = 1; i+4 < l(tok); i += 2) if (eqOneOf(get(tok, i+2), "fail", "todo") && eq(get(tok, i+4), "(") && !eqOneOf(get(tok, i), "throw", "RuntimeException", "return", "f", "function", ".", "void", "main", "Throwable")) { tok.set(i+2, "throw " + tok.get(i+2)); anyChange = true; } if (anyChange) reTok(tok); } static void namedThreads(List<String> tok) { for (int i = 0; i < 100; i++) { int idx = findCodeTokens(tok, "thread", "<quoted>", "{"); if (idx < 0) idx = findCodeTokens(tok, "thread", "<id>", "{"); if (idx < 0) break; int j = findEndOfBracketPart(tok, idx+4); String tName = tok.get(idx+2); String pre = "startThread(" + tName + ", r { "; String post = "})"; if (!tok_tokenLeftOfExpression(tok, idx-2)) post += ";"; tok.set(idx, pre); tok.set(idx+2, ""); tok.set(idx+4, ""); tok.set(j-1, post); //print(join(subList(tok, idx, j))); reTok(tok, idx, j); } } static void rNamedThread(List<String> tok) { for (int i = 0; i < 100; i++) { int idx = findCodeTokens(tok, "r", "-", "thread", "<quoted>", "{"); if (idx < 0) idx = findCodeTokens(tok, "r", "-", "thread", "<id>", "{"); if (idx < 0) break; int j = findEndOfBracketPart(tok, idx+8); String tName = tok.get(idx+6); String pre = "r { thread " + tName + " {"; String post = "}}"; replaceTokens(tok, idx, idx+9, pre); tok.set(j-1, post); reTok(tok, idx, j); } } static void threads(List<String> tok) { replaceKeywordBlock(tok, "daemon", "startDaemonThread(r {", "});"); //replaceKeywordBlock(tok, "thread", "startThread(r {", "});"); // now enclose in { } to allow using like "void bla() thread { ... }" - if it's not used as an expression replaceKeywordBlock_dyn2_legacy(tok, "thread", new Object() { // don't use func here, it can't be transpiled String[] get (List<String> tok, int iOpening, int iClosing) { // is the thread clause used as an expression? boolean isExpression = tok_tokenLeftOfExpression(tok, iOpening-4); return new String[] { (isExpression ? "" : "{ ") + "startThread(r {", "})" + (isExpression ? "" : "; }") }; } }); } static Map<String, String> sf; // standard standard functions (haha) static Boolean _761ok; static List<String> standardFunctions(List<String> tok) { if (sf == null) { String _761 = cacheGet("#761"); if (_761ok == null) _761ok = isBracketHygienic(_761); assertTrue("Whoa! #761 truncated?", _761ok); List<String> standardFunctions = concatLists( (List) loadVariableDefinition(_761, "standardFunctions"), (List) loadVariableDefinition(cacheGet("#1006654"), "standardFunctions")); sf = new HashMap(); for (String x : standardFunctions) { String[] f = x.split("/"); sf.put(f[1], f[0]); } } Map<String, String> sfMap = combinedMap(extraStandardFunctions, sf); for (int i = 0; ; i++) { print("Looking for required functions"); Set<String> defd = new HashSet(findFunctions(tok)); int j; while ((j = jfind(tok, "should not include function *.")) >= 0) { String fname = tok.get(j+8); shouldNotIncludeFunction.add(fname); clearAllTokens(subList(tok, j, j+12)); } while ((j = jfind(tok, "do not include function *.")) >= 0) { String fname = tok.get(j+8); doNotIncludeFunction.add(fname); clearAllTokens(subList(tok, j, j+12)); } while ((j = jfind(tok, "need latest <id>.")) >= 0) { String t = tok.get(j+4); needLatest.add(t); doNotIncludeClass.remove(t); clearAllTokens(subList(tok, j, j+8)); } grabImportedStaticFunctions(tok); doNotIncludeFunction.removeAll(needLatest); // changes tok Set<String> invocations = findFunctionInvocations(tok, sfMap, hardFunctionReferences, defd, true, mainClassName()); /*if (invocations.contains("str")) print("==STR==" + join(tok) + "==STR==");*/ if (!cic(definitions, "leanMode")) invocations.addAll(functionsToAlwaysInclude); //print("Functions invoked: " + structure(invocations)); List<String> needed = diff(invocations, defd); for (String f : doNotIncludeFunction) needed.remove(f); if (needed.isEmpty()) break; print("Adding functions: " + join(" " , needed)); HashSet neededSet = new HashSet(needed); Collection<String> bad = setIntersection(neededSet, shouldNotIncludeFunction); if (nempty(bad)) { String msg = "INCLUDING BAD FUNCTIONS: " + sfu(bad); print(msg); print(join(tok)); throw fail(msg); } List<String> added = new ArrayList(); List<Future<String>> parts = new ArrayList(); List<String> preload = new ArrayList(); for (String x : needed) if (sfMap.containsKey(x)) preload.add(sfMap.get(x)); print("Preloading: " + preload); cachePreload(preload); for (String x : cloneList(needed)) { if (defd.contains(x)) continue; String id = sfMap.get(x); if (id == null) { print("Standard function " + x + " not found."); needed.remove(x); continue; } //print("Adding function: " + x + " (" + id + ")"); String function = cacheGet(id) + "\n"; //if (("\n" + function).contains("\n!")) print("Warning: " + id + " contains translators."); if (cacheStdFunctions) { long _id = psI(id); CachedInclude ci = cachedIncludes.get(_id); if (ci == null) { cachedIncludes.put(_id, ci = new CachedInclude(_id)); //println("Caching include " + _id + ", l=" + l(cachedIncludes)); } function += "\n"; final String _function = function; if (neq(ci.javax, function)) { print("Compiling function: " + x); ci.javax = function; ci.java = executor.submit(new Callable<String>() { public String call() { // We assume that variables made with makeVar() will always be local to some block varCountByThread.set(null); return join(localStuff1(jtok(_function))); } }); ci.realJava = null; } parts.add(ci.javaFuture()); } else parts.add(nowFuture(function)); added.add(x); Collection<String> newFunctions = new HashSet(findFunctionDefs(javaTok(function))); defd.addAll(newFunctions); for (String f : newFunctions) if (!addedFunctions.add(f)) { printSources(tok); throw fail("Trying to add function " + f + " again - main class syntax broken!"); } } print("Getting " + nParts(parts)); String text = lines(getAllFutures(parts)); print("Including " + nParts(parts)); tok = includeInMainLoaded(tok, text); // defd = new HashSet(findFunctions(tok)); //print("Functions added: " + joinWithSpace(added)); for (String x : needed) if (!defd.contains(x)) { print(join(tok)); throw fail("Function not defined properly: " + x); } //print("Iteration " + (i+2)); print("Processing definitions"); dontPrint("definitions"); tok_definitions(tok); dontPrint("ifndef"); tok_ifndef(tok); dontPrint("ifdef"); tok_ifdef(tok); if (i >= 1000) throw fail("Too many iterations"); } return tok; } // TODO: skip functions defined in inner classes! static List<String> findFunctions(List<String> tok) { //ret findFunctionDefinitions(join(findMainClass(tok))); return findFunctionDefs(findMainClass(tok)); } static String cacheGet(String snippetID) { snippetID = formatSnippetID(snippetID); String text = snippetCache.get(snippetID); if (text == null) { text = loadSnippet(snippetID); // very early processing/checks for includes if (hasUnclosedStringLiterals(text)) throw fail("Unclosed string literals in " + snippetID); if (regexpContains("\\bscope\\b", text)) { List<String> tok = javaTok(text); tok_scopes(tok, "autoCloseScopes" , true); text = join(tok); } snippetCache.put(snippetID, text); } return text; } static void cachePreload(Collection<String> ids) { List<String> needed = new ArrayList(); for (String id : ids) if (!snippetCache.containsKey(formatSnippetID(id))) needed.add(formatSnippetID(id)); if (l(needed) > 1) { List<String> texts = loadSnippets(needed); for (int i = 0; i < l(needed); i++) if (texts.get(i) != null) snippetCache.put(needed.get(i), texts.get(i)); } } static List<String> jtok(List<String> tok) { return jtok(join(tok)); } static List<String> jtok(String s) { return indexTokenList(javaTok(s)); } static HashSet<String> haveClasses_actual(List<String> tok) { HashSet<String> have = new HashSet(); for (List<String> c : innerClassesOfMain(tok)) have.add(getClassDeclarationName(c)); return have; } static HashSet<String> haveClasses_addImported(List<String> tok, HashSet<String> have) { return haveClasses_addImported(tok, have, true); } static HashSet<String> haveClasses_addImported(List<String> tok, HashSet<String> have, boolean mainLevel) { have.addAll(tok_importedClassNames(tok, mainLevel ? (__18, __19) -> onImportFound(__18, __19) : null)); have.addAll(usualJavaClassNames()); // for S => S.class return have; } // works on Java level (no "sclass" etc) // returns list of classes we have (useful for other processing) static HashSet<String> addStandardClasses_v2(List<String> tok) { if (lclasses == null) { String sc = cacheGet("#1003674"); lclasses = new ArrayList(); for (String line : tlft_j(sc)) { int idx = line.indexOf('/'); lclasses.addAll(ll(line.substring(0, idx), line.substring(idx+1))); } } List<String> definitions = lclasses; for (int safety = 0; safety < 10; safety++) { HashSet<String> have = haveClasses_actual(tok); haveClasses_addImported(tok, have); have.addAll(keys(rewrites)); int j; while ((j = jfind(tok, "should not include class *.")) >= 0) { String cname = tok.get(j+8); shouldNotIncludeClass.add(cname); clearAllTokens(subList(tok, j, j+12)); } while ((j = jfind(tok, "do not include class *.")) >= 0) { String name = tok.get(j+8); if (!needLatest.contains(name)) doNotIncludeClass.add(name); clearAllTokens(subList(tok, j, j+12)); } Map<String, String> need = new HashMap(); Set<String> snippets = new HashSet(); Set<String> idx = tokenIndexWithoutIfclass_forStdClasses(tok); while ((j = jfind(tok, "please include class *.")) >= 0) { String cname = tok.get(j+6); idx.add(cname); clearAllTokens(subList(tok, j, j+10)); } for (int i = 0; i+1 < l(definitions); i += 2) { String className = definitions.get(i); String snippetID = fsI(definitions.get(i+1)); if (idx.contains(className) && !have.contains(className) && snippets.add(snippetID)) need.put(className, snippetID); } if (hasDef("SymbolAsString")) { print("Have SymbolAsString."); if (need.containsKey("Symbol")) { print("Have Symbol."); need.remove("Symbol"); } } else print("No SymbolAsString."); removeAll(need, doNotIncludeClass); if (empty(need)) return have; for (String className : keys(need)) if (shouldNotIncludeClass.contains(className)) { String msg = "INCLUDING BAD CLASS: " + className; print(msg); print(join(tok)); throw fail(msg); } cachePreload(values(need)); List<Pair<String, CachedInclude>> parts = new ArrayList(); // class name, Java code print("Adding classes: " + joinWithSpace(keys(need))); for (String className : keys(need)) { if (have.contains(className)) continue; // intermittent add String snippetID = need.get(className); //print("Adding class " + className + " / " + snippetID); snippetID = fsI(snippetID); String text = cacheGet(snippetID) + "\n"; assertTrue(cacheStdClasses); long _id = psI(snippetID); CachedInclude ci = cachedIncludes.get(_id); if (ci == null) cachedIncludes.put(_id, ci = new CachedInclude(_id)); if (neq(ci.javax, text)) { print("Compiling class: " + className); ci.javax = text; ci.java = executor.submit(new Callable<String>() { public String call() { // We assume that variables made with makeVar() will always be local to some block varCountByThread.set(null); return join(localStuff1(jtok(text))); } }); ci.realJava = null; } parts.add(pair(className, ci)); } StringBuilder buf = new StringBuilder(); for (Pair<String, CachedInclude> p : parts) { String className = p.a; List<String> ct = javaTok(p.b.java()); Map<String, String> rewritten = new HashMap(); tok_findAndClearRewrites(ct, rewritten); if (rewritten.containsKey(className)) have.add(className); for (List<String> c : allClasses(ct)) { String name = getClassDeclarationName(c); have.add(name); } haveClasses_addImported(ct, have, false); if (!have.contains(className)) throw fail("Wrongly defined class: " + className + " / " + p.b.snippetID + "\n\n" + p.b.java()); if (!addedClasses.add(className)) { printSources(tok); throw fail("Trying to add class " + className + " again - main class syntax broken!"); } buf.append(p.b.java()); } // for part tok = includeInMainLoaded(tok, str(buf)); } throw fail("safety 10"); } static Set<String> expandableClassNames = lithashset("BigInteger"); // no reTok - leaves tok dirty // magically append ".class" to class name references static void expandClassReferences_lazy(List<String> tok, Set<String> classNames) { expandClassReferences_lazy(tok, classNames, null); } static void expandClassReferences_lazy(List<String> tok, Set<String> classNames, List<IntRange> reToks) { for (int i = 3; i+2 < l(tok); i += 2) { String t = tok.get(i); // skip implements/extends/throws lists if (eqOneOf(t, "implements", "extends", "throws")) { i = tok_endOfImplementsList(tok, i); continue; } if (classNames.contains(t) || expandableClassNames.contains(t)) { String s = tok.get(i-2); t = tok.get(i+2); // Now s is token before class name, t is token after class name // TODO: This whole logic ain't very good // (Hard to distinguish between "Int.class" as an argument // and "Int" as a type parameter.) if (eqOneOf(s, "instanceof", "new", ".", "<", ">", "/", "nu")) continue; if (eq(t, ":")) continue; // e.g. String::concat if (isInteger(s)) continue; if (isIdentifier(s) && !eqOneOf(s, "ret", "return")) continue; if (eq(t, ",") && isIdentifier(get(tok, i+4)) && eqGet(tok, i+6, ">")) continue; // e.g. T3<L<S>, S, S> if (eq(s, ",") && isIdentifier(get(tok, i-4)) && (eqGet(tok, i-6, "<") || eqGet(tok, i-6, ",") && isIdentifier(get(tok, i-8)) && eqGet(tok, i-10, "<"))) continue; // e.g. T3<S, S, S> or IF3<S, S, S, S> if (eq(s, ",") && eqOneOf(_get(tok, i-6), "implements", "throws")) continue; // check for cast if (eq(s, "(") && eq(t, ")") && i >= 5) { if (!eqOneOf(get(tok, i+4), "{", ";")) { String x = tok.get(i-4); if (!isIdentifier(x)) continue; if (eqOneOf(x, "ret", "return")) continue; } } // check following token if (eqOneOf(t, ",", ")", ";", ":", "|")) { tok.set(i, tok.get(i) + ".class"); { if (reToks != null) reToks.add(intRange(i, i+1)); } } } } } static void expandClassReferences(List<String> tok, Set<String> classNames) { List<IntRange> reToks = new ArrayList(); expandClassReferences_lazy(tok, classNames, reToks); reTok_multi(tok, reToks); } // "<id>/<ClassName>" => "((ClassName) <id>)" static void slashCasts(List<String> tok, final Set<String> classNames) { /*jreplace(tok, "<id>/<id>", "(($3) $1)", tokcondition { ret classNames.contains(tok.get(i+5)); });*/ int n = l(tok)-4; for (int i = 1; i < n; i += 2) if (tok.get(i+2).equals("/") && isIdentifier(tok.get(i)) && classNames.contains(tok.get(i+4))) replaceTokens_reTok(tok, i, i+5, "((" + tok.get(i+4) + ") " + tok.get(i) + ")"); } // "<ClassName>(...)" => "new <ClassName>(...)" // doesn't work at beginning of statement as we can't easily // distinguish it from a constructor declaration. static void newWithoutNew(List<String> tok, final Set<String> classNames) { TokCondition cond = newWithoutNew_condition(classNames); jreplace(tok, "<id>(", "new $1(", cond); // just two cases with type args for now jreplace(tok, "<id><<id>>(", "new $1<$3>(", cond); jreplace(tok, "<id><>(", "new $1<>(", cond); } static TokCondition newWithoutNew_condition(final Set<String> classNames) { return new TokCondition() { public boolean get(final List<String> tok, final int i) { if (!classNames.contains(tok.get(i+1))) return false; String prev = _get(tok, i-1); boolean ok = //!(eqGet(tok, i-3, "ifclass") && isIdentifier(prev)) nempty(prev) // discarded ifclass && (eq(prev, ">") ? eqGet(tok, i-3, "-") : neqOneOf(prev, "new", ";", "}", "{", "public", "protected", "private", ".")); //print("newWithoutNew: checking " + struct(subList(tok, i-3, i+2)) + " => " + ok); return ok; }}; } static boolean processConceptsDot(List<String> tok) { boolean anyChange = false, change; do { change = false; for (int i : jfindAll(tok, "concepts.")) if (contains(get(tok, i+3), "\n")) { replaceTokens(tok, i, i+3, "!" + "include once #1004863 // Dynamic Concepts"); reTok(tok, i, i+3); change = anyChange = true; break; } } while (change); return anyChange; } static void caseAsVariableName(List<String> tok) { if (!tok.contains("case")) return; for (int i = 1; i+2 < l(tok); i += 2) { String t = tok.get(i+2); if (tok.get(i).equals("case") && !(t.startsWith("'") || isInteger(t) || isIdentifier(t) || isQuoted(t))) tok.set(i, "_case"); } } static void continueAsFunctionName(List<String> tok) { jreplace(tok, "continue(", "_continue("); } // f bla => "bla" - and "please include function bla." static void functionReferences(List<String> tok) { int i; jreplace_dyn(tok, "f-thread <id>", new F2<List<String>, Integer, Object>() { public Object get(List<String> tok, Integer cIdx) { try { return "dynamicCallableMC_thread(" + quote(tok.get(cIdx+6)) + ")"; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "\"dynamicCallableMC_thread(\" + quote(tok.get(cIdx+6)) + \")\""; }}); String keyword = "f"; while ((i = jfind(tok, keyword + " <id>", new TokCondition() { public boolean get(final List<String> tok, final int i) { return !eqOneOf(tok.get(i+3), "instanceof", "default"); }})) >= 0) { String f = tok.get(i+2); clearTokens(tok, i, i+2); tok.set(i+2, quote(f)); reTok(tok, i, i+2); tok.set(l(tok)-1, last(tok) + "\nplease include function " + f + "."); reTok(tok, l(tok)-1, l(tok)); } // r|rThread|rEnter|rThreadEnter|rEnterThread fname => r|rThread|... { fname() } while ((i = jfindOneOf_cond(tok, new TokCondition() { public boolean get(final List<String> tok, final int i) { return !eq(tok.get(i+3), "instanceof") && !eq(_get(tok, i-1), "cast"); }}, "r <id>", "rThread <id>", "rEnter <id>", "rThreadEnter <id>", "rEnterThread <id>")) >= 0) { String f = tok.get(i+2); replaceTokens(tok, i, i+3, tok.get(i) + " { " + f + "(); }"); reTok(tok, i, i+3); } // dm_q fname => r_dm_q(r fname) jreplace(tok, "dm_q <id>", "r_dm_q(r $2)"); // vf<S> fname => voidfunc(S s) { fname(s) } jreplace(tok, "vf<<id>> <id>", "voidfunc($3 a) { $5(a) }"); // vf<L<S>> fname => voidfunc(L<S> a) { fname(a) } jreplace(tok, "vf<<id><<id>>> <id>", "voidfunc($3<$5> a) { $8(a) }"); // construct<S> Entry => func(S s) -> Entry { new Entry(s) } jreplace(tok, "construct<<id>> <id>", "func($3 a) -> $5 { new $5(a) }"); // f<S> fname => func -> S { fname() } jreplace(tok, "f<<id>> <id>", "func -> $3 { $5() }"); // f<S, S> fname => func(S x) -> S { fname(x) } jreplace(tok, "f<<id>, <id>> <id>", "func($3 x) -> $5 { $7(x) }"); // f<S, L<S>> fname => func(S x) -> L<S> { fname(x) } jreplace(tok, "f<<id>, <id><<id>>> <id>", "func($3 x) -> $5 $6 $7 $8 { $10(x) }"); // f<L<S>, S> fname => func(L<S> x) -> S { fname(x) } jreplace(tok, "f<<id><<id>>, <id>> <id>", "func($3 $4 $5 $6 x) -> $8 { $10(x) }"); // f<S, L<S>, S> fname => func(S x, L<S> y) -> S { fname(x, y) } jreplace(tok, "f<<id>, <id><<id>>, <id>> <id>", "func($3 x, $5 $6 $7 $8 y) -> $10 { $12(x, y) }"); // if1 fname => a -> fname(a) // ivf1 fname => a -> fname(a) for (String _keyword : ll("if1", "ivf1")) jreplace_dyn(tok, _keyword + " <id>", new F2<List<String>, Integer, String>() { public String get(List<String> tok, Integer i) { try { String var = makeVar(); return var + " -> " + tok.get(i+2) + "(" + var + ")"; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "S var = makeVar();\r\n ret var + \" -> \" + tok.get(i+2) + \"(\" + var + \")\";"; }}); } static void quicknu(List<String> tok) { jreplace(tok, "nu <id>(", "nu($2.class, "); // not needed anymore jreplace(tok, "nu <id>", "new $2"); } // fill variable innerClasses_list static void innerClassesVar(List<String> tok, Set<String> have) { int i = jfind_check("myInnerClasses_list", tok, ">myInnerClasses_list;"); if (i < 0) return; tok.set(i+4, "=litlist(\n" + joinQuoted(", ", have) + ");"); reTok(tok, i+4, i+5); } // fill variable innerClasses_list static void fillVar_transpilationDate(List<String> tok) { int i = jfind_check("myTranspilationDate_value", tok, "long myTranspilationDate_value;"); if (i < 0) return; tok.set(i+4, " = " + now() + "L;"); reTok(tok, i+4, i+5); } static boolean ifclass_reTokImmediately = false; static boolean ifclass_noReTok = true; // process ifclass x ... endif blocks static void tok_ifclass(List<String> tok, Set<String> have) { tok_conditionals(tok, "ifclass", "endif", id -> contains(have, id), ifclass_reTokImmediately, ifclass_noReTok); } // returns number of changes static int tok_conditionals(List<String> tok, String keyword, String keywordEnd, IF1<String, Boolean> pred, boolean reTokImmediately, boolean noReTok) { int changes = 0; if (tok instanceof IContentsIndexedList) { int[] l = ((IContentsIndexedList) tok).indicesOf(keyword); for (int j = l(l)-1; j >= 0; j--) { int i = l[j]; if (isIdentifier(get(tok, i+2))) { processConditional(tok, i, keyword, keywordEnd, pred, reTokImmediately && !noReTok); ++changes; } } } else { if (!tok.contains(keyword)) return changes; int i = l(tok); while ((i = rjfind(tok, 1, i-1, keyword + " <id>")) >= 0) { ++changes; processConditional(tok, i, keyword, keywordEnd, pred, reTokImmediately && !noReTok); } } if (changes != 0 && !reTokImmediately && !noReTok) reTok(tok); //print(keyword + ": " + nChanges(changes)); return changes; } static void processConditional(List<String> tok, int i, String keyword, String keywordEnd, IF1<String, Boolean> pred, boolean reTokImmediately) { int j = jfind(tok, i+4, keywordEnd); if (j < 0) j = l(tok)-1; String name = tok.get(i+2); boolean has = pred.get(name); //print(keyword + " " + name + " => " + has); if (has) { clearTokens_maybeReTok(tok, j, j+1, reTokImmediately); clearTokens_maybeReTok(tok, i, i+3, reTokImmediately); } else clearTokens_maybeReTok(tok, i, j+1, reTokImmediately); // safer than before } // set flag *. static void tok_definitions(List<String> tok) { int i; while ((i = jfind_check("flag", tok, "set flag <id>.")) >= 0) { String fname = tok.get(i+4); print("Setting flag " + fname); definitions.add(fname); if (eqic(fname, "debug_jreplace")) debug_jreplace = true; clearAllTokens(subList(tok, i, i+8)); } while ((i = jfind_check("flag", tok, "unset flag <id>.")) >= 0) { String fname = tok.get(i+4); print("Unsetting flag " + fname); definitions.remove(fname); clearAllTokens(subList(tok, i, i+8)); } } // rewrite <id> [=|with|to] <definition> // - a global version of "replace <id> with" // new version - may not work yet /*svoid tok_findAndClearRewrites(LS tok, SS newlyDefined default null) { tok_findRewrites(tok, newlyDefined, f -> { print("Have rewrite: " + f.token + " => " + f.replacement()); clearTokens(f.tok, f.startCIdx(), f.endNIdx()); }); }*/ // rewrite <id> [=|with|to] <definition> // - a global version of "replace <id> with" // old version (works) static void tok_findAndClearRewrites(List<String> tok) { tok_findAndClearRewrites(tok, null); } static void tok_findAndClearRewrites(List<String> tok, Map<String, String> newlyDefined) { int i; while ((i = jfind(tok, "rewrite <id>", (_tok, nIdx) -> eqGetOneOf(_tok, nIdx+5, "with", "=", "to"))) >= 0) { String token = tok.get(i+2); int repStart = i+6; int repEnd = smartIndexOf(tok, repStart, "."); String replacement = joinSubList(tok, repStart, repEnd-1); clearTokens(tok, i, repEnd+1); mapPut(newlyDefined, token, replacement); rewrites.put(token, replacement); print("Have rewrite: " + token + " => " + replacement); } } static void tok_processRewrites(List<String> tok) { for (String token : keys(rewrites)) jreplace(tok, token, rewrites.get(token)); } // extend *. (set base class of main class) static void tok_extend(List<String> tok) { int i; while ((i = jfind(tok, "extend <id>.")) >= 0) { mainBaseClass = tok.get(i+2); clearAllTokens(tok, i, i+7); } } // process ifndef x ... endifndef blocks static void tok_ifndef(List<String> tok) { tok_conditionals(tok, "ifndef", "endifndef", id -> !definitions.contains(id), true, false); } // process ifdef x ... endifdef blocks static void tok_ifdef(List<String> tok) { tok_conditionals(tok, "ifdef", "endifdef", id -> definitions.contains(id), true, false); } static void conceptDeclarations(List<String> tok) { for (String kw : ll("concept", "sconcept")) { Object cond = new TokCondition() { public boolean get(final List<String> tok, final int i) { tok_addFieldOrder(tok, i+1); return true; }}; boolean re = false; if (jreplace(tok, kw + " <id> {", "static class $2 extends Concept {", cond)) re = true; if (jreplace(tok, kw + " <id> implements", "static class $2 extends Concept implements", cond)) re = true; if (jreplace(tok, kw + " <id>", "static class $2", cond)) re = true; if (re) reTok(tok); } } static void shortenedSubconcepts(List<String> tok) { jreplace(tok, "<id> > <id> {", "concept $3 extends $1 {", new TokCondition() { public boolean get(final List<String> tok, final int i) { boolean b = (i == 0 || tok.get(i).contains("\n")) || eq(_get(tok, i-1), "abstract"); // only at beginning of line or after "abstract" //print("subconcept " + b + ": " + structure(subList(tok, i-1, i+5))); return b; }}); } // -slightly experimental // -do calculation in another thread, then return to AWT thread // -must be placed in a block // -transforms rest of block static void unswing(List<String> tok) { int i; while ((i = jfind(tok, "unswing {")) >= 0) { int idx = i+2; int closingBracket = findEndOfBracketPart(tok, idx)-1; int endOfOuterBlock = findEndOfBracketPart(tok, closingBracket)-1; tok.set(i, "thread"); tok.set(closingBracket, " awt {"); tok.set(endOfOuterBlock, "}}}"); reTok(tok, closingBracket-1, endOfOuterBlock+1); } } // -Syntax: lock theLock; // -lock a lock, unlock at end of current block with finally static void lockBlocks(List<String> tok) { int i; while ((i = jfind(tok, "lock <id>", new TokCondition() { public boolean get(final List<String> tok, final int i) { return neq(tok.get(i+3), "instanceof"); }})) >= 0) { int semicolon = findEndOfStatement(tok, i)-1; String var = makeVar(); int endOfOuterBlock = findEndOfBracketPart(tok, semicolon)-1; replaceTokens(tok, i, semicolon+1, "Lock " + var + " = " + joinSubList(tok, i+2, semicolon-1) + "; lock(" + var + "); try {"); tok.set(endOfOuterBlock, "} finally { unlock(" + var + "); } }"); reTok(tok, i, endOfOuterBlock+1); } } // -Syntax: temp Bla bla = bla(); // -expands to try(Bla bla = bla()) { ... } with rest of block inside static void tempBlocks(List<String> tok) { int i; jreplace_dyn(tok, "temp (<id>) <id>", (_tok, cIdx) -> { String var = makeVar(), type = tok.get(cIdx+4), firstTokenOfExpr = tok.get(cIdx+8); return ("temp " + type + " " + var + " = cast " + firstTokenOfExpr); }); jreplace(tok, "temp <id> =", "temp var $2 ="); while ((i = jfind(tok, "temp <id>")) >= 0) { int semicolon = findEndOfStatement(tok, i)-1; int endOfOuterBlock = findEndOfBracketPart(tok, semicolon)-1; List<String> sub = subList(tok, i-1, semicolon); int eq = subList(sub, 0, smartIndexOfOneOf(sub, "{", "(")).indexOf("="); String var; if (eq >= 0) var = sub.get(eq-2); else { // no var name, e.g. temp newThoughtSpace(); var = makeVar(); tok.set(i+2, "AutoCloseable " + var + " = " + tok.get(i+2)); } //tok.set(i, "try ("); //tok.set(semicolon, ") {"; //tok.set(endOfOuterBlock, "}}"); tok.set(i, ""); tok.set(semicolon, "; try {"); tok.set(endOfOuterBlock, "} finally { _close(" + var + "); }}"); reTok(tok, i, endOfOuterBlock+1); } } static void forgetCachedIncludes() { cachedIncludes.clear(); } // TODO: when to do this / merge contents if there are multiple transpilers? static void cleanMeUp() { for (CachedInclude ci : values(cachedIncludes)) ci.clean(); vmKeepWithProgramMD5_save("cachedIncludes"); } static void printSources(List<String> tok) { String src = join(tok); print("----"); print(src); print("----"); print("Bracket hygiene: " + testBracketHygiene2(src)); } static void tok_quickInstanceOf(List<String> tok, final Set<String> haveClasses) { if (!quickInstanceOfEnabled) return; // "x << X" or "x >> X" => "x instanceof X" for (String op : ll("<<", ">>")) jreplace(tok, "<id> " + op + " <id>", "$1 instanceof $4", new TokCondition() { public boolean get(final List<String> tok, final int i) { return haveClasses.contains(tok.get(i+7)) && !eqOneOf(tok.get(i-1), "<", "extends", "implements"); }}); } static boolean hasDef(String s) { return definitions.contains(s); } static void tok_shortFinals(List<String> tok) { jreplace(tok, "fS", "final S"); jreplace(tok, "fO", "final O"); jreplace(tok, "fL", "final L"); jreplace(tok, "fMap", "final Map"); jreplace(tok, "fRunnable", "final Runnable"); jreplace(tok, "f int", "final int"); } static void tok_mainClassNameAndPackage(List<String> tok) { int i; if ((i = jfind(tok, "mainClassName <id>")) >= 0) { mainClassName = tok.get(i+2); if (eqGet(tok, i+4, ".") && isIdentifier(get(tok, i+6))) { mainPackage = mainClassName; mainClassName = tok.get(i+6); clearTokensAndReTok(tok, i, i+7); } else clearTokensAndReTok(tok, i, i+3); } if ((i = jfind(tok, "mainPackage <id>")) >= 0) { int j = i+2; while (subListEquals(tok, j+1, "", ".", "") && isIdentifier(get(tok, j+4))) j += 4; mainPackage = joinSubList(tok, i+2, j+1); clearTokens_reTok(tok, i, j+1); } } static void defineMapLikes(List<String> tok) { int i; while ((i = jfind(tok, "mapLike <id>")) >= 0) { mapLikeFunctions.add(printIf(printMapLikes(), "mapLike", tok.get(i+2))); clearTokens_reTok(tok, i, i+2); } } static void defineLambdaMapLikes(List<String> tok) { int i; while ((i = jfind(tok, "lambdaMapLike <id>")) >= 0) { lambdaMapLikeFunctions.add(printIf(printMapLikes(), "lambdaMapLike", tok.get(i+2))); clearTokens_reTok(tok, i, i+2); } } static void defineCurry1Likes(List<String> tok) { int i; while ((i = jfind(tok, "curry1Like <id>")) >= 0) { curry1LikeFunctions.add(printIf(printMapLikes(), "curry1Like", tok.get(i+2))); clearTokens_reTok(tok, i, i+2); } } static void defineMapMethodLikes(List<String> tok) { int i; while ((i = jfind(tok, "mapMethodLike <id>")) >= 0) { mapMethodLikeFunctions.add(printIf(printMapLikes(), "mapMethodLike", tok.get(i+2))); clearTokens_reTok(tok, i, i+2); } } // functions that work like "nu" syntactically (accept a class as "super-first" parameter [left of the bracket]) static void defineNuLikes(List<String> tok) { int i; while ((i = jfind(tok, "nuLike <id>")) >= 0) { nuLikeFunctions.add(printIf(printMapLikes(), "nuLike", tok.get(i+2))); clearTokens_reTok(tok, i, i+2); } } static void defineXLikes(List<String> tok, String keyword, Set<String> xLikeFunctions) { int i; while ((i = jfind(tok, keyword + " <id>")) >= 0) { xLikeFunctions.add(printIf(printMapLikes(), keyword, tok.get(i+2))); clearTokens_reTok(tok, i, i+2); } } static void defineExtraSF(List<String> tok) { int i; IntRange reTok = null; while ((i = jfind(tok, "function <id> is in *.")) >= 0) { extraStandardFunctions.put(tok.get(i+2), fsI(unquote(tok.get(i+8)))); clearTokens(tok, i, i+12); reTok = combineIntRanges(reTok, intRange(i, i+12)); } reTok(tok, reTok); } static boolean tok_applyAllXLikeFunctions(List<String> tok) { List<IntRange> reToks = new ArrayList(); for (int i : jfindAll(tok, "<id> <id> (")) { String f = tok.get(i), arg = tok.get(i+2), replacement = null; if (contains(mapLikeFunctions, f)) replacement = (f + "(f " + arg + ","); else if (contains(lambdaMapLikeFunctions, f)) replacement = (f + "(lambda1 " + arg + ","); else if (contains(curry1LikeFunctions, f)) replacement = (f + "(lambda2 " + arg + ","); else if (contains(mapMethodLikeFunctions, f)) replacement = (f + "(" + (quote(arg)) + ","); else if (contains(nuLikeFunctions, f)) replacement = (f + "(" + arg + ".class,"); else if (contains(getLikeFunctions, f)) replacement = (f + "(lambdaField " + arg + ","); else if (contains(lambdaMethod0LikeFunctions, f)) replacement = (f + "(methodLambda0 " + arg + ","); else if (contains(lambda0LikeFunctions, f)) replacement = (f + "(lambda0 " + arg + ","); if (replacement != null) replaceTokens_reTokLater(tok, reToks, i, i+5, replacement + " "); } reTok_multi(tok, reToks); return nempty(reToks); } /*sbool tok_applyMapLikeFunctions(LS tok, final Set<S> mapLikeFunctions) { // map funcname(...) => map(f funcname, ...) // filter funcname(...) => filter(f funcname, ...) // ... ret jreplace(tok, "<id> <id>(", "$1(f $2,", func(L<S> tok, int i) -> bool { contains(mapLikeFunctions, tok.get(i+1)) }); }*/ /*sbool tok_applyLambdaMapLikeFunctions(LS tok, final Set<S> lambdaMapLikeFunctions) { // mapNonNulls funcname(...) => mapNonNulls(lambda1 funcname, ...) // mapKeysAndValues funcname(...) => mapKeysAndValues(lambda1 funcname, ...) // ... ret jreplace(tok, "<id> <id>(", "$1(lambda1 $2,", func(L<S> tok, int i) -> bool { contains(lambdaMapLikeFunctions, tok.get(i+1)) }); }*/ /*sbool tok_applyCurry1LikeFunctions(LS tok, final Set<S> curry1LikeFunctions) { // curry1 funcname(...) => curry1(lambda2 funcname, ...) ret jreplace(tok, "<id> <id>(", "$1(lambda2 $2,", func(L<S> tok, int i) -> bool { contains(curry1LikeFunctions, tok.get(i+1)) }); }*/ /*sbool tok_applyMapMethodLikeFunctions(LS tok, final Set<S> mapMethodLikeFunctions) { // mapMethod funcname(...) => mapMethod('funcname, ...) // collect funcname(...) => collect('funcname, ...) // ... ret jreplace_dyn(tok, "<id> <id>(", func(L<S> tok, int cIdx) -> S { tok.get(cIdx) + "(" + quote(tok.get(cIdx+2)) + "," }, func(L<S> tok, int i) -> bool { contains(mapMethodLikeFunctions, tok.get(i+1)) }); }*/ static void runMetaPostBlocks(List<String> tok) { for (String code : unnull(metaPostBlocks)) { ping(); String snippetID = standardFunctionSnippet(assertIdentifier(code)); if (empty(snippetID)) throw fail("meta-post function not found: " + code); call(hotwireCached(snippetID), code, tok); //callF(codeToFunctionOnArbitraryType(code, "LS", L, "tok"), tok); } } static void runMetaTransformers(List<String> tok) { for (String code : unnull(metaTransformers)) { ping(); tok_runMetaTransformer(tok, code); } } /*sbool tok_applyNuLikeFunctions(LS tok, final Set<S> nuLikeFunctions) { // nu ClassName(...) => nu(ClassName, ...) // ... ret jreplace_dyn(tok, "<id> <id>(", func(L<S> tok, int cIdx) -> S { tok.get(cIdx) + "(" + tok.get(cIdx+2) + ".class," }, func(L<S> tok, int i) -> bool { contains(nuLikeFunctions, tok.get(i+1)) }); }*/ /*sbool tok_applyGetLikeFunctions(LS tok, Set<S> getLikeFunctions) { // get fieldName(...) => get(fieldLambda fieldName, ...) // ... ret jreplace_dyn(tok, "<id> <id>(", func(L<S> tok, int cIdx) -> S { tok.get(cIdx) + "(lambdaField " + tok.get(cIdx+2) + "," }, func(L<S> tok, int i) -> bool { contains(getLikeFunctions, tok.get(i+1)) }); }*/ static boolean metaCodeAllowed() { return allowMetaCode || containsIC(definitions, "allowMetaCode"); } static List<String> indexTokenList(List<String> tok) { if (useIndexedList2) return indexedList2(tok); if (useTokenIndexedList) return tokenIndexedList3(tok); return tok; } static void tok_earlyGeneralStuff(List<String> tok) { // self-compile construct (TODO) /*jreplace(tok, "self-compile", (tok, iOpening, iClosing) -> S[] { selfCompiling });*/ tok_standardBot1(tok); tok_processSimplified(tok); tok_compactModules(tok); tok_metaFor(tok); // is, short for "implements" jreplace(tok, "is <id>", "implements $2", new TokCondition() { public boolean get(final List<String> tok, final int i) { return !eqGetOneOf(tok, i+3, "a", "in"); // "is a", "is in" are defined as something else }}); } static void lambdaReferences(List<String> tok) { // lambda0 myFunction => () -> myFunction() jreplace(tok, "lambda0 <id>", "() -> $2()"); // lambda1 myFunction => var123 -> myFunction(var123) jreplace_dyn(tok, "lambda1 <id>", new F2<List<String>, Integer, Object>() { public Object get(List<String> tok, Integer cIdx) { try { String var = makeVar(); String s = var + " -> " + tok.get(cIdx+2) + "(" + var + ")"; return eqGet(tok, cIdx-2, ")") ? roundBracket(s) : s; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "S var = makeVar();\r\n S s = var + \" -> \" + tok.get(cIdx+2) + \"(\" + var + \")..."; }}); // lambda2 myFunction => (a, b) -> myFunction(a, b) jreplace_dyn(tok, "lambda2 <id>", new F2<List<String>, Integer, Object>() { public Object get(List<String> tok, Integer cIdx) { try { String a = makeVar(); String b = makeVar(); String s = ("(" + a + ", " + b + ") -> " + (tok.get(cIdx+2)) + "(" + a + ", " + b + ")"); return eqGet(tok, cIdx-2, ")") ? roundBracket(s) : s; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "S a = makeVar();\r\n S b = makeVar();\r\n S s = \"(\\*a*/, \\*b*/) -> \\*tok.ge..."; }}); // methodLambda0 methodName => var123 -> var123.methodName() jreplace_dyn(tok, "methodLambda0 <id>", new F2<List<String>, Integer, Object>() { public Object get(List<String> tok, Integer cIdx) { try { String var = makeVar(); return var + " -> " + var + "." + tok.get(cIdx+2) + "()"; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "S var = makeVar();\r\n ret var + \" -> \" + var + \".\" + tok.get(cIdx+2) + \"()\";"; }}); // fieldLambda fieldName => var123 -> var123.fieldName jreplace_dyn(tok, "fieldLambda <id>", new F2<List<String>, Integer, Object>() { public Object get(List<String> tok, Integer cIdx) { try { String var = makeVar(); return var + " -> " + var + "." + tok.get(cIdx+2); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "S var = makeVar();\r\n ret var + \" -> \" + var + \".\" + tok.get(cIdx+2);"; }}); } static void clearSnippetCache() { snippetCache.clear(); sf = null; lclasses = null; } static void mediumRefresh() { clearSnippetCache(); print("Medium-refreshed transpiler " + mc()); } static void jreplace_performing(List<String> tok, int i, int end, String expansion) { if (debug_jreplace) print("jreplace: " + quote(joinSubList(tok, i, end)) + " => " + quote(expansion)); } static String mainClassName() { return or(mainClassName, "main"); } static void grabImportedStaticFunctions(List<String> tok) { for (String name : tok_importedStaticFunctionNamesWithPackages(tok)) { int idx = lastIndexOf(name, '.'); String pkg = takeFirst(idx, name); String functionName = dropFirst(idx+1, name); //print(functionName + " => " + pkg); doNotIncludeFunction.add(functionName); functionToPackage.put(functionName, pkg); } } static boolean printMapLikes() { return contains(definitions, "printMapLikesEtc"); } // delete import if marked as "need latest" static void onImportFound(List<String> tok, IntRange r) { String id = get(tok, r.end-3); if (needLatest.contains(id)) { print("Purging import: " + joinSubList(tok, r)); clearTokens(tok, r); } } static RuntimeException fail() { throw new RuntimeException("fail"); } static RuntimeException fail(Throwable e) { throw asRuntimeException(e); } static RuntimeException fail(Object msg) { throw new RuntimeException(String.valueOf(msg)); } static RuntimeException fail(Object... objects) { throw new Fail(objects); } static RuntimeException fail(String msg) { throw new RuntimeException(msg == null ? "" : msg); } static RuntimeException fail(String msg, Throwable innerException) { throw new RuntimeException(msg, innerException); } static String str(Object o) { return o == null ? "null" : o.toString(); } static String str(char[] c) { return new String(c); } static boolean boolOptPar(ThreadLocal<Boolean> tl) { return boolOptParam(tl); } // defaults to false static boolean boolOptPar(Object[] __, String name) { return boolOptParam(__, name); } static boolean boolOptPar(String name, Object[] __) { return boolOptParam(__, name); } static boolean neq(Object a, Object b) { return !eq(a, b); } static <A> HashSet<A> lithashset(A... items) { HashSet<A> set = new HashSet(); for (A a : items) set.add(a); return set; } // supports the usual quotings (", variable length double brackets) except ' quoting static boolean isQuoted(String s) { if (isNormalQuoted_dirty(s)) return true; return isMultilineQuoted(s); } static boolean isIdentifier(String s) { return isJavaIdentifier(s); } static boolean isInteger(String s) { int n = l(s); if (n == 0) return false; int i = 0; if (s.charAt(0) == '-') if (++i >= n) return false; while (i < n) { char c = s.charAt(i); if (c < '0' || c > '9') return false; ++i; } return true; } static boolean eqic(String a, String b) { if ((a == null) != (b == null)) return false; if (a == null) return true; return a.equalsIgnoreCase(b); } static boolean eqic(Symbol a, Symbol b) { return eq(a, b); } static boolean eqic(Symbol a, String b) { return eqic(asString(a), b); } static boolean eqic(char a, char b) { if (a == b) return true; char u1 = Character.toUpperCase(a); char u2 = Character.toUpperCase(b); if (u1 == u2) return true; return Character.toLowerCase(u1) == Character.toLowerCase(u2); } static volatile StringBuffer local_log = new StringBuffer(); // not redirected static volatile Appendable print_log = local_log; // might be redirected, e.g. to main bot // in bytes - will cut to half that static volatile int print_log_max = 1024*1024; static volatile int local_log_max = 100*1024; static boolean print_silent = false; // total mute if set static Object print_byThread_lock = new Object(); static volatile ThreadLocal<Object> print_byThread; // special handling by thread - prefers F1<S, Bool> static volatile Object print_allThreads; static volatile Object print_preprocess; static void print() { print(""); } static <A> A print(String s, A o) { print(combinePrintParameters(s, o)); return o; } // slightly overblown signature to return original object... static <A> A print(A o) { ping_okInCleanUp(); if (print_silent) return o; String s = o + "\n"; print_noNewLine(s); return o; } static void print_noNewLine(String s) { try { Object f = getThreadLocal(print_byThread_dontCreate()); if (f == null) f = print_allThreads; if (f != null) // We do need the general callF machinery here as print_byThread is sometimes shared between modules if (isFalse( f instanceof F1 ? ((F1) f).get(s) : callF(f, s))) return; } catch (Throwable e) { System.out.println(getStackTrace(e)); } print_raw(s); } static void print_raw(String s) { if (print_preprocess != null) s = (String) callF(print_preprocess, s); s = fixNewLines(s); Appendable loc = local_log; Appendable buf = print_log; int loc_max = print_log_max; if (buf != loc && buf != null) { print_append(buf, s, print_log_max); loc_max = local_log_max; } if (loc != null) print_append(loc, s, loc_max); System.out.print(s); vmBus_send("printed", mc(), s); } static void print_autoRotate() { } static boolean checkTokCondition(Object condition, List<String> tok, int i) { if (condition instanceof TokCondition) return ((TokCondition) condition).get(tok, i); return checkCondition(condition, tok, i); } static <A> List<A> ll(A... a) { ArrayList l = new ArrayList(a.length); if (a != null) for (A x : a) l.add(x); return l; } static List syncMap(Object f, Map map) { return syncMap(map, f); } // map: func(key, value) -> list element static List syncMap(Map map, Object f) { return map(cloneLinkedHashMap(map), f); // TODO: use a temporary list instead } static <A, B> Map<A, B> syncMap() { return synchroHashMap(); } static <A, B> Map<A, B> syncMap(Map map) { return synchronizedMap(map); } static TreeSet<String> ciSet() { return caseInsensitiveSet(); } static <A> A getFuture(Future<A> f) { try { return f == null ? null : f.get(); } catch (Exception __e) { throw rethrow(__e); } } static <A> NowFuture<A> nowFuture(A a) { return new NowFuture(a); } static long sysNow() { ping(); return System.nanoTime()/1000000; } static void vmKeepWithProgramMD5_get(String varName) { String struct = (String) (callOpt(javax(), "vmKeep_get", programID(), md5OfMyJavaSource(), varName)); if (struct != null) setOpt(mc(), varName, unstructure(struct)); } static volatile PersistableThrowable _handleException_lastException; static List _handleException_onException = synchroList(ll((IVF1<Throwable>) (__1 -> printStackTrace2(__1)))); static boolean _handleException_showThreadCancellations = false; static void _handleException(Throwable e) { _handleException_lastException = persistableThrowable(e); Throwable e2 = innerException(e); if (e2.getClass() == RuntimeException.class && eq(e2.getMessage(), "Thread cancelled.") || e2 instanceof InterruptedException) { if (_handleException_showThreadCancellations) System.out.println(getStackTrace_noRecord(e2)); return; } for (Object f : cloneList(_handleException_onException)) try { callF(f, e); } catch (Throwable e3) { try { printStackTrace2(e3); // not using pcall here - it could lead to endless loops } catch (Throwable e4) { System.out.println(getStackTrace(e3)); System.out.println(getStackTrace(e4)); } } } static volatile int numberOfCores_value; static int numberOfCores() { if (numberOfCores_value == 0) numberOfCores_value = Runtime.getRuntime().availableProcessors(); return numberOfCores_value; } static <A> A or(A a, A b) { return a != null ? a : b; } // this syntax should be removed... static Object getThreadLocal(Object o, String name) { ThreadLocal t = (ThreadLocal) (getOpt(o, name)); return t != null ? t.get() : null; } static <A> A getThreadLocal(ThreadLocal<A> tl) { return tl == null ? null : tl.get(); } static <A> A getThreadLocal(ThreadLocal<A> tl, A defaultValue) { return or(getThreadLocal(tl), defaultValue); } static Object getOpt(Object o, String field) { return getOpt_cached(o, field); } static Object getOpt(String field, Object o) { return getOpt_cached(o, field); } static Object getOpt_raw(Object o, String field) { try { Field f = getOpt_findField(o.getClass(), field); if (f == null) return null; makeAccessible(f); return f.get(o); } catch (Exception __e) { throw rethrow(__e); } } // access of static fields is not yet optimized static Object getOpt(Class c, String field) { try { if (c == null) return null; Field f = getOpt_findStaticField(c, field); if (f == null) return null; makeAccessible(f); return f.get(null); } catch (Exception __e) { throw rethrow(__e); } } static Field getOpt_findStaticField(Class<?> c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) return f; _c = _c.getSuperclass(); } while (_c != null); return null; } static Class javax() { return getJavaX(); } static ThreadLocal<Object> print_byThread() { synchronized(print_byThread_lock) { if (print_byThread == null) print_byThread = new ThreadLocal(); } return print_byThread; } // f can return false to suppress regular printing // call print_raw within f to actually print something static AutoCloseable tempInterceptPrint(F1<String, Boolean> f) { return tempSetThreadLocal(print_byThread(), f); } // get purpose 1: access a list/array/map (safer version of x.get(y)) static <A> A get(List<A> l, int idx) { return l != null && idx >= 0 && idx < l(l) ? l.get(idx) : null; } // seems to conflict with other signatures /*static <A, B> B get(Map<A, B> map, A key) { ret map != null ? map.get(key) : null; }*/ static <A> A get(A[] l, int idx) { return idx >= 0 && idx < l(l) ? l[idx] : null; } // default to false static boolean get(boolean[] l, int idx) { return idx >= 0 && idx < l(l) ? l[idx] : false; } // get purpose 2: access a field by reflection or a map static Object get(Object o, String field) { try { if (o == null) return null; if (o instanceof Class) return get((Class) o, field); if (o instanceof Map) return ((Map) o).get(field); Field f = getOpt_findField(o.getClass(), field); if (f != null) { makeAccessible(f); return f.get(o); } if (o instanceof DynamicObject) return getOptDynOnly(((DynamicObject) o), field); } catch (Exception e) { throw asRuntimeException(e); } throw new RuntimeException("Field '" + field + "' not found in " + o.getClass().getName()); } static Object get_raw(String field, Object o) { return get_raw(o, field); } static Object get_raw(Object o, String field) { try { if (o == null) return null; Field f = get_findField(o.getClass(), field); makeAccessible(f); return f.get(o); } catch (Exception __e) { throw rethrow(__e); } } static Object get(Class c, String field) { try { Field f = get_findStaticField(c, field); makeAccessible(f); return f.get(null); } catch (Exception e) { throw new RuntimeException(e); } } static Field get_findStaticField(Class<?> c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) return f; _c = _c.getSuperclass(); } while (_c != null); throw new RuntimeException("Static field '" + field + "' not found in " + c.getName()); } static Field get_findField(Class<?> c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field)) return f; _c = _c.getSuperclass(); } while (_c != null); throw new RuntimeException("Field '" + field + "' not found in " + c.getName()); } static Object get(String field, Object o) { return get(o, field); } static boolean get(BitSet bs, int idx) { return bs != null && bs.get(idx); } static Map<Class, ArrayList<Method>> callF_cache = newDangerousWeakHashMap(); static <A> A callF(F0<A> f) { return f == null ? null : f.get(); } static <A, B> B callF(F1<A, B> f, A a) { return f == null ? null : f.get(a); } static <A> A callF(IF0<A> f) { return f == null ? null : f.get(); } static <A, B> B callF(IF1<A, B> f, A a) { return f == null ? null : f.get(a); } static <A, B, C> C callF(F2<A, B, C> f, A a, B b) { return f == null ? null : f.get(a, b); } static <A, B, C> C callF(IF2<A, B, C> f, A a, B b) { return f == null ? null : f.get(a, b); } static <A> void callF(VF1<A> f, A a) { if (f != null) f.get(a); } static Object callF(Runnable r) { { if (r != null) r.run(); } return null; } static Object callF(Object f, Object... args) { if (f instanceof String) return callMCWithVarArgs((String) f, args); // possible SLOWDOWN over callMC return safeCallF(f, args); } static Object safeCallF(Object f, Object... args) { if (f instanceof Runnable) { ((Runnable) f).run(); return null; } if (f == null) return null; Class c = f.getClass(); ArrayList<Method> methods; synchronized(callF_cache) { methods = callF_cache.get(c); if (methods == null) methods = callF_makeCache(c); } int n = l(methods); if (n == 0) { throw fail("No get method in " + getClassName(c)); } if (n == 1) return invokeMethod(methods.get(0), f, args); for (int i = 0; i < n; i++) { Method m = methods.get(i); if (call_checkArgs(m, args, false)) return invokeMethod(m, f, args); } throw fail("No matching get method in " + getClassName(c)); } // used internally static ArrayList<Method> callF_makeCache(Class c) { ArrayList<Method> l = new ArrayList(); Class _c = c; do { for (Method m : _c.getDeclaredMethods()) if (m.getName().equals("get")) { makeAccessible(m); l.add(m); } if (!l.isEmpty()) break; _c = _c.getSuperclass(); } while (_c != null); callF_cache.put(c, l); return l; } static String formatInt(int i, int digits) { return padLeft(str(i), '0', digits); } static String formatInt(long l, int digits) { return padLeft(str(l), '0', digits); } // f can return false to suppress regular printing // call print_raw within f to actually print something // f preferrably is F1<S, Bool> static Object interceptPrintInThisThread(Object f) { Object old = print_byThread().get(); print_byThread().set(f); return old; } static void _close(AutoCloseable c) { if (c != null) try { c.close(); } catch (Throwable e) { // Some classes stupidly throw an exception on double-closing if (c instanceof javax.imageio.stream.ImageOutputStream) return; else throw rethrow(e); } } static boolean sameSnippetID(String a, String b) { if (!isSnippetID(a) || !isSnippetID(b)) return false; return parseSnippetID(a) == parseSnippetID(b); } static String programID() { return getProgramID(); } static String programID(Object o) { return getProgramID(o); } static String defaultJavaXTranslatorID_value = "#759"; static String defaultJavaXTranslatorID() { return defaultJavaXTranslatorID_value; } static void setDefaultJavaXTranslatorID(String snippetID) { defaultJavaXTranslatorID_value = snippetID; } static String mainJava; static String loadMainJava() throws IOException { if (mainJava != null) return mainJava; return loadTextFile("input/main.java", ""); } static int identityHashCode(Object o) { return System.identityHashCode(o); } static <A> HashSet<A> cloneHashSet(Collection<A> set) { if (set == null) return new HashSet(); synchronized(collectionMutex(set)) { HashSet < A > s = new HashSet<>(l(set)); s.addAll(set); return s; } } static Set<String> tok_mapLikeFunctions_set = emptySet(); static Set<String> tok_mapLikeFunctions() { return tok_mapLikeFunctions_set; } static Set<String> tok_mapMethodLikeFunctions_set = asHashSet( splitAtSpace("mapMethod uniquifyByField indexByField collect")); static Set<String> tok_mapMethodLikeFunctions() { return tok_mapMethodLikeFunctions_set; } static boolean hasCodeTokens(List<String> tok, String... tokens) { return findCodeTokens(tok, tokens) >= 0; } static int l(Object[] a) { return a == null ? 0 : a.length; } static int l(boolean[] a) { return a == null ? 0 : a.length; } static int l(byte[] a) { return a == null ? 0 : a.length; } static int l(short[] a) { return a == null ? 0 : a.length; } static int l(long[] a) { return a == null ? 0 : a.length; } static int l(int[] a) { return a == null ? 0 : a.length; } static int l(float[] a) { return a == null ? 0 : a.length; } static int l(double[] a) { return a == null ? 0 : a.length; } static int l(char[] a) { return a == null ? 0 : a.length; } static int l(Collection c) { return c == null ? 0 : c.size(); } static int l(Iterator i) { return iteratorCount_int_close(i); } // consumes the iterator && closes it if possible static int l(Map m) { return m == null ? 0 : m.size(); } static int l(CharSequence s) { return s == null ? 0 : s.length(); } static long l(File f) { return f == null ? 0 : f.length(); } static int l(Object o) { return o == null ? 0 : o instanceof String ? l((String) o) : o instanceof Map ? l((Map) o) : o instanceof Collection ? l((Collection) o) : o instanceof Object[] ? l((Object[]) o) : o instanceof boolean[] ? l((boolean[]) o) : o instanceof byte[] ? l((byte[]) o) : o instanceof char[] ? l((char[]) o) : o instanceof short[] ? l((short[]) o) : o instanceof int[] ? l((int[]) o) : o instanceof float[] ? l((float[]) o) : o instanceof double[] ? l((double[]) o) : o instanceof long[] ? l((long[]) o) : (Integer) call(o, "size"); } static int l(MultiSet ms) { return ms == null ? 0 : ms.size(); } static int l(IntRange r) { return r == null ? 0 : r.length(); } static <A> List<A> singlePlusList(A a, Collection<A> l) { return itemPlusList(a, l); } static Object first(Object list) { return first((Iterable) list); } static <A> A first(List<A> list) { return empty(list) ? null : list.get(0); } static <A> A first(A[] bla) { return bla == null || bla.length == 0 ? null : bla[0]; } static <A> A first(IterableIterator<A> i) { return first((Iterator<A>) i); } static <A> A first(Iterator<A> i) { return i == null || !i.hasNext() ? null : i.next(); } static <A> A first(Iterable<A> i) { if (i == null) return null; Iterator<A> it = i.iterator(); return it.hasNext() ? it.next() : null; } static Character first(String s) { return empty(s) ? null : s.charAt(0); } static Character first(CharSequence s) { return empty(s) ? null : s.charAt(0); } static <A, B> A first(Pair<A, B> p) { return p == null ? null : p.a; } static <A, B, C> A first(T3<A, B, C> t) { return t == null ? null : t.a; } static Byte first(byte[] l) { return empty(l) ? null : l[0]; } static <A> A first(A[] l, IF1<A, Boolean> pred) { return firstThat(l, pred); } static <A> A first(Iterable<A> l, IF1<A, Boolean> pred) { return firstThat(l, pred); } static <A> A first(IF1<A, Boolean> pred, Iterable<A> l) { return firstThat(pred, l); } static String[] dropFirst(int n, String[] a) { return drop(n, a); } static String[] dropFirst(String[] a) { return drop(1, a); } static Object[] dropFirst(Object[] a) { return drop(1, a); } static <A> List<A> dropFirst(List<A> l) { return dropFirst(1, l); } static <A> List<A> dropFirst(int n, Iterable<A> i) { return dropFirst(n, toList(i)); } static <A> List<A> dropFirst(Iterable<A> i) { return dropFirst(toList(i)); } static <A> List<A> dropFirst(int n, List<A> l) { return n <= 0 ? l : new ArrayList(l.subList(Math.min(n, l.size()), l.size())); } static <A> List<A> dropFirst(List<A> l, int n) { return dropFirst(n, l); } static String dropFirst(int n, String s) { return substring(s, n); } static String dropFirst(String s, int n) { return substring(s, n); } static String dropFirst(String s) { return substring(s, 1); } // TODO: extended multi-line strings static int javaTok_n, javaTok_elements; static boolean javaTok_opt = false; static List<String> javaTok(String s) { ++javaTok_n; ArrayList<String> tok = new ArrayList(); int l = s == null ? 0 : s.length(); int i = 0; while (i < l) { int j = i; char c, d; // scan for whitespace while (j < l) { c = s.charAt(j); d = j+1 >= l ? '\0' : s.charAt(j+1); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (c == '/' && d == '*') { do ++j; while (j < l && !regionMatches(s, j, "*/")); j = Math.min(j+2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } tok.add(javaTok_substringN(s, i, j)); i = j; if (i >= l) break; c = s.charAt(i); d = i+1 >= l ? '\0' : s.charAt(i+1); // scan for non-whitespace // Special JavaX syntax: 'identifier if (c == '\'' && Character.isJavaIdentifierStart(d) && i+2 < l && "'\\".indexOf(s.charAt(i+2)) < 0) { j += 2; while (j < l && Character.isJavaIdentifierPart(s.charAt(j))) ++j; } else if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { int c2 = s.charAt(j); if (c2 == opener || c2 == '\n' && opener == '\'') { // allow multi-line strings, but not for ' ++j; break; } else if (c2 == '\\' && j+1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || s.charAt(j) == '\'')); // for stuff like "don't" else if (Character.isDigit(c)) { do ++j; while (j < l && Character.isDigit(s.charAt(j))); if (j < l && s.charAt(j) == 'L') ++j; // Long constants like 1L } else if (c == '[' && d == '[') { do ++j; while (j < l && !regionMatches(s, j, "]]")); j = Math.min(j+2, l); } else if (c == '[' && d == '=' && i+2 < l && s.charAt(i+2) == '[') { do ++j; while (j+2 < l && !regionMatches(s, j, "]=]")); j = Math.min(j+3, l); } else ++j; tok.add(javaTok_substringC(s, i, j)); i = j; } if ((tok.size() % 2) == 0) tok.add(""); javaTok_elements += tok.size(); return tok; } static List<String> javaTok(List<String> tok) { return javaTokWithExisting(join(tok), tok); } static void replaceTokens_reTok(List<String> tok, int i, int j, String s) { replaceTokens(tok, i, j, s); reTok(tok, i, j); } static String unnull(String s) { return s == null ? "" : s; } static <A> Collection<A> unnull(Collection<A> l) { return l == null ? emptyList() : l; } static <A> List<A> unnull(List<A> l) { return l == null ? emptyList() : l; } static int[] unnull(int[] l) { return l == null ? emptyIntArray() : l; } static char[] unnull(char[] l) { return l == null ? emptyCharArray() : l; } static double[] unnull(double[] l) { return l == null ? emptyDoubleArray() : l; } static <A, B> Map<A, B> unnull(Map<A, B> l) { return l == null ? emptyMap() : l; } static <A> Iterable<A> unnull(Iterable<A> i) { return i == null ? emptyList() : i; } static <A> A[] unnull(A[] a) { return a == null ? (A[]) emptyObjectArray() : a; } static BitSet unnull(BitSet b) { return b == null ? new BitSet() : b; } //ifclass Symbol static Symbol unnull(Symbol s) { return s == null ? emptySymbol() : s; } //endif static <A, B> Pair<A, B> unnull(Pair<A, B> p) { return p != null ? p : new Pair(null, null); } static int unnull(Integer i) { return i == null ? 0 : i; } static long unnull(Long l) { return l == null ? 0L : l; } static double unnull(Double l) { return l == null ? 0.0 : l; } static List<String> tok_moveImportsUp(List<String> tok) { StringBuilder buf = new StringBuilder(); //print("tok_moveImportsUp n=" + l(tok)); //print("Source begins: " + quote(shorten(join(tok), 200))); // scan imports on top int i; Set<String> have = new HashSet(); for (i = 1; i < l(tok); i += 2) if (eq(tok.get(i), "import")) { int j = indexOf(tok, i+2, ";"); if (j < 0) break; String s = joinSubList(tok, i, j+1); have.add(s); i = j; } else break; //print("tok_moveImportsUp have " + l(have) + " after " + i); List<IntRange> reToks = new ArrayList(); // scan imports in text for (; i < l(tok); i += 2) if (eq(tok.get(i), "import")) { int j = indexOf(tok, i+2, ";"); if (j < 0) continue; // huh? String s = joinSubList(tok, i, j+1); //print("Found import at " + i + ": " + s); if (!have.contains(s)) { buf.append(s).append("\n"); have.add(s); } replaceTokens(tok, i, j+1, ""); i -= 2; } if (nempty(buf)) { if (l(tok) == 1) addAll(tok, "", ""); tok.set(1, str(buf)+"\n"+tok.get(1)); reToks.add(intRange(1, 2)); } return reTok_multi(tok, reToks); } static boolean tok_hasTranslators(List<String> tok) { int n = l(tok)-2; for (int i = 1; i < n; i += 2) if (tok.get(i).equals("!") && isInteger(tok.get(i+2))) return true; return false; } static String defaultTranslate(String text) { Class javax = getJavaX(); File x = makeTempDir(); saveTextFile(new File(x, "main.java"), text); List<File> libraries_out = new ArrayList(); List<String> libraries2_out = new ArrayList(); File y = (File) (call(javax, "defaultTranslate", x, libraries_out, libraries2_out)); if (y == null) return null; return loadTextFile(new File(y, "main.java")); } public static <A> String join(String glue, Iterable<A> strings) { if (strings == null) return ""; if (strings instanceof Collection) { if (((Collection) strings).size() == 1) return str(first((Collection) strings)); } StringBuilder buf = new StringBuilder(); Iterator<A> i = strings.iterator(); if (i.hasNext()) { buf.append(i.next()); while (i.hasNext()) buf.append(glue).append(i.next()); } return buf.toString(); } public static String join(String glue, String... strings) { return join(glue, Arrays.asList(strings)); } static <A> String join(Iterable<A> strings) { return join("", strings); } static <A> String join(Iterable<A> strings, String glue) { return join(glue, strings); } public static String join(String[] strings) { return join("", strings); } static String join(String glue, Pair p) { return p == null ? "" : str(p.a) + glue + str(p.b); } static void tok_metaTransformNow(List<String> tok) { int i = -1; while ((i = jfind(tok, i+1, "meta-transformNow {")) >= 0) { int iOpening = indexOf(tok, i, "{"); int iClosing = findEndOfBracketPart(tok, iOpening)-1; String code = joinSubList(tok, iOpening+2, iClosing-1); clearTokens_reTok(tok, i, iClosing+1); tok_runMetaTransformer(tok, code); } } //sbool ping_actions_shareable = true; static volatile boolean ping_pauseAll = false; static int ping_sleep = 100; // poll pauseAll flag every 100 static volatile boolean ping_anyActions = false; static Map<Thread, Object> ping_actions = newWeakHashMap(); static ThreadLocal<Boolean> ping_isCleanUpThread = new ThreadLocal(); // always returns true static boolean ping() { //ifdef useNewPing newPing(); //endifdef if (ping_pauseAll || ping_anyActions) ping_impl(true /* XXX */); //ifndef LeanMode ping_impl(); endifndef return true; } // returns true when it slept static boolean ping_impl(boolean okInCleanUp) { try { if (ping_pauseAll && !isAWTThread()) { do Thread.sleep(ping_sleep); while (ping_pauseAll); return true; } if (ping_anyActions) { // don't allow sharing ping_actions if (!okInCleanUp && !isTrue(ping_isCleanUpThread.get())) failIfUnlicensed(); Object action = null; synchronized(ping_actions) { if (!ping_actions.isEmpty()) { action = ping_actions.get(currentThread()); if (action instanceof Runnable) ping_actions.remove(currentThread()); if (ping_actions.isEmpty()) ping_anyActions = false; } } if (action instanceof Runnable) ((Runnable) action).run(); else if (eq(action, "cancelled")) throw fail("Thread cancelled."); } return false; } catch (Exception __e) { throw rethrow(__e); } } static <A> ArrayList<A> cloneList(Iterable<A> l) { return l instanceof Collection ? cloneList((Collection) l) : asList(l); } static <A> ArrayList<A> cloneList(Collection<A> l) { if (l == null) return new ArrayList(); synchronized(collectionMutex(l)) { return new ArrayList<A>(l); } } static String jreplace(String s, String in, String out) { return jreplace(s, in, out, null); } static String jreplace(String s, String in, String out, Object condition) { List<String> tok = javaTok(s); return jreplace(tok, in, out, condition) ? join(tok) : s; } // leaves tok properly tokenized // returns true iff anything was replaced static boolean jreplace(List<String> tok, String in, String out) { return jreplace(tok, in, out, false, true, null); } static boolean jreplace(List<String> tok, String in, String out, Object condition) { return jreplace(tok, in, out, false, true, condition); } static boolean jreplace(List<String> tok, String in, String out, IF2<List<String>, Integer, Boolean> condition) { return jreplace(tok, in, out, (Object) condition); } static boolean jreplace(List<String> tok, String in, String out, boolean ignoreCase, boolean reTok, Object condition) { String[] toks = javaTokForJFind_array(in); int lTokin = toks.length*2+1; boolean anyChange = false; int i = -1; for (int n = 0; n < 10000; n++) { // TODO: don't need this check anymore i = findCodeTokens(tok, i+1, ignoreCase, toks, condition); if (i < 0) return anyChange; List<String> subList = tok.subList(i-1, i+lTokin-1); // N to N String expansion = jreplaceExpandRefs(out, subList); int end = i+lTokin-2; jreplace_performing(tok, i, end, expansion); clearAllTokens(tok, i, end); // C to C tok.set(i, expansion); if (reTok) // would this ever be false?? reTok(tok, i, end); i = end; anyChange = true; } throw fail("woot? 10000! " + quote(in) + " => " + quote(out)); } static boolean jreplace_debug = false; static void tok_selfType(List<String> tok) { int i; mainLoop: while ((i = jfind(tok, "selfType <id>")) >= 0) { // Now find class name by going backwards. int j = i, level = 1; while (j > 0 && level > 0) { String t = tok.get(j); if (t.equals("}")) ++level; if (t.equals("{")) --level; j -= 2; } // search for class name while (j > 0) { String t = tok.get(j); if (t.equals("class")) { String className = tok.get(j+2); tok.set(i, className); continue mainLoop; } j -= 2; } tok.set(i, "Object"); // avoid endless loop } } // extra commas - e.g. ll(1, 2,) => ll(1, 2) static void tok_dropExtraCommas(List<String> tok) { jreplace(tok, ",)", ")"); } static void tok_delegateTo(List<String> tok) { jreplace(tok, "delegate <id> to <id>.", "replace $2 with $4.$2."); jreplace(tok, "delegate <id> to <id>().", "replace $2 with $4().$2."); // TODO: general expressions in "to" clause } static void tok_replaceWith(List<String> tok) { int i; while ((i = jfind(tok, "replace <id> with")) >= 0) { ping(); String token = tok.get(i+2); int repStart = i+6; int repEnd = repStart; // Find . with space or line break or EOF afterwards while (repEnd < l(tok) && !( eqGet(tok, repEnd, ".") && // end when there is a dot (nempty(get(tok, repEnd+1)) || repEnd == l(tok)-2))) // ...and it's the end of the text OR there is a space or newline after the dot { ping(); repEnd += 2; } print("tok_replaceWith: Found " + joinSubList(tok, repStart, repEnd)); //int repEnd = smartIndexOf(tok, repStart, "."); String replacement = joinSubList(tok, repStart, repEnd-1); clearTokens(tok, i, repEnd+1); print("Replacing " + token + " with " + replacement + "."); int end = findEndOfBlock(tok, repEnd)-1; for (int j = repEnd+2; j < end; j += 2) { ping(); if (eq(tok.get(j), token)) tok.set(j, replacement); } reTok(tok, i, end); } } // example: // sS loadTextFile(File/S file) { ... } static void tok_multiTypeArguments_v2(List<String> tok) { int i; // File/S while ((i = jfind(tok, "File/<id> <id>", (_tok, nIdx) -> eqGetOneOf(_tok, nIdx+5, "S", "String"))) >= 0) { String argName = tok.get(i+6); String mainType = tok.get(i), altType = tok.get(i+4); String converter = "newFile"; String expr = converter + "(" + argName + ")"; tok_expandMultiTypeArgument(tok, i, i+8, argName, mainType, altType, expr); } // Graphics2D etc, IIntegralImage etc, ... while ((i = jfind(tok, "<id> etc <id>")) >= 0) { String mainType = tok.get(i); String argName = tok.get(i+4); int iArgEnd = i+6; List<Pair<String, String>> alts = new ArrayList(); // altType, converter if (eq(mainType, "Graphics2D")) alts.add(pair("BufferedImage", "graphics")); else if (eq(mainType, "IIntegralImage")) { alts.add(pair("BufferedImage", "IntegralImage")); alts.add(pair("MakesBufferedImage", "IntegralImage")); } else if (eq(mainType, "BufferedImage")) alts.add(pair("MakesBufferedImage", "toBufferedImage")); else if (eq(mainType, "Pt")) { alts.add(pair(("int " + argName + "_x, int " + argName + "_y"), ("pt(" + argName + "_x, " + argName + "_y)"))); tok_expandMultiTypeArgument_v3(tok, i, iArgEnd, argName, mainType, alts); continue; } if (empty(alts)) throw fail("Unknown multi-type: " + joinSubList(tok, i, iArgEnd)); alts = mapPairB(alts, converter -> converter + "(" + argName + ")"); tok_expandMultiTypeArgument_v2(tok, i, iArgEnd, argName, mainType, alts); } // Iterable<X> or X[], Iterable<> or X... IntRange r; for (String modifier : ll("[]", "...")) while ((r = jfind_range(tok, "Iterable<<id>> or <id>" + modifier + " <id>")) != null) { i = r.start+1; String mainType = joinSubList(tok, i, i+7); String altType = joinSubList(tok, i+10, r.end-3); String argName = tok.get(r.end-2); String converter = "asList"; String expr = converter + "(" + argName + ")"; tok_expandMultiTypeArgument(tok, i, r.end, argName, mainType, altType, expr); } // Iterable or O[], Iterable or X..., Cl/O[], etc for (String modifier : ll("[]", "...")) while ((r = jfind_range(tok, "<id> * *" + modifier + " <id>", new F2<List<String>, Integer, Object>() { public Object get(List<String> tok, Integer nIdx) { try { return eqOneOf(tok.get(nIdx+1), "Iterable", "Collection", "Cl", "List", "L") && eqGetOneOf(tok, nIdx+3, "or", "/") && eqGetOneOf(tok, nIdx+5, "O", "Object"); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "eqOneOf(tok.get(nIdx+1), \"Iterable\", \"Collection\", \"Cl\", \"List\", \"L\")\r\n ..."; }})) != null) { i = r.start+1; String mainType = tok.get(i); String altType = joinSubList(tok, i+4, r.end-3); String argName = tok.get(r.end-2); String converter = "asList"; String expr = converter + "(" + argName + ")"; tok_expandMultiTypeArgument(tok, i, r.end, argName, mainType, altType, expr); } } // goes over input only once (doesn't start again at 1 like jreplace_dyn) static String jreplace_dyn_allowNull(String s, String in, TokReplacer replacer) { return jreplace_dyn_allowNull(s, in, replacer, null); } static String jreplace_dyn_allowNull(String s, String in, TokReplacer replacer, ITokCondition condition) { List<String> tok = javaTok(s); jreplace_dyn_allowNull(tok, in, replacer, condition); return join(tok); } static boolean jreplace_dyn_allowNull(List<String> tok, String in, TokReplacer replacer) { return jreplace_dyn_allowNull(tok, in, replacer, null); } static boolean jreplace_dyn_allowNull(List<String> tok, String in, TokReplacer replacer, ITokCondition condition) { return jreplace_dyn_allowNull(tok, in, replacer, condition, false, true); } static boolean jreplace_dyn_allowNull(List<String> tok, String in, TokReplacer replacer, ITokCondition condition, boolean ignoreCase, boolean reTok) { List<String> tokin = javaTok(in); jfind_preprocess(tokin); String[] toks = toStringArray(codeTokensOnly(tokin)); boolean anyChange = false; int i = 0; for (int safety = 0; safety < 10000; safety++) { ping(); i = findCodeTokens(tok, i, ignoreCase, toks, condition); if (i < 0) return anyChange; int start = i, end = i+l(tokin)-2; i = end+2; String expansion = replacer.get(tok, start, end); if (expansion != null) { clearAllTokens(tok, start, end); // C to C tok.set(start, expansion); if (reTok) { // would this ever be false?? int n = l(tok); reTok(tok, start, end); i += l(tok)-n; // adjust for replacement } anyChange = true; } } throw fail("woot? 10000! " + quote(in) + " => " + replacer); } // Use like this: printVars(+x, +y); // Or: printVars("bla", +x); // Or: printVars bla(, +x); static void printVars(Object... params) { printVars_str(params); } static boolean eqGet(List l, int i, Object o) { return eq(get(l, i), o); } static <A, B> boolean eqGet(Map<A, B> map, A key, Object o) { return eq(mapGet(map, key), o); } static RuntimeException rethrow(Throwable t) { if (t instanceof Error) _handleError((Error) t); throw t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t); } static RuntimeException rethrow(String msg, Throwable t) { throw new RuntimeException(msg, t); } static void tok_collectMetaPostBlocks(List<String> tok, List<String> postProcessBlocks_out) { int i = -1; while ((i = jfind(tok, i+1, "meta-postProcess {")) >= 0) { int iOpening = indexOf(tok, i, "{"); int iClosing = findEndOfBracketPart(tok, iOpening)-1; add(postProcessBlocks_out, joinSubList(tok, iOpening+2, iClosing-1)); clearTokens_reTok(tok, i, iClosing+1); } } static void tok_collectTransformers(List<String> tok, List<String> out) { int i = -1; while ((i = jfind(tok, i+1, "meta-transform {")) >= 0) { int iOpening = indexOf(tok, i, "{"); int iClosing = findEndOfBracketPart(tok, iOpening)-1; add(out, joinSubList(tok, iOpening+2, iClosing-1)); clearTokens_reTok(tok, i, iClosing+1); } } static long now_virtualTime; static long now() { return now_virtualTime != 0 ? now_virtualTime : System.currentTimeMillis(); } static boolean eq(Object a, Object b) { return a == b || a != null && b != null && a.equals(b); } // a little kludge for stuff like eq(symbol, "$X") static boolean eq(Symbol a, String b) { return eq(str(a), b); } static String jreplace1(String s, String in, String out) { return jreplace1(s, in, out, null); } static String jreplace1(String s, String in, String out, Object condition) { List<String> tok = javaTok(s); return jreplace1(tok, in, out, condition) ? join(tok) : s; } // leaves tok properly tokenized // returns true iff anything was replaced static boolean jreplace1(List<String> tok, String in, String out) { return jreplace1(tok, in, out, false, true, null); } static boolean jreplace1(List<String> tok, String in, String out, Object condition) { return jreplace1(tok, in, out, false, true, condition); } static boolean jreplace1(List<String> tok, String in, String out, boolean ignoreCase, boolean reTok, Object condition) { List<String> tokin = javaTok(in); jfind_preprocess(tokin); boolean anyChange = false; int i = 1; while ((i = findCodeTokens(tok, i, ignoreCase, toStringArray(codeTokensOnly(tokin)), condition)) >= 0) { List<String> subList = tok.subList(i-1, i+l(tokin)-1); // N to N String expansion = jreplaceExpandRefs(out, subList); int end = i+l(tokin)-2; clearAllTokens(tok, i, end); // C to C tok.set(i, expansion); if (reTok) // would this ever be false?? reTok(tok, i, end); i = end; anyChange = true; } return anyChange; } static boolean jreplace1_debug = false; // out: func(L<S> tok, int cIndex) -> S // condition: func(L<S> tok, int nIndex) -> S [yeah it's inconsistent] static String jreplace_dyn(String s, String in, Object out) { return jreplace_dyn(s, in, out, null); } static String jreplace_dyn(String s, String in, Object out, Object condition) { List<String> tok = javaTok(s); jreplace_dyn(tok, in, out, condition); return join(tok); } // leaves tok properly tokenized // returns true iff anything was replaced static boolean jreplace_dyn(List<String> tok, String in, Object out) { return jreplace_dyn(tok, in, out, false, true, null); } static boolean jreplace_dyn(List<String> tok, String in, IF2<List<String>, Integer, String> out) { return jreplace_dyn(tok, in, (Object) out); } static boolean jreplace_dyn(List<String> tok, String in, IF2<List<String>, Integer, String> out, IF2<List<String>, Integer, Boolean> condition) { return jreplace_dyn(tok, in, (Object) out, (Object) condition); } static boolean jreplace_dyn(List<String> tok, String in, Object out, Object condition) { return jreplace_dyn(tok, in, out, false, true, condition); } static boolean jreplace_dyn(List<String> tok, String in, Object out, boolean ignoreCase, boolean reTok, Object condition) { List<String> tokin = javaTok(in); jfind_preprocess(tokin); String[] toks = toStringArray(codeTokensOnly(tokin)); boolean anyChange = false; for (int n = 0; n < 10000; n++) { int i = findCodeTokens(tok, 1, ignoreCase, toks, condition); if (i < 0) return anyChange; String expansion = (String) (callF(out, tok, i)); int end = i+l(tokin)-2; clearAllTokens(tok, i, end); // C to C tok.set(i, expansion); if (reTok) // would this ever be false?? reTok(tok, i, end); anyChange = true; } throw fail("woot? 10000! " + quote(in) + " => " + quote(out)); } static String stringToLegalIdentifier(String s) { StringBuilder buf = new StringBuilder(); s = dropTrailingSquareBracketStuff(s); for (int i = 0; i < l(s); i++) { char c = s.charAt(i); if (empty(buf) ? Character.isJavaIdentifierStart(c) : Character.isJavaIdentifierPart(c)) buf.append(c); } if (empty(buf)) throw fail("Can't convert to legal identifier: " + s); return str(buf); } static String getSnippetTitle(String id) { if (id == null) return null; if (!isSnippetID(id)) return "?"; IResourceLoader rl = vm_getResourceLoader(); if (rl != null) return rl.getSnippetTitle(id); return getSnippetTitle_noResourceLoader(id); } static String getSnippetTitle_noResourceLoader(String id) { try { if (isLocalSnippetID(id)) return localSnippetTitle(id); long parsedID = parseSnippetID(id); String url; if (isImageServerSnippet(parsedID)) url = imageServerURL() + "title/" + parsedID + muricaCredentialsQuery(); else if (isGeneralFileServerSnippet(parsedID)) url = "http://butter.botcompany.de:8080/files/name/" + parsedID; else url = tb_mainServer() + "/tb-int/getfield.php?id=" + parsedID + "&field=title" + standardCredentials_noCookies(); String title = trim(loadPageSilently(url)); if (title != null) try { saveTextFileIfChanged(snippetTitle_cacheFile(id), title); } catch (Throwable __e) { print(exceptionToStringShort(__e)); } return or(title, "?"); } catch (Exception __e) { throw rethrow(__e); } } static String getSnippetTitle(long id) { return getSnippetTitle(fsI(id)); } static void tok_overridableFunctionDefs(List<String> tok, Set<String> overriableFunctions_out) { int i; while ((i = jfind(tok, "static overridable <id>")) >= 0) { int bracket = indexOf(tok, "(", i); int codeStart = indexOf(tok, "{", bracket); String fName = assertIdentifier(tok.get(bracket-2)); String type = joinSubList(tok, i+4, bracket-3); String boxedType = tok_toNonPrimitiveTypes(type); String args = joinWithComma(map(__45 -> tok_lastIdentifier(__45), tok_parseArgsDeclList(subList(tok, i)))); String castIt = eq(type, "Object") ? "" : ("(" + type + ")"); replaceTokens(tok, i, bracket-1, ("static Object _override_" + fName + ";\n") + ("static " + type + " " + fName)); tokAppend(tok, codeStart, (" if (_override_" + fName + " != null) return " + castIt + " callF(_override_" + fName + ", " + args + ");\n")); reTok(tok, i, codeStart+1); addToCollection(overriableFunctions_out, fName); } } static List<String> tok_cleanImports(List<String> tok) { List<String> index = toContentsIndexedList(tok); List<IntRange> imports = tok_findImports_returnRanges(tok); BitSet exclude = new BitSet(); for (IntRange r : imports) set(exclude, r.end-4); List<IntRange> reToks = new ArrayList(); loop: for (IntRange r : imports) { String id = get(tok, r.end-4); if (!isIdentifier(id)) continue; for (int i : indicesOf(index, id)) if (!get(exclude, i)) continue loop; // id is in use // import is unused - delete clearTokens_addToReToks(tok, r.start+1, r.end, reToks); } reTok_multi(tok, reToks); return tok; } static int lastIndexOfStartingWith(List<String> l, String s) { for (int i = l(l)-1; i >= 0; i--) if (startsWith(l.get(i), s)) return i; return -1; } static String dropPrefix(String prefix, String s) { return s == null ? null : s.startsWith(prefix) ? s.substring(l(prefix)) : s; } static String sfu(Object o) { return structureForUser(o); } // unclear semantics when l is a special set (e.g. ciSet) static <A> boolean containsOneOf(Collection<A> l, A... x) { if (l instanceof Set) { if (x != null) for (A a : x) if (l.contains(a)) return true; } else { for (A a : unnull(l)) if (eqOneOf(a, x)) return true; } return false; } static <A> boolean containsOneOf(Collection<A> l, Set<A> set) { if (set == null) return false; for (A a : unnull(l)) if (set.contains(a)) return true; return false; } static boolean containsOneOf(String s, String... x) { for (String o : x) if (contains(s, o)) return true; return false; } static boolean containsIC(Collection<String> l, String s) { return containsIgnoreCase(l, s); } static boolean containsIC(String[] l, String s) { return containsIgnoreCase(l, s); } static boolean containsIC(String s, char c) { return containsIgnoreCase(s, c); } static boolean containsIC(String a, String b) { return containsIgnoreCase(a, b); } static boolean containsIC(Producer<String> p, String a) { if (p != null && a != null) while (true) { String x = p.next(); if (x == null) break; if (eqic(x, a)) return true; } return false; } static String extractAndPrintJavaParseError(String src, Throwable e) { StringBuilder buf = new StringBuilder(); print_tee(buf); String msg = takeFirstLines(2, innerMessage(e)); print_tee(buf, msg); int line = parseIntOpt(regexpFirstGroupIC("line (\\d+)", msg)); print_tee(buf); if (line != 0) { List<String> lines = lines(src); for (int i = max(1, line-5); i <= min(l(lines), line+5); i++) print_tee(buf, (i == line ? "* " : " ") + "LINE " + i + ": " + lines.get(i-1)); } print_tee(buf); return str(buf); } static File transpilerErrorSourceFile() { return javaxCachesDir("error-source.java"); } static void saveTextFileVerbose(File f, String text) { boolean exists = f.exists(); saveTextFile(f, text); print((!exists ? "Created" : "Updated") + " file " + f2s(f) + " (" + f.length() + " bytes)"); } static String innerMessage(Throwable e) { return getInnerMessage(e); } static void tokPrepend(List<String> tok, String s) { tokPrepend(tok, 0, s); } static void tokPrepend(List<String> tok, int i, String s) { tok.set(i, s + tok.get(i)); } static List<String> reTok(List<String> tok) { replaceCollection(tok, javaTok(tok)); return tok; } static List<String> reTok(List<String> tok, int i) { return reTok(tok, i, i+1); } static List<String> reTok(List<String> tok, int i, int j) { // extend i to an "N" token // and j to "C" (so j-1 is an "N" token) i = max(i & ~1, 0); j = min(l(tok), j | 1); if (i >= j) return tok; List<String> t = javaTok(joinSubList(tok, i, j)); replaceListPart(tok, i, j, t); // fallback to safety // reTok(tok); return tok; } static List<String> reTok(List<String> tok, IntRange r) { if (r != null) reTok(tok, r.start, r.end); return tok; } static boolean nempty(Collection c) { return !empty(c); } static boolean nempty(CharSequence s) { return !empty(s); } static boolean nempty(Object[] o) { return !empty(o); } static boolean nempty(byte[] o) { return !empty(o); } static boolean nempty(int[] o) { return !empty(o); } static boolean nempty(Map m) { return !empty(m); } static boolean nempty(Iterator i) { return i != null && i.hasNext(); } static boolean nempty(Object o) { return !empty(o); } static boolean nempty(IntRange r) { return !empty(r); } static String concatMap_strings(Object f, Iterable l) { return join((List<String>) map(f, l)); } static String concatMap_strings(Object f, Object[] l) { return join((List<String>) map(f, l)); } static String concatMap_strings(Iterable l, Object f) { return concatMap_strings(f, l); } static <A> String concatMap_strings(Iterable<A> l, IF1<A, String> f) { return concatMap_strings(f, l); } static <A> String concatMap_strings(IF1<A, String> f, Iterable<A> l) { return concatMap_strings((Object) f, l); } static String f2s(File f) { return f == null ? null : f.getAbsolutePath(); } static String f2s(String s) { return f2s(newFile(s)); } static String f2s(java.nio.file.Path p) { return p == null ? null : f2s(p.toFile()); } static File saveProgramTextFile(String name, String contents) { return saveTextFile(getProgramFile(name), contents); } static File saveProgramTextFile(String progID, String name, String contents) { return saveTextFile(getProgramFile(progID, name), contents); } static void splitJavaFiles(List<String> tok) { try { splitJavaFiles(tok, newFile("output")); } catch (Exception __e) { throw rethrow(__e); } } static void splitJavaFiles(List<String> tok, File outDir) { try { List<Integer> indexes = jfindAll(tok, "package"); if (empty(indexes) || indexes.get(0) != 1) indexes.add(0, 1); for (int i = 0; i < l(indexes); i++) { int from = indexes.get(i); int to = i+1 < l(indexes) ? indexes.get(i+1) : l(tok); List<String> subtok = cncSubList(tok, from, to); String src = join(subtok); //print(shorten(src, 80)); String pack = tok_packageName(subtok); print("Package: " + quote(pack)); List<List<String>> classes = allClasses(subtok); /*for (L<S> c : classes) { //print(" Class: " + shorten(join(c), 80)); print(" Class: " + quote(getClassDeclarationName(c))); }*/ if (empty(classes)) print("No classes?? " + quote(src)); else { String className = getNameOfPublicClass(subtok); if (className == null) className = getNameOfAnyClass(subtok); String fileName = addSlash(pack.replace('.', '/')) + className + ".java"; print("File name: " + fileName); saveTextFile(newFile(outDir, fileName), join(subtok)); } print(); } } catch (Exception __e) { throw rethrow(__e); } } static void saveMainJava(String s) throws IOException { if (mainJava != null) mainJava = s; else saveTextFile("output/main.java", s); } static void saveMainJava(List<String> tok) throws IOException { saveMainJava(join(tok)); } // process scope x. ... end scope blocks static void tok_scopes(List<String> tok, Object... __) { if (!tok.contains("scope")) return; boolean autoCloseScopes = boolPar("autoCloseScopes", __); // New syntax: scope bla { ... } replaceKeywordBlock(tok, "scope <id>", "scope $2. ", " end scope "); int i; // Old syntax: scope bla ... end scope while ((i = rjfind(tok, "scope <id>")) >= 0) { String scopeName = tok.get(i+2); int start = i+4; if (eqGet(tok, start, ".")) start += 2; int j = jfind(tok, start, "end scope"); if (j < 0) if (autoCloseScopes) j = l(tok); else throw fail("Scope " + scopeName + " opened but not closed"); else clearTokens(tok, j, j+3); HashSet<String> names = new HashSet(); HashSet<String> functions = new HashSet(); clearTokens(tok, i, start-1); List<String> subTok = subList(tok, start-1, j); // auto-make #lock variable if (jfind(subTok, "lock #lock") >= 0 && jfind(subTok, "Lock #lock") < 0) tok.set(i, "static Lock " + scopeName + "_lock = lock();\n"); // first pass (find # declarations) for (int k = start; k < j-2; k += 2) { String t = get(tok, k+2); if (eqGet(tok, k, "#") && isIdentifier(t)) { names.add(t); if (eqGetOneOf(tok, k+4, "(", "{", "<", "extends", "implements", ">")) // cover class declarations too functions.add(t); replaceTokens(tok, k, k+3, scopeName + "_" + t); } } // second pass (references to scoped variables) for (int k = start; k < j; k += 2) { String t = get(tok, k); if (isIdentifier(t)) { if (names.contains(t)) { if (eqGet(tok, k-2, ".")) {} else if (eqGet(tok, k+2, "(") && !functions.contains(t)) {} // avoid lock ... and map ... else if (eqOneOf(t, "lock", "map") && isIdentifier(get(tok, k+2))) {} else tok.set(k, scopeName + "_" + t); } else if (eq(t, "__scope")) tok.set(k, quote(scopeName)); } } reTok(tok, i, j+1); } } static void tok_dropMetaComments(List<String> tok) { int i = -1; while ((i = jfind(tok, i+1, "meta-comment {")) >= 0) { int iOpening = indexOf(tok, i, "{"); int iClosing = findEndOfBracketPart(tok, iOpening)-1; clearTokens_reTok(tok, i, iClosing+1); } } // TODO: sometimes equals/hashCode is not generated. See an old version of #1026301 static boolean tok_recordDecls_autoWithToList = true; static void tok_recordDecls(List<String> tok) { int i; boolean re = false; jreplace(tok, "record <id> > <id> {", "record $2 extends $4 {"); jreplace(tok, "record <id> > <id><<id>> {", "record $2 extends $4 $5 $6 $7 {"); jreplace(tok, "record <id> {", "record $2() {"); jreplace(tok, "record <id> implements", "record $2() implements"); jreplace(tok, "record <id> extends", "record $2() extends"); while ((i = jfind_any(tok, "record <id>(", "record <id><")) >= 0) { int argsFrom = smartIndexOf(tok, i, "(")+2; int argsTo = findCodeTokens(tok, argsFrom, false, ")"); int idx = findCodeTokens(tok, argsTo, false, "{"); int j = findEndOfBracketPart(tok, idx); String name = tok.get(i+2); int iMod = tok_leftScanCustomModifiers(tok, i, addAllAndReturnCollection(litset("noeq", "flexeq", "noToString", "withToList", "transformable"), getJavaModifiers())); Set<String> mods = codeTokensAsSet(subList(tok, iMod-1, i)); clearTokensExceptFromSet(tok, iMod, i-1, getJavaModifiers()); boolean withToList = mods.contains("withToList"); withToList = withToList || tok_recordDecls_autoWithToList; StringBuilder buf = new StringBuilder(); List<String> tArgs = subList(tok, argsFrom-1, argsTo); List<Pair<String, String>> args = tok_typesAndNamesOfParams(tArgs, "typelessMeansObject" , true); List<String> contents = subList(tok, idx+1, j); boolean hasDefaultConstructor = tok_hasDefaultConstructor(contents, name); for (Pair<String, String> p : args) buf.append("\n " + jreplace(p.a, "...", "[]") + " " + p.b + ";"); if (nempty(args) && !hasDefaultConstructor) buf.append("\n *() {}"); buf.append("\n *(" + joinWithComma(map(args, new F1<Pair<String, String>, String>() { public String get(Pair<String, String> p) { try { return dropPrefix("new ", p.a) + " *" + p.b; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "dropPrefix(\"new \", p.a) + \" *\" + p.b"; }})) + ") {}"); if (!mods.contains("noToString") && !(jfind(contents, "toString {") >= 0 || jfind(contents, "toString()") >= 0)) buf.append("\n toString { ret " + "shortClassName_dropNumberPrefix(this) + \"(\" + " + join(" + \", \" + ", secondOfPairs(args)) + " + \")\"; }"); if (!mods.contains("noeq")) { //buf.append("\n [stdEq]"); boolean flexEq = mods.contains("flexeq"); // fix for records inside of parameterized classes buf.append(tok_genEqualsAndHashCode(name, args, "flexEq", flexEq)); } if (withToList) buf.append(tok_genRecordFieldsToList(args)); boolean transformable = mods.contains("transformable"); if (transformable) buf.append(tok_genRecordTransformable(name, args)); String interfaces = joinNemptiesWithComma( withToList ? "IFieldsToList" : "", transformable ? "Transformable, Visitable" : ""); tok.set(idx, (empty(interfaces) ? "" : (contains(subList(tok, argsTo, idx), "implements") ? "," : "implements") + " " + interfaces) + "{" + buf); tok.set(i, "class"); clearTokens(tok, argsFrom-2, argsTo+1); reTok(tok, i, idx+1); // no static fields allowed in non-static classes (for whatever reason) if (contains(tok_modifiersLeftOf(tok, i), "static")) tok_addFieldOrder(tok, i); re = true; } if (re) reTok(tok); } static void tok_singleQuoteIdentifiersToStringConstants(List<String> tok) { for (int i = 1; i < l(tok); i += 2) { String t = tok.get(i); if (isSingleQuoteIdentifier(t)) tok.set(i, quote(substring(t, 1))); } } static void tok_inStringEvals(List<String> tok) { boolean change = false; for (int i = 1; i < tok.size(); i += 2) { String t = tok.get(i); if (!isQuoted(t)) continue; if (t.contains("\\*") && !t.contains("\\\\")) { // << rough tok.set(i, transpile_inStringEval(t)); change = true; } } if (change) reTok(tok); } static void tok_listComprehensions(List<String> tok) { if (!tok.contains("[")) return; for (int i = 1; i < l(tok); i += 2) try { { if (!(eq(tok.get(i), "["))) continue; } int iOp = indexOfAny(tok, i+2, "?", ":", "in", "[", "]"); if (iOp < 0) return; if (!eqOneOf(tok.get(iOp), ":", "in")) continue; // not a list comprehension if (eqGet(tok, iOp+2, ".")) continue; // "in." (in is a variable name) Map<Integer, Integer> bracketMap = getBracketMap(tok); // XXX - optimize String type = joinSubList(tok, i+2, iOp-3), id = tok.get(iOp-2); int j = scanOverExpression(tok, bracketMap, iOp+2, "|"); String exp = join(subList(tok, iOp+2, j)); j += 2; int k = scanOverExpression(tok, bracketMap, j, "]"); String where = join(subList(tok, j, k)); ++k; String code = "filter(" + exp + ", func(" + type + " " + id + ") -> Bool { " + where + " })"; replaceTokens(tok, i, k, code); reTok(tok, i, k); } catch (Throwable _e) { print("Was processing list comprehension: " + joinSubList(tok, i, i+30) + "..."); throw rethrow(_e); } } /* event change; => transient L<Runnable> onChange; selfType onChange(Runnable r) { onChange = syncAddOrCreate(onChange, r); this; } void change() { pcallFAll(onChange); } */ static void tok_eventFunctions(List<String> tok) { int i; while ((i = jfind(tok, "event <id>")) >= 0) { int iSemicolon = i+4; List<String> tokArgs = null; if (eqGet(tok, i+4, "(")) { int argsFrom = i+6; int argsTo = findCodeTokens(tok, argsFrom, false, ")"); tokArgs = subList(tok, argsFrom-1, argsTo); iSemicolon = argsTo+2; } // TODO for next version: parse modifiers in square brackets //if (eqGet(tok, iSemicolon, "[")) if (neqGet(tok, iSemicolon, ";")) throw fail("Semicolon expected at end: " + joinSubList(tok, i, iSemicolon+1)); String change = tok.get(i+2); String onChange = "on" + firstToUpper(change); List<Pair<String, String>> args = tok_typesAndNamesOfParams(tokArgs); List<String> types = pairsA(args); String args1 = join(dropFirstAndLast(tokArgs)); String args2 = joinWithComma(pairsB(args)); String typeParams = joinWithComma(map(__46 -> tok_toNonPrimitiveTypes(__46), types)); String listenerType = empty(args) ? "Runnable" : "IVF" + l(args) + "<" + typeParams + ">"; String r = empty(args) ? "r" : "f"; replaceTokens_reTok(tok, i, iSemicolon+1, ("transient L<" + listenerType + "> " + onChange + ";\n") + ("selfType " + onChange + "(" + listenerType + " " + r + ") { " + onChange + " = syncAddOrCreate(" + onChange + ", " + r + "); this; }\n") + ("void " + change + "(" + args1 + ") { pcallFAll(" + (joinNemptiesWithComma(onChange, args2)) + "); }") ); } } // for single () iterates once when the expression is not null // and zero times when it is null. // It was actually used once. static void tok_for_single(List<String> tok) { int i = -1; while ((i = jfind(tok, i+1, "for single (")) >= 0) { int iColon = indexOf(tok, ":", i); int iClosing = findEndOfBracketPart(tok, iColon)-1; tok.set(iColon, ": singletonUnlessNull("); tok.set(iClosing, "))"); clearTokens(tok, i+2, i+4); reTok(tok, i, iClosing+1); } } static void tok_for_unpair(List<String> tok) { jreplace(tok, "for (unpair <id> <id>, <id> :", "for (unpair $4 $5, $4 $7 :"); jreplace(tok, "for (<id> <id>, <id> : unpair", "for (unpair $3 $4, $3 $6 :"); jreplace(tok, "for (<id> <id>, <id> <id> : unpair", "for (unpair $3 $4, $6 $7 :"); int i = -1; while ((i = jfind(tok, i+1, "for (unpair <id> <id>, <id> <id> :")) >= 0) { String type1 = tok.get(i+6), var1 = tok.get(i+8); String type2 = tok.get(i+12), var2 = tok.get(i+14); int iColon = indexOf(tok, ":", i); int iClosing = findEndOfBracketPart(tok, iColon)-1; int iCurly = iClosing+2; tok_statementToBlock(tok, iCurly); String pairVar = makeVar(); replaceTokens(tok, i+4, iColon-1, tok_toNonPrimitiveTypes("Pair<" + type1 + ", " + type2 + ">") + " " + pairVar); tok.set(iCurly, "{ " + type1 + " " + var1 + " = pairA(" + pairVar + "); " + type2 + " " + var2 + " = pairB(" + pairVar + "); "); reTok(tok, i, iCurly+1); } } static boolean tok_doubleFor_v3_debug = false; static void tok_doubleFor_v3(List<String> tok) { for (int i : reversed(indexesOf(tok, "for"))) { if (neq(get(tok, i+2), "(")) continue; int argsFrom = i+4; // move loop label to proper place if (eqGet(tok, i-2, ":") && isIdentifier(get(tok, i-4))) i -= 4; int iColon = indexOfAny(tok, argsFrom, ":", ")"); if (neq(get(tok, iColon), ":")) continue; if (tok_doubleFor_v3_debug) print("have colon"); tok_typesAndNamesOfParams_keepModifiers.set(true); List<Pair<String, String>> args; try { args = tok_typesAndNamesOfParams(subList(tok, argsFrom-1, iColon-1)); } catch (Throwable _e) { print("tok_doubleFor_v3: Skipping parsing complicated for statement (probably not a double for)"); continue; } if (l(args) != 2) continue; // simple for or a three-argument for (out of this world!) // S a, b => S a, S b if (eq(second(args).a, "?")) second(args).a = first(args).a; if (tok_doubleFor_v3_debug) print("have 2 args: " + sfu(args)); int iClosing = tok_findEndOfForExpression(tok, iColon+2); if (iClosing < 0) continue; if (tok_doubleFor_v3_debug) print("have closing"); String exp = trimJoinSubList(tok, iColon+2, iClosing-1); if (tok_doubleFor_v3_debug) print("Expression: " + exp); int iCurly = iClosing+2; tok_statementToBlock(tok, iCurly); int iCurlyEnd = tok_findEndOfStatement(tok, iCurly)-1; if (iCurlyEnd < 0) continue; if (tok_doubleFor_v3_debug) print("have curly end"); tokAppend(tok, iColon, " _entrySet("); tokPrepend(tok, iClosing, ")"); String entryVar = makeVar(); replaceTokens(tok, argsFrom, iColon-1, "Map.Entry<? extends " + tok_toNonPrimitiveTypes(first(first(args))) + ", ? extends " + tok_toNonPrimitiveTypes(first(second(args))) + "> " + entryVar); /*"Map.Entry<" + first(first(args)) + ", " + first(second(args)) + "> " + entryVar);*/ tokAppend(tok, iCurly, " " + joinPairWithSpace(first(args)) + " = " + entryVar + ".getKey(); " + joinPairWithSpace(second(args)) + " = " + entryVar + ".getValue(); "); reTok(tok, i, iCurlyEnd+1); } } static void tok_forUnnull(List<String> tok) { jreplace(tok, "fOr (", "for unnull ("); int i = -1; while ((i = jfind(tok, i+1, "for unnull (")) >= 0) { int argsFrom = i+4; int iColon = indexOf(tok, i, ":"); int iClosing = tok_findEndOfForExpression(tok, iColon+2); clearTokens(tok, i+2, i+4); tokPrepend(tok, iColon+2, "unnullForIteration("); tokPrepend(tok, iClosing, ")"); reTok(tok, i+2, iClosing+1); } } static void tok_ifCast(List<String> tok) { int i; while ((i = jfind_check("cast", tok, "if (<id> cast <id>")) >= 0) { int iEndOfType = indexOfAny(tok, i, ")", "&"); int iClosing = tok_endOfExpression(tok, i+4)+1; String var = tok.get(i+4), type = joinSubList(tok, i+8, iEndOfType-1); String rawType = tok_dropTypeParameters(type); int start = iClosing+2, end = tok_findEndOfStatement(tok, start); replaceTokens(tok, i+6, iEndOfType-1, "instanceof " + rawType); // replace "var" with "((Type) var)" in enclosed block // unless it's another cast expression or an assignment printVars("iEndOfType", iEndOfType, "iClosing", iClosing, "iClosing" , get(tok, iClosing), "start", start, "start" , get(tok, start), "end", end, "lTok" , l(tok)); end = min(end, l(tok)); for (int j = iEndOfType; j < end; j += 2) if (eq(tok.get(j), var) && neqGet(tok, j-2, ".") && neqGetOneOf(tok, j+2, "cast", "(") && !tok_isAssignment(tok, j+2)) tok_insertCast(tok, j, type); reTok(tok, i+6, end); } } // # 123 => "#123" static void tok_directSnippetRefs(List<String> tok) { int i = -1; while ((i = jfind(tok, i+1, "#<int>", new TokCondition() { public boolean get(final List<String> tok, final int i) { return !eqOneOf(_get(tok, i-1), "include", "once"); }})) >= 0) { String id = tok.get(i+2); clearTokens(tok, i+1, i+3); tok.set(i, quote("#" + id)); reTok(tok, i, i+3); } } static void tok_doPing(List<String> tok) { jreplace(tok, "do ping {", "do { ping();"); int i; while ((i = jfind(tok, "do ping <id>")) >= 0) { int j = tok_findEndOfStatement(tok, i+4); tok.set(i+2, "{ ping();"); tokAppend(tok, j-1, " }"); reTok(tok, i, j); } } // keyword can comprise multiple tokens now (like "p-awt"} static List<String> replaceKeywordBlock(List<String> tok, String keyword, String beg, String end) { return replaceKeywordBlock(tok, keyword, beg, end, false, null); } static List<String> replaceKeywordBlock(List<String> tok, String keyword, String beg, String end, Object cond) { return replaceKeywordBlock(tok, keyword, beg, end, false, cond); } static List<String> replaceKeywordBlock(List<String> tok, String keyword, String beg, String end, boolean debug, Object cond) { for (int n = 0; n < 1000; n++) { int i = jfind(tok, keyword + " {", cond); if (i < 0) break; int idx = findCodeTokens(tok, i, false, "{"); int j = findEndOfBracketPart(tok, idx); if (debug) { print(toUpper(keyword) + " BEFORE\n" + join(subList(tok, i, j))); print(" THEN " + join(subList(tok, j, j+10))); } //assertEquals("}", tok.get(j-1)); List<String> subList = subList(tok, i-1, idx); // N to somewhere tok.set(j-1, jreplaceExpandRefs(end, subList)); replaceTokens(tok, i, idx+1, jreplaceExpandRefs(beg, subList)); reTok(tok, i, j); if (debug) print(toUpper(keyword) + "\n" + join(subList(tok, i, j)) + "\n"); } return tok; } // finds "<keyword> <quoted> {" // func: tok, C token index of keyword -> S[] {beg, end} static List<String> replaceKeywordPlusQuotedBlock(List<String> tok, String keyword, Object func) { for (int i = 0; i < 1000; i++) { int idx = jfind(tok, keyword + " <quoted> {"); if (idx < 0) break; int j = findEndOfBracketPart(tok, idx+4); String[] be = (String[]) callF(func, tok, idx); tok.set(idx, be[0]); clearTokens(tok, idx+1, idx+5); tok.set(j-1, be[1]); reTok(tok, idx, j); } return tok; } static int jfind(String s, String in) { return jfind(javaTok(s), in); } static int jfind(List<String> tok, String in) { return jfind(tok, 1, in); } static int jfind(List<String> tok, int startIdx, String in) { return jfind(tok, startIdx, in, null); } static int jfind(List<String> tok, String in, Object condition) { return jfind(tok, 1, in, condition); } static int jfind(List<String> tok, String in, ITokCondition condition) { return jfind(tok, 1, in, condition); } static int jfind(List<String> tok, int startIndex, String in, ITokCondition condition) { return jfind(tok, startIndex, in, (Object) condition); } static int jfind(List<String> tok, int startIdx, String in, Object condition) { //LS tokin = jfind_preprocess(javaTok(in)); return jfind(tok, startIdx, javaTokForJFind_array(in), condition); } // assumes you preprocessed tokin static int jfind(List<String> tok, List<String> tokin) { return jfind(tok, 1, tokin); } static int jfind(List<String> tok, int startIdx, List<String> tokin) { return jfind(tok, startIdx, tokin, null); } static int jfind(List<String> tok, int startIdx, String[] tokinC, Object condition) { return findCodeTokens(tok, startIdx, false, tokinC, condition); } static int jfind(List<String> tok, int startIdx, List<String> tokin, Object condition) { return jfind(tok, startIdx, codeTokensAsStringArray(tokin), condition); } static List<String> jfind_preprocess(List<String> tok) { for (String type : litlist("quoted", "id", "int")) replaceSublist(tok, ll("<", "", type, "", ">"), ll("<" + type + ">")); replaceSublist(tok, ll("\\", "", "*"), ll("\\*")); return tok; } // Return value is index of semicolon/curly brace+1 static int tok_findEndOfStatement(List<String> tok, int i) { // Is it a block? if (eq(get(tok, i), "{")) return findEndOfBlock(tok, i); // It's a regular statement. Special handling of "for" and "if" int j = i; boolean special = false; while (j < l(tok) && neq(tok.get(j), ";")) { String t = get(tok, j); if (eqOneOf(t, "for", "if")) special = true; if (eqOneOf(t, "{", "(")) { j = findEndOfBracketPart(tok, j)+1; if (special && eq(t, "{")) return j-1; } else j += 2; } return j+1; } static TokCondition tokCondition_beginningOfMethodDeclaration() { return new TokCondition() { public boolean get(final List<String> tok, final int i) { return eqOneOf(_get(tok, i-1), "}", ";", "{", null, ""); // "" is there to hopefully handle badly re-toked includes preceding the declaration }}; } static boolean neqGet(List l, int i, Object o) { return neq(get(l, i), o); } static void tok_moduleClassDecls(List<String> tok) { jreplace(tok, "module <id> {", "module $2 extends DynModule {"); jreplace(tok, "module {", "module " + stefansOS_defaultModuleClassName() + " {"); jreplace(tok, "module > <id>", "module " + stefansOS_defaultModuleClassName() + " > $3"); int i = -1; while ((i = jfind(tok, i+1, "module <id>")) >= 0) { int j = findEndOfBlock(tok, indexOf(tok, "{", i))-1; String name = tok.get(i+2); tok.set(i, "sclass"); tokAppend(tok, j, "\nsbool _moduleClass_" + name + " = true;"); // just a marker to quickly find module classes reTok(tok, j, j+1); } } static <A> A _get(List<A> l, int idx) { return l != null && idx >= 0 && idx < l(l) ? l.get(idx) : null; } static Object _get(Object o, String field) { return get(o, field); } static Object _get(String field, Object o) { return get(o, field); } static <A> A _get(A[] l, int idx) { return idx >= 0 && idx < l(l) ? l[idx] : null; } // func : func(LS tok, int iOpening, int iClosing) -> S[] {beg, end} static List<String> replaceKeywordBlock_dyn2_legacy(List<String> tok, String keyword, Object func) { for (int i = 0; i < 1000; i++) { //int idx = findCodeTokens(tok, keyword, "{"); int idx = jfind(tok, keyword + " {"); if (idx < 0) break; int idx2 = findCodeTokens(tok, idx, false, "{"); int j = findEndOfBracketPart(tok, idx2); String[] be = (String[]) callF(func, tok, idx2, j-1); replaceTokens(tok, idx, idx2+2, be[0] + " "); tok.set(j-1, be[1]); reTok(tok, idx, j); } return tok; } static boolean startsWithLowerCaseOrUnderscore(String s) { return nempty(s) && (s.startsWith("_") || Character.isLowerCase(s.charAt(0))); } static boolean empty(Collection c) { return c == null || c.isEmpty(); } static boolean empty(Iterable c) { return c == null || !c.iterator().hasNext(); } static boolean empty(CharSequence s) { return s == null || s.length() == 0; } static boolean empty(Map map) { return map == null || map.isEmpty(); } static boolean empty(Object[] o) { return o == null || o.length == 0; } static boolean empty(Object o) { if (o instanceof Collection) return empty((Collection) o); if (o instanceof String) return empty((String) o); if (o instanceof Map) return empty((Map) o); if (o instanceof Object[]) return empty((Object[]) o); if (o instanceof byte[]) return empty((byte[]) o); if (o == null) return true; throw fail("unknown type for 'empty': " + getType(o)); } static boolean empty(Iterator i) { return i == null || !i.hasNext(); } static boolean empty(double[] a) { return a == null || a.length == 0; } static boolean empty(float[] a) { return a == null || a.length == 0; } static boolean empty(int[] a) { return a == null || a.length == 0; } static boolean empty(long[] a) { return a == null || a.length == 0; } static boolean empty(byte[] a) { return a == null || a.length == 0; } static boolean empty(short[] a) { return a == null || a.length == 0; } static boolean empty(MultiSet ms) { return ms == null || ms.isEmpty(); } static boolean empty(File f) { return getFileSize(f) == 0; } static boolean empty(IntRange r) { return r == null || r.empty(); } stat [...]
Began life as a copy of #759
full source download show line numbers debug dex old transpilations
Travelled to 2 computer(s): bhatertpkbcr, mqqgnosmbjvj
No comments. add comment
Snippet ID: | #1032684 |
Snippet name: | #759 transpilation backup |
Eternal ID of this version: | #1032684/1 |
Text MD5: | 7b7244b5016b2b09008f7304bfefdb62 |
Author: | stefan |
Category: | javax |
Type: | JavaX source code (desktop) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2021-10-01 23:22:41 |
Source code size: | 826505 bytes / 28369 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 383 / 401 |
Referenced in: | -