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 java.util.function.*; 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 java.awt.geom.*; import javax.imageio.*; import java.math.*; import java.time.Duration; import java.lang.invoke.VarHandle; import java.lang.invoke.MethodHandles; 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.nio.charset.Charset; import java.awt.geom.*; import java.text.NumberFormat; import java.text.SimpleDateFormat; import javax.imageio.metadata.*; import javax.imageio.stream.*; import static x30_pkg.x30_util.DynamicObject; import java.text.*; import java.nio.file.Files; import java.nio.file.Path; import java.util.TimeZone; 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 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 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); } @Override public void visit(EnumDeclaration n, Object arg) { 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 m = n.getModifiers(); //print("Method found: " + n.getName() + " with modifiers: " + m + ", position: " + n.getRange()->begin); if (!m.contains(com.github.javaparser.ast.Modifier.privateModifier())) { makePublic(m); } /*else if (!m.contains(Modifier.staticModifier()) && !m.contains(Modifier.finalModifier())) m.add(Modifier.finalModifier());*/ 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, true); 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 tok, String... tokens) { return findCodeTokens(tok, 1, false, tokens); } static int findCodeTokens(List tok, boolean ignoreCase, String... tokens) { return findCodeTokens(tok, 1, ignoreCase, tokens); } static int findCodeTokens(List tok, int startIdx, boolean ignoreCase, String... tokens) { return findCodeTokens(tok, startIdx, ignoreCase, tokens, null); } static HashSet findCodeTokens_specials = lithashset("*", "", "", "", "\\*"); static int findCodeTokens_bails, findCodeTokens_nonbails; static interface findCodeTokens_Matcher { boolean get(String token); } static int findCodeTokens(List 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 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("")) matcher = t -> isQuoted(t); else if (p.equals("")) matcher = t -> isIdentifier(t); else if (p.equals("")) 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 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 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; static String mainSnippetID; // snippet to compile - for usePerProgramPreloads static boolean usePerProgramPreloads = true; // _registerThread usually costs nothing because we need // the registerWeakHashMap mechanism anyway for ping(). // Anyway - no forced functions for now :) static List functionsToAlwaysInclude = ll( //"_registerThread", //"asRuntimeException" ); // classes with two type parameters that can written with just one // e.g. Pair => Pair static Set pairClasses = lithashset("Pair", "Either", "Map", "AbstractMap", "HashMap", "TreeMap", "LinkedHashMap", "MultiMap", "CompactHashMap", "WrappedMap", "F1", "IF1", "AllOnAll", "AllOnAllWithUpdates", "MultiSetMap", "AutoMap", "ValueOnDemandMap", "NavigableMap", "SortedMap", "BijectiveMap", "PairCollector", "IF2_OOInt"); // classes with 3 type parameters that can written with just one // e.g. T3 => T3 static Set tripleClasses = lithashset("T3", "IF2", "F2", "IVF3", "VF3"); static String transpilingSnippetID; //static new AtomicInteger varCount; static ThreadLocal varCountByThread = new ThreadLocal(); static Map snippetCache = syncMap(); // Which snippets were actually requested during transpilation static Set cacheRequested; // Which snippets were required when this program was last transpiled? // (So we can preload them all.) static Map> preloadsPerProgram = mruCache(500); static boolean useTokenIndexedList = true; static boolean opt_javaTok = true; static boolean cacheStdFunctions = true, cacheStdClasses = true; static HashMap cachedIncludes = new HashMap(); static ExecutorService executor; static Map standardClassesMap; static long startTime, lastPrint; // These variables have to be cleared manually for each transpilation static HashSet included = new HashSet(); static NavigableSet definitions = ciSet(); static HashMap rewrites = new HashMap(); static HashSet shouldNotIncludeFunction = new HashSet(); // this verifies after the fact that the function was not included static HashSet shouldNotIncludeClass = new HashSet(); static HashSet doNotIncludeFunction = new HashSet(); // this actually prevents the function from being included static Map functionToStaticHolder = new HashMap(); static HashSet doNotIncludeClass = new HashSet(); static HashSet needLatest = new HashSet(); // this forces a function to be included static HashSet addedFunctions = new HashSet(); static HashSet addedClasses = new HashSet(); static HashSet hardFunctionReferences = new HashSet(); static HashSet mapLikeFunctions = new HashSet(); static HashSet lambdaMapLikeFunctions = new HashSet(); static HashSet curry1LikeFunctions = new HashSet(); static HashSet mapMethodLikeFunctions = new HashSet(); static HashSet nuLikeFunctions = new HashSet(); static HashSet getLikeFunctions = new HashSet(); // name is slightly misleading. this turns a pre-argument into a fieldLambda static HashSet lambdaMethod0LikeFunctions = new HashSet(); // we're getting better again with the names (maybe) static HashSet lambda0LikeFunctions = new HashSet(); static HashSet lambda2LikeFunctions = new HashSet(); static Map extraStandardFunctions; static boolean quickmainDone1, quickmainDone2; static TreeSet 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 metaPostBlocks, metaTransformers, localTransformers; static boolean dontPrintSource = false; // disabling this because of the changed-include-early-in-standard-class problem static boolean dontLoadCachedIncludesFromVM = true; static boolean saveCachedIncludesInVM = false; static HashSet haveClasses = new HashSet(); static class CachedInclude { String javax; Future java; String realJava; long snippetID; CachedInclude() {} CachedInclude(long snippetID) { this.snippetID = snippetID;} String java() { return realJava != null ? realJava : getFuture(java); } Future 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) { pcallFail(__e); } executor = Executors.newFixedThreadPool(numberOfCores()); transpilingSnippetID = or(getThreadLocal((ThreadLocal) getOpt(javax(), "transpilingSnippetID")), transpilingSnippetID); //print(+transpilingSnippetID); transpileRaw_dontCopyFromCreator = true; final Object oldPrint = or(print_byThread().get(), "print_raw"); AutoCloseable __19 = tempInterceptPrint(new F1() { 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(__19); }} static void _main() { try { if (sameSnippetID(programID(), defaultJavaXTranslatorID())) setDefaultJavaXTranslatorID("#7"); //reTok_modify_check = 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)); if (usePerProgramPreloads && nempty(mainSnippetID)) { var preloads = preloadsPerProgram.get(fsI(mainSnippetID)); print("Preloading " + nSnippets(preloads) + " for " + mainSnippetID); cachePreload(preloads); } // clear things cacheRequested = syncSet(); includeInMainLoaded_magicComment = null; included.clear(); definitions.clear(); definitions.add("true"); rewrites.clear(); // XXX definitions.add("SymbolAsString"); shouldNotIncludeFunction.clear(); shouldNotIncludeClass.clear(); doNotIncludeFunction.clear(); functionToStaticHolder.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(); lambda2LikeFunctions.clear(); extraStandardFunctions = new HashMap(); libs.clear(); mainBaseClass = mainPackage = mainClassName = null; varCountByThread.set(null); quickmainDone1 = quickmainDone2 = false; metaPostBlocks = new ArrayList(); metaTransformers = new ArrayList(); localTransformers = 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 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)) { print("DEFAULT TRANSLATE"); 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 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, __20 -> isDefined(__20)); defineMapLikesEtc(tok); 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 (", mainClassName() + ".$2("); grabImportedStaticFunctions(tok); jreplace_dyn_allowNull(tok, "main ", (_tok, cIdx, end) -> { String fname = _tok.get(cIdx+2); boolean isClass = haveClasses.contains(fname); //printVars expandMainRef(+fname, +isClass); if (isClass || eqGet(_tok, cIdx+4, "(")) { String holder = functionToStaticHolder.get(fname); //printVars expandMainRef(+holder); String call = "." + fname; return or(holder, mainClassName()) + call; } return null; }); // references to global function holder jreplace_dyn_allowNull(tok, "mainFunctionHolder ", (_tok, cIdx, end) -> { String fname = _tok.get(cIdx+2); String holder = functionToStaticHolder.get(fname); return or(holder, mainClassName()) + ".class"; }); try { if (safety == 0) tok = quickmain(tok); } catch (Throwable e) { printSources(tok); rethrow(e); } tok_collectMetaPostBlocks(tok, metaPostBlocks); tok_collectTransformers(tok, metaTransformers); tok_collectTransformers(tok, localTransformers, "meta-transformLocal"); 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, Integer, String>() { public String get(List tok, Integer cIndex) { try { try { return "class " + stringToLegalIdentifier(getSnippetTitle(transpilingSnippetID)); } catch (Throwable __e) { pcallFail(__e); } return "class Whatever"; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "pcall { ret \"class \" + stringToLegalIdentifier(getSnippetTitle(transpilingSni..."; }}); tok_elegantVSInlined(tok); 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 functions = new HashSet(findFunctions(tok)); for (String f : hardFunctionReferences) if (!functions.contains(f)) warn("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() { 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); } 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); if (usePerProgramPreloads && nempty(mainSnippetID)) preloadsPerProgram.put(fsI(mainSnippetID), cacheRequested); } catch (Exception __e) { throw rethrow(__e); } } static List localStuff1(List tok) { int safety = 0, i; boolean same = false; tok = indexTokenList(tok); tok_scopes(tok, "autoCloseScopes" , true); do { ping(); List 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_eventInterfaces(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); tok_castQuestionDot(tok); jreplace(tok, "LLS", "L"); jreplace(tok, "LS", "L"); jreplace(tok, "LByte", "L"); jreplace(tok, "ES", "Ext"); jreplace(tok, "ExtS", "Ext"); jreplace(tok, "ClS", "Cl"); jreplace(tok, "WeakRef", "WeakReference"); jreplace(tok, "dispose ;", "{ cleanUp($2); $2 = null; }"); tok_doPing(tok); 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 tok, final int i) {", "}}"); jreplace(tok, "synced ", "synchronized $2"); jreplace(tok, "sync ", "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 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, "cachedVisualize {", //"public transient simplyCached JComponent visualize() {"); "public transient simplyCached JComponent visualize() { ret markVisualizer(this, visualize_impl()); }\n" + "JComponent visualize_impl() {"); 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 tok, final int i) { return neqGet(tok, i-1, "void"); }}; // run { ... } => public void run() { ... } // same with close // These need to be ctex as AutoCloseable and Runnable don't allow explicit exceptions jreplace(tok, "run {", "public void run() ctex {", notVoidMethod); jreplace(tok, "close {", "public void close() ctex {", notVoidMethod); replaceKeywordBlock(tok, "html", "static O html(S uri, fMap 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 ", "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"); jreplace(tok, "SymbolSymbol", "Map"); jreplace(tok, "CISet", "Set"); jreplace(tok, "MapSO", "Map"); jreplace(tok, "ByName<", "IF1>", "IF1<$3>"); jreplace(tok, "ITransform", "IF1"); jreplace(tok, "PairS", "Pair"); jreplace(tok, "LPairS", "L>"); jreplace(tok, "T3S", "T3"); jreplace(tok, "F1S", "F1"); jreplace(tok, "ItIt", "IterableIterator"); jreplace(tok, "CloseableItIt", "CloseableIterableIterator"); // ">" instead of "extends" for (String keyword : ll("class", "interface")) { jreplace(tok, (keyword + " > "), "$1 $2 extends $4", new TokCondition() { public boolean get(final List tok, final int i) { String t = _get(tok, i+1+4*2); return eq(t, "{") || isIdentifier(t); }}); jreplace(tok, (keyword + " > <> {"), "$1 $2 extends $4 $5 $6 $7 {"); jreplace(tok, (keyword + " <> > "), "$1 $2<$4> extends $7"); } jreplace(tok, "ISegmenter", "IF1>"); // IPred => IF2 jreplace(tok, "IPred<, >", "IF2<$3, $5, Bool>"); // IPred => IF1 jreplace(tok, "IPred<>", "IF1<$3, Bool>"); jreplace(tok, "IPred<[]>", "IF1<$3[], Bool>"); // Proposition => WithReasoning (should we really define this?) jreplace(tok, "Proposition", "WithReasoning"); 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 ", new Object() { String[] get(List 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 ", new Object() { String[] get(List 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) {"); jreplace_dyn(tok, "catch print {", () -> { String var = makeVar(); return ("catch " + var + " { printStackTrace(" + var + ");"); }); // "catch print e {" => "catch e { printStackTrace(e); " jreplace(tok, "catch print {", "catch $3 { printStackTrace($3);"); // "catch print short e {" => "catch e { printExceptionShort(e); " jreplace(tok, "catch print short {", "catch $4 { printExceptionShort($4);"); // "catch X e {" => "catch (X e) {" jreplace(tok, "catch {", "catch ($2 $3) {"); // "catch e {" => "catch (Throwable e) {" (if e is lowercase) jreplace(tok, "catch {", "catch (Throwable $2) {", new TokCondition() { public boolean get(final List tok, final int i) { String word = tok.get(i+3); return startsWithLowerCaseOrUnderscore(word); }}); jreplace(tok, "+ +", "+", new TokCondition() { public boolean get(final List 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); }"); jreplace(tok, "for ( :", "for (var $3 :"); jreplace(tok, "for ( )", "for ($3 $4 : list($3))"); jreplace(tok, "for (final )", "for (final $4 $5 : list($4))"); tok_retShortForReturn(tok); // "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, ", if null;", new TokCondition() { public boolean get(final List 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 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 ; => { if (var) return; set var; } jreplace(tok, "return unless set ;", "{ if ($4) return; set $4; }"); // set x; => x = true; // yeah it doesn't save many characters, but I like it jreplace(tok, "set ;", "$2 = true;", new TokCondition() { public boolean get(final List 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 !;", "$3 = false;"); // unset x; => x = false; jreplace(tok, "unset ;", "$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 if" // "return with " / "continue with " / "break with " while ((i = jfind(tok, " with", new TokCondition() { public boolean get(final List 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 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 while ((i = jfindOneOf(tok, "return with", "return 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, " not null (", new TokCondition() { public boolean get(final List 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, " null (", new TokCondition() { public boolean get(final List 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 ", "instanceof $3"); jreplace(tok, "! instanceof .", "!($2 instanceof $4.$6)"); jreplace(tok, "! instanceof ", "!($2 instanceof $4)"); jreplace(tok, " !instanceof ", "!($1 instanceof $4)"); // map func1 func2 func3(...) => mapFGH(f func1, f func2, f func3, ...) jreplace(tok, "map (", "mapFGH(f $2, f $3, f $4,"); // map func1 func2(...) => mapFG(f func1, f func2, ...) jreplace(tok, "map (", "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, " ->", "$1.get()."); jreplace(tok, "->", ".get().", new TokCondition() { public boolean get(final List 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 ;", "$2 = trim($2);"); // iterate with index tok_forOver(tok); jreplace (tok, "for to :", "for (int $2 = 0; $2 < $4; $2++)"); jreplace (tok, "for to :", "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 + r ", "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 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 + " {")) >= 0) { int idx = findCodeTokens(tok, i, false, "{"); int j = findEndOfBracketPart(tok, idx); List 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 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 => ret "OK" with [probably outdated] jreplace(tok, "ok ", "return \"OK\" with $2", (_tok, nIdx) -> !eqGetOneOf(_tok, nIdx+3, "aka")); replaceKeywordBlock(tok, "ok", "{", " return \"OK\"; }", new F2, Integer, Boolean>() { public Boolean get(List _tok, Integer nIdx) { try { //print("ok construct: " + subList(_tok, nIdx-1, nIdx+4)); return !eqGetOneOf(_tok, nIdx-1, "void", "svoid"); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "//print(\"ok construct: \" + subList(_tok, nIdx-1, nIdx+4));\r\n ret\r\n ..."; }}); // OLD SHIZ //tok_identifierSemicolonAsFunctionCall(tok); // NEW SHIZ!! new Tok_IdentifierSemicolonToReturnStatement(tok).run(); // shorter match syntax for answer methods tok_expandIfQuoted(tok); jreplace(tok, "if eq ", "if (eq($2, $4))"); tok_dropExtraCommas(tok); // additional translations (if necessary) jreplace(tok, "pcall ping {", "pcall { ping();"); replaceKeywordBlock(tok, ") pcall", ") { pcall {", "}}"); //jreplace(tok, "void pcall {", "$1 $2() pcall {"); tok_pcall(tok); 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 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 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 tok, int iOpening, int iClosing) { List 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); } // , print "..."; => { ; print("..."); } while ((i = jfind(tok, ", print ;")) >= 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 => if ( == 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 =")) >= 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 ()", (_tok, cIdx) -> { String type = _tok.get(cIdx+6); return "try object " + type + " " + makeVar() + " = (" + type + ")"; }); // try object (return if not null) - now with auto-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, "{ var " + 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 =")) >= 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 ")) >= 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 star constructors because tok_expandStarConstructors // doesn't like a meta command in front of it tok_delegateTo(tok); tok_replaceWith(tok); tok_replaceVarWith(tok); tok_exclamPostfix(tok); // before temp blocks tok_varNamedLikeFunction(tok); tok_onCleanExit(tok); tempBlocks(tok); // after quicknew2 for stuff like "temp new X x;" // X x = nu(+...) => X x = nu X(+...) jreplace(tok, " = nu(+", "$1 $2 = nu $1(+"); // X x = nu(a := ...) => X x = nu X(a := ...) jreplace(tok, " = nu( :=", "$1 $2 = nu $1($6 :="); tok_expandVarCopies(tok); // AFTER the lines just above tok_replaceColonEqualsSyntax(tok); // ditto tok_unpair(tok); tok_cachedFunctions_new(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 ", " 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 {", "$1 $2() {"); jreplace(tok, "void thread {", "$1 $2() thread {"); jreplace(tok, "String {", "$1 $2() {"); jreplace(tok, "Object {", "$1 $2() {"); jreplace(tok, "List {", "$1 $2() {"); namedThreads(tok); threads(tok); //tok_maxEquals(tok); tok_questionDot(tok); jreplace(tok, "if (?!)", "if ($3 != null && $3!)"); tok_embeddedFunctions(tok); tok_quickNewArray(tok); jreplace(tok, "[] = new {", "$1[] $4 = {"); jreplace(tok, " ifNull =", "if ($1 == null) $1 ="); jreplace(tok, "class extends <.>", "class $2 extends $4<$2.$7>"); tok_once(tok); // must come before next line so you can combine them tok_ifRecordMatch(tok); jreplace(tok, " ||=", "$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 ", "print($2);"); tok_tildeCalls(tok); tok_svoidEtc(tok); tok_swappableFunctions(tok); tok_optParLambda(tok); tok_runnableClasses(tok); tok_swapStatement(tok); //defineMapLikesEtc(tok); tok_optionalArguments(tok); tok_usualDefaults(tok); tok_defaultArguments_debug = isDef("tok_defaultArguments_debug"); tok_defaultArguments(tok); tok_akaFunctionNames(tok); tok_simplyCachedFunctions(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 : {", "for (var $2 : $4) {"); tok_shortLambdas(tok); if (metaCodeAllowed()) runTransformers(tok, localTransformers); tok_andVarMixIn(tok); tok_stages(tok); tok_beginPeriod(tok); tok_enterStatement(tok); tok_settableFields(tok); tok_reImmutableVars(tok); tok_scaffoldedFunctions(tok); while ((i = jfind(tok, "scaffoldPrint(")) >= 0) { tokReplace_reTok(tok, i, i+4, "if (scaffoldingEnabled(this)) scaffoldCalled(this, "); tok_statementToBlock(tok, i); } jreplace(tok, " from method;", "var $1 = $1();"); tok_whileCast(tok); tok_multiTypeArguments_v2(tok); tok_printIfdef(tok); // Doing this later than voidfunc, quicknew etc // because it relies on detecting anonymous classes tok_swingBlocks(tok); tok_defEquals(tok); tok_swapFunctions(tok); tok_dotPlus(tok); // end of local stuff tok_processMetaBlocks(tok, metaCodeAllowed()); if (metaCodeAllowed()) runTransformers(tok, metaTransformers); 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 reTok_include(List tok, int i, int j) { return reTok_modify(__51 -> localStuff1(__51), tok, i, j); } static List includeInMainLoaded_reTok(List tok, int i, int j) { return reTok_include(tok, i, j); } static List stdstuff(List tok) { //if (++level >= 10) fail("woot? 10"); print("stdstuff!"); int i; List 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 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 multilineStrings(List 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_relaxedMLS(t))); } return tok; } static List quickmain(List 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 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 rtq(List tok, String id) { return runTranslatorQuick(tok, id); } static List expandShortTypes(List tok) { // replace with 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); } for (var __17 : _entrySet( javaxClassShortcuts())) { var key = __17.getKey(); var val = __17.getValue(); jreplace(tok, key, val); } var tcShortPrimitive = new TokCondition() { public boolean get(final List tok, final int i) { return neqGetOneOf(tok, i+3, "(", null); }}; // bool -> boolean if it's not a function name jreplace(tok, "bool", "boolean", tcShortPrimitive); // dbl x; => double x; // BUT: void dbl() => dbl() jreplace(tok, "dbl", "double", tcShortPrimitive); jreplace(tok, "Dbl", "Double", tcShortPrimitive); jreplace(tok, "AtomicBool", "AtomicBoolean"); jreplace(tok, "AtomicInt", "AtomicInteger"); tok_selfNestedType(tok, "LL", "L", true); tok_selfNestedType(tok, "MatrixOfMatrices", "Matrix", false); jreplace(tok, "LPt", "L"); jreplace(tok, "Clusters< >", "Map<$3, Collection<$3>>"); return tok; } static List autoImports(List tok) { HashSet 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 tok_processIncludes(List tok) { int safety = 0; while (hasCodeTokens(tok, "!", "include") && ++safety < 100) tok = tok_processIncludesSingle(tok); //tok_autoCloseBrackets(tok); return tok; } static void tok_processEarlyIncludes(List tok) { int i; while ((i = jfind_check("include", tok, "!include early #")) >= 0) { String id = tok.get(i+8); included.add(parseLong(id)); replaceTokens_reTok(tok, i, i+10, "\n" + cacheGet(id) + "\n"); } // !include string (include as string constant) // doing this early because it didn't work in imports otherwise while ((i = jfind_check("include", tok, "!include string #")) >= 0) { String id = tok.get(i+8); included.add(parseLong(id)); replaceTokens_reTok(tok, i, i+10, quote(cacheGet(id))); } } static List tok_processIncludesSingle(List tok) { // simple !include int i; while ((i = jfind_check("include", tok, "!include #")) >= 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); } // !include once while ((i = jfind_check("include", tok, "!include once #")) >= 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 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 dialogHandler(List tok) { return replaceKeywordBlock(tok, "dialogHandler", "new DialogHandler() {\n" + "public void run(final DialogIO io) {", "}}"); } static List extendClasses(List tok) { int i; while ((i = jfind(tok, "extend {")) >= 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 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 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 tok) { int i; while ((i = jfind(tok, "lib ")) >= 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 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 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 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 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 args = cloneSubList(tok, argsFrom-1, argsTo); tok_shortFinals(args); tok_toNonPrimitiveTypes(args); List 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 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 args = cloneSubList(tok, argsFrom-1, argsTo); tok_shortFinals(args); tok_toNonPrimitiveTypes(args); List 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 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 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); } } // fail(); => throw fail(); // unimplemented(); => throw unimplemented(); // etc static void throwFailEtc(List tok) { boolean anyChange = false; for (int i = 1; i+4 < l(tok); i += 2) if (eqOneOf(get(tok, i+2), "fail", "todo", "unimplemented") && 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 tok) { for (int i = 0; i < 100; i++) { int idx = findCodeTokens(tok, "thread", "", "{"); if (idx < 0) idx = findCodeTokens(tok, "thread", "", "{"); 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 tok) { for (int i = 0; i < 100; i++) { int idx = findCodeTokens(tok, "r", "-", "thread", "", "{"); if (idx < 0) idx = findCodeTokens(tok, "r", "-", "thread", "", "{"); 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 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 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 sf; // standard standard functions (haha) static Boolean _761ok; static List standardFunctions(List tok) { if (sf == null) { String _761 = cacheGet("#761"); if (_761ok == null) _761ok = isBracketHygienic(_761); assertTrue("Whoa! #761 truncated?", _761ok); List 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 sfMap = combinedMap(extraStandardFunctions, sf); for (int i = 0; ; i++) { print("Looking for required functions"); Set 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")) >= 0) { int k = j+4; while (!eqGetOneOf(tok, k, ".", null)) { String t = tok.get(k); if (isIdentifier(t)) { needLatest.add(t); doNotIncludeClass.remove(t); } k += 2; } clearTokens_reTok(tok, j, k+2); } grabImportedStaticFunctions(tok); doNotIncludeFunction.removeAll(needLatest); // changes tok //Set invocations = findFunctionInvocations(tok, sfMap, hardFunctionReferences, defd, true, mainClassName()); Set invocations = findFunctionInvocations_v2(tok, sfMap, hardFunctionReferences, defd, true, mainClassName(), containsKeyPredicate(standardClassesMap())); /*if (invocations.contains("str")) print("==STR==" + join(tok) + "==STR==");*/ if (!cic(definitions, "leanMode")) invocations.addAll(functionsToAlwaysInclude); //print("Functions invoked: " + structure(invocations)); Set needed = setMinusSet(invocations, defd); for (String f : doNotIncludeFunction) needed.remove(f); if (needed.isEmpty()) break; print("Adding functions: " + join(" " , needed)); Collection bad = setIntersection(needed, shouldNotIncludeFunction); if (nempty(bad)) { String msg = "INCLUDING BAD FUNCTIONS: " + sfu(bad); print(msg); print(join(tok)); throw fail(msg); } List added = new ArrayList(); List> parts = new ArrayList(); List 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() { 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 newFunctions = new HashSet(findFunctionDefsAtCurlyLevel(0, 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, __21 -> isDefined(__21)); if (i >= 1000) throw fail("Too many iterations"); } return tok; } static List findFunctions(List tok) { return findFunctionDefsAtCurlyLevel(1, findMainClass(tok)); } static String cacheGet(String snippetID) { snippetID = formatSnippetID(snippetID); cacheRequested.add(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 tok = javaTok(text); tok_scopes(tok, "autoCloseScopes" , true); text = join(tok); } snippetCache.put(snippetID, text); } return text; } static void cachePreload(Collection ids) { List needed = new ArrayList(); for (String id : unnullForIteration(ids)) if (!snippetCache.containsKey(formatSnippetID(id))) needed.add(formatSnippetID(id)); if (l(needed) > 1) { List 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 jtok(List tok) { return jtok(join(tok)); } static List jtok(String s) { return indexTokenList(javaTok(s)); } static HashSet haveClasses_actual(List tok) { HashSet have = new HashSet(); for (List c : innerClassesOfMain(tok)) have.add(getClassDeclarationName(c)); return have; } static HashSet haveClasses_addImported(List tok, HashSet have) { return haveClasses_addImported(tok, have, true); } static HashSet haveClasses_addImported(List tok, HashSet have, boolean mainLevel) { have.addAll(setMinusSet( tok_importedClassNames(tok, mainLevel ? (__22, __23) -> onImportFound(__22, __23) : null), needLatest)); have.addAll(usualJavaClassNames()); // for S => S.class return have; } static Map standardClassesMap() { if (standardClassesMap == null) { standardClassesMap = new HashMap(); for (String snippetID : standardClassesSnippetIDs()) { String sc = cacheGet(snippetID); for (String line : tlft_j(sc)) { int idx = line.indexOf('/'); standardClassesMap.put(line.substring(0, idx), fsI(line.substring(idx+1))); } } } return standardClassesMap; } // works on Java level (no "sclass" etc) // returns list of classes we have (useful for other processing) static HashSet addStandardClasses_v2(List tok) { for (int safety = 0; safety < 10; safety++) { HashSet 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 need = new HashMap(); Set snippets = new HashSet(); Set idx = tokenIndexWithoutIfclass_forStdClasses(tok); while ((j = jfind(tok, "please include class *.")) >= 0) { String cname = tok.get(j+6); print("Found: please include class " + cname); idx.add(cname); clearAllTokens(subList(tok, j, j+10)); } for (var __16 : _entrySet( standardClassesMap())) { var className = __16.getKey(); var snippetID = __16.getValue(); 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> 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); snippetID = fsI(snippetID); String text = cacheGet(snippetID); print("Added class " + className + " / " + snippetID + ", md5: " + md5(text)); text += "\n"; var _text_24 = text; assertTrue(cacheStdClasses); long _id = psI(snippetID); // mark as included (the continue should never happen) if (!included.add(_id)) continue; CachedInclude ci = cachedIncludes.get(_id); if (ci == null) cachedIncludes.put(_id, ci = new CachedInclude(_id)); if (neq(ci.javax, _text_24)) { print("Compiling class: " + className); ci.javax = _text_24; ci.java = executor.submit(new Callable() { 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_24))); } }); ci.realJava = null; } parts.add(pair(className, ci)); } StringBuilder buf = new StringBuilder(); for (Pair p : parts) { String className = p.a; List ct = javaTok(p.b.java()); Map rewritten = new HashMap(); tok_findAndClearRewrites(ct, rewritten); if (rewritten.containsKey(className)) have.add(className); for (List 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 expandableClassNames = lithashset("BigInteger"); // no reTok - leaves tok dirty // magically append ".class" to class name references static void expandClassReferences_lazy(List tok, Set classNames) { expandClassReferences_lazy(tok, classNames, null); } static void expandClassReferences_lazy(List tok, Set classNames, List 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, 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 or IF3 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 tok, Set classNames) { List reToks = new ArrayList(); expandClassReferences_lazy(tok, classNames, reToks); reTok_multi(tok, reToks); } // "/" => "((ClassName) )" static void slashCasts(List tok, final Set classNames) { /*jreplace(tok, "/", "(($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) + ")"); } // "(...)" => "new (...)" // doesn't work at beginning of statement as we can't easily // distinguish it from a constructor declaration. static void newWithoutNew(List tok, final Set classNames) { TokCondition cond = newWithoutNew_condition(classNames); jreplace(tok, "(", "new $1(", cond); // just two cases with type args for now jreplace(tok, "<>(", "new $1<$3>(", cond); jreplace(tok, "<>(", "new $1<>(", cond); } static TokCondition newWithoutNew_condition(final Set classNames) { return new TokCondition() { public boolean get(final List 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 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 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) || eq(t, "-") && eqGet(tok, i+3, "") && isInteger(get(tok, i+4)))) tok.set(i, "_case"); } } static void continueAsFunctionName(List tok) { jreplace(tok, "continue(", "_continue("); } // f bla => "bla" - and "please include function bla." static void functionReferences(List tok) { int i; if (definitions.contains("callF_legacy")) { jreplace_dyn(tok, "f-thread ", new F2, Integer, Object>() { public Object get(List 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 + " ", new TokCondition() { public boolean get(final List 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 tok, final int i) { return !eqOneOf(tok.get(i+3), "instanceof", "aka", "default") && !eq(_get(tok, i-1), "cast"); }}, "r ", "rThread ", "rEnter ", "rThreadEnter ", "rEnterThread ")) >= 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 ", "r_dm_q(r $2)"); // vf fname => voidfunc(S s) { fname(s) } jreplace(tok, "vf<> ", "voidfunc($3 a) { $5(a) }"); // vf> fname => voidfunc(L a) { fname(a) } jreplace(tok, "vf<<>> ", "voidfunc($3<$5> a) { $8(a) }"); // construct Entry => func(S s) -> Entry { new Entry(s) } jreplace(tok, "construct<> ", "func($3 a) -> $5 { new $5(a) }"); // f fname => func -> S { fname() } jreplace(tok, "f<> ", "func -> $3 { $5() }"); // f fname => func(S x) -> S { fname(x) } jreplace(tok, "f<, > ", "func($3 x) -> $5 { $7(x) }"); // f> fname => func(S x) -> L { fname(x) } jreplace(tok, "f<, <>> ", "func($3 x) -> $5 $6 $7 $8 { $10(x) }"); // f, S> fname => func(L x) -> S { fname(x) } jreplace(tok, "f<<>, > ", "func($3 $4 $5 $6 x) -> $8 { $10(x) }"); // f, S> fname => func(S x, L y) -> S { fname(x, y) } jreplace(tok, "f<, <>, > ", "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 + " ", new F2, Integer, String>() { public String get(List 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 tok) { jreplace(tok, "nu (", "nu($2.class, "); // not needed anymore jreplace(tok, "nu ", "new $2"); } // fill variable innerClasses_list static void innerClassesVar(List tok, Set 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 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 tok, Set have) { tok_conditionals(tok, "ifclass", "endif", id -> contains(have, id), ifclass_reTokImmediately, ifclass_noReTok); } // set flag *. static void tok_definitions(List tok) { int i; while ((i = jfind_check("flag", tok, "set flag .")) >= 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 .")) >= 0) { String fname = tok.get(i+4); print("Unsetting flag " + fname); definitions.remove(fname); clearAllTokens(subList(tok, i, i+8)); } } // rewrite [=|with|to] // - a global version of "replace 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 [=|with|to] // - a global version of "replace with" // old version (works) static void tok_findAndClearRewrites(List tok) { tok_findAndClearRewrites(tok, null); } static void tok_findAndClearRewrites(List tok, Map newlyDefined) { int i; while ((i = jfind(tok, "rewrite ", (_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); if (mapPut_trueIfChanged(rewrites, token, replacement)) { boolean reify = definitions.contains("ReifyRewrites"); print("Have rewrite (reify " + reify + "): " + token + " => " + replacement); if (reify) tokSet_reTok(tok, i, "static { defineRewrite(" + quoted(token) + ", " + quoted(replacement) + "); }\n"); } } } static void tok_processRewrites(List tok) { for (String token : keys(rewrites)) jreplace(tok, token, rewrites.get(token)); } // extend *. (set base class of main class) static void tok_extend(List tok) { int i; while ((i = jfind(tok, "extend .")) >= 0) { mainBaseClass = tok.get(i+2); clearAllTokens(tok, i, i+7); } } // process ifndef x ... endifndef blocks static void tok_ifndef(List tok) { tok_conditionals(tok, "ifndef", "endifndef", id -> !definitions.contains(id), true, false); } static void conceptDeclarations(List tok) { for (String kw : ll("concept", "sconcept")) { if (!contains(tok, kw)) continue; // condition is a side effect in this case Object cond = new TokCondition() { public boolean get(final List tok, final int i) { tok_addFieldOrder(tok, i+1); return true; }}; boolean change = false; if (jreplace(tok, kw + " {", "static class $2 extends Concept {", cond)) change = true; if (jreplace(tok, kw + " implements", "static class $2 extends Concept implements", cond)) change = true; // TODO: general type parsing if (jreplace(tok, kw + " < extends > {", "static class $2<$4 extends $6> extends Concept {", cond)) change = true; if (jreplace(tok, kw + " ", "static class $2", cond)) change = true; if (change) reTok(tok); } } static void shortenedSubconcepts(List tok) { jreplace(tok, " > {", "concept $3 extends $1 {", new TokCondition() { public boolean get(final List 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 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 tok) { int i; while ((i = jfind(tok, "lock ", new TokCondition() { public boolean get(final List 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 tok) { int i; jreplace_dyn(tok, "temp () ", (_tok, cIdx) -> { String var = makeVar(), type = tok.get(cIdx+4), firstTokenOfExpr = tok.get(cIdx+8); return ("temp " + type + " " + var + " = cast " + firstTokenOfExpr); }); jreplace(tok, "temp =", "temp var $2 ="); while ((i = jfindOneOf(tok, "temp ", "temp !")) >= 0) { int semicolon = findEndOfStatement(tok, i)-1; int endOfOuterBlock = findEndOfBracketPart(tok, semicolon)-1; List sub = subList(tok, i-1, semicolon); // find initializer int eq = !isIdentifier(sub.get(3)) ? -1 : 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, ""); 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(); if (saveCachedIncludesInVM) vmKeepWithProgramMD5_save("cachedIncludes"); } static void printSources(List tok) { String src = join(tok); print("----"); print(src); print("----"); var bh = testBracketHygiene2(src); if (bh != null) print("Bracket hygiene error: " + bh); } static void tok_quickInstanceOf(List tok, final Set haveClasses) { if (!quickInstanceOfEnabled) return; // "x << X" or "x >> X" => "x instanceof X" for (String op : ll("<<", ">>")) jreplace(tok, " " + op + " ", "$1 instanceof $4", new TokCondition() { public boolean get(final List tok, final int i) { return haveClasses.contains(tok.get(i+7)) && !eqOneOf(tok.get(i-1), "<", "extends", "implements"); }}); } final static boolean isDef(String s){ return hasDef(s); } final static boolean isDefined(String s){ return hasDef(s); } static boolean hasDef(String s) { return definitions.contains(s); } static void tok_shortFinals(List 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 tok) { int i; if ((i = jfind(tok, "mainClassName ")) >= 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 ")) >= 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 defineMapLikesEtc(List tok) { defineMapLikes(tok); defineLambdaMapLikes(tok); defineCurry1Likes(tok); defineMapMethodLikes(tok); defineNuLikes(tok); defineXLikes(tok, "getLike", getLikeFunctions); defineXLikes(tok, "lambdaMethod0Like", lambdaMethod0LikeFunctions); defineXLikes(tok, "lambda0Like", lambda0LikeFunctions); defineXLikes(tok, "lambda2Like", lambda2LikeFunctions); } static void defineMapLikes(List tok) { int i; while ((i = jfind(tok, "mapLike ")) >= 0) { mapLikeFunctions.add(printIf(printMapLikes(), "mapLike", tok.get(i+2))); clearTokens_reTok(tok, i, i+2); } } static void defineLambdaMapLikes(List tok) { int i; while ((i = jfind(tok, "lambdaMapLike ")) >= 0) { lambdaMapLikeFunctions.add(printIf(printMapLikes(), "lambdaMapLike", tok.get(i+2))); clearTokens_reTok(tok, i, i+2); } } static void defineCurry1Likes(List tok) { int i; while ((i = jfind(tok, "curry1Like ")) >= 0) { curry1LikeFunctions.add(printIf(printMapLikes(), "curry1Like", tok.get(i+2))); clearTokens_reTok(tok, i, i+2); } } static void defineMapMethodLikes(List tok) { int i; while ((i = jfind(tok, "mapMethodLike ")) >= 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 tok) { int i; while ((i = jfind(tok, "nuLike ")) >= 0) { nuLikeFunctions.add(printIf(printMapLikes(), "nuLike", tok.get(i+2))); clearTokens_reTok(tok, i, i+2); } } static void defineXLikes(List tok, String keyword, Set xLikeFunctions) { int i; while ((i = jfind(tok, keyword + " ")) >= 0) { xLikeFunctions.add(printIf(printMapLikes(), keyword, tok.get(i+2))); clearTokens_reTok(tok, i, i+2); } } static void defineExtraSF(List tok) { int i; IntRange reTok = null; while ((i = jfind(tok, "function 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 tok) { List reToks = new ArrayList(); for (int i : jfindAll(tok, " (")) { 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 + ","); else if (contains(lambda2LikeFunctions, f)) replacement = (f + "(lambda2 " + 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 mapLikeFunctions) { // map funcname(...) => map(f funcname, ...) // filter funcname(...) => filter(f funcname, ...) // ... ret jreplace(tok, " (", "$1(f $2,", func(L tok, int i) -> bool { contains(mapLikeFunctions, tok.get(i+1)) }); }*/ /*sbool tok_applyLambdaMapLikeFunctions(LS tok, final Set lambdaMapLikeFunctions) { // mapNonNulls funcname(...) => mapNonNulls(lambda1 funcname, ...) // mapKeysAndValues funcname(...) => mapKeysAndValues(lambda1 funcname, ...) // ... ret jreplace(tok, " (", "$1(lambda1 $2,", func(L tok, int i) -> bool { contains(lambdaMapLikeFunctions, tok.get(i+1)) }); }*/ /*sbool tok_applyCurry1LikeFunctions(LS tok, final Set curry1LikeFunctions) { // curry1 funcname(...) => curry1(lambda2 funcname, ...) ret jreplace(tok, " (", "$1(lambda2 $2,", func(L tok, int i) -> bool { contains(curry1LikeFunctions, tok.get(i+1)) }); }*/ /*sbool tok_applyMapMethodLikeFunctions(LS tok, final Set mapMethodLikeFunctions) { // mapMethod funcname(...) => mapMethod('funcname, ...) // collect funcname(...) => collect('funcname, ...) // ... ret jreplace_dyn(tok, " (", func(L tok, int cIdx) -> S { tok.get(cIdx) + "(" + quote(tok.get(cIdx+2)) + "," }, func(L tok, int i) -> bool { contains(mapMethodLikeFunctions, tok.get(i+1)) }); }*/ static void runMetaPostBlocks(List 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 runTransformers(List tok, List transformers) { for (String code : unnullForIteration(transformers)) { ping(); tok_runMetaTransformer(tok, code); } } /*sbool tok_applyNuLikeFunctions(LS tok, final Set nuLikeFunctions) { // nu ClassName(...) => nu(ClassName, ...) // ... ret jreplace_dyn(tok, " (", func(L tok, int cIdx) -> S { tok.get(cIdx) + "(" + tok.get(cIdx+2) + ".class," }, func(L tok, int i) -> bool { contains(nuLikeFunctions, tok.get(i+1)) }); }*/ /*sbool tok_applyGetLikeFunctions(LS tok, Set getLikeFunctions) { // get fieldName(...) => get(fieldLambda fieldName, ...) // ... ret jreplace_dyn(tok, " (", func(L tok, int cIdx) -> S { tok.get(cIdx) + "(lambdaField " + tok.get(cIdx+2) + "," }, func(L tok, int i) -> bool { contains(getLikeFunctions, tok.get(i+1)) }); }*/ static boolean metaCodeAllowed() { return allowMetaCode || containsIC(definitions, "allowMetaCode"); } static List indexTokenList(List tok) { if (useTokenIndexedList) return tokenIndexedList3(tok); return tok; } static void tok_earlyGeneralStuff(List 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 ", "implements $2", new TokCondition() { public boolean get(final List tok, final int i) { return !eqGet(tok, i-3, "if") // tok_ifRecordMatch // "is a", "is in" are defined as something else && !eqGetOneOf(tok, i+3, "a", "in", "default"); }}); } static void lambdaReferences(List tok) { // lambda0 myFunction => () -> myFunction() for (String keyword : ll("lambda0", "l0")) jreplace(tok, keyword + " ", "() -> $2()"); // lambda1 myFunction => var123 -> myFunction(var123) for (String keyword : ll("lambda1", "l1")) jreplace_dyn(tok, keyword + " ", new F2, Integer, Object>() { public Object get(List 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) for (String keyword : ll("lambda2", "l2")) jreplace_dyn(tok, keyword + " ", new F2, Integer, Object>() { public Object get(List 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*/) -> \\*to..."; }}); // methodLambda0 methodName => var123 -> var123.methodName() jreplace_dyn(tok, "methodLambda0 ", new F2, Integer, Object>() { public Object get(List 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 ", new F2, Integer, Object>() { public Object get(List 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; standardClassesMap = null; } static void mediumRefresh() { clearSnippetCache(); print("Medium-refreshed transpiler " + mc()); } static void jreplace_performing(List 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 tok) { for (String name : unnullForIteration(tok_importedStaticFunctionNamesWithPackages_v2(tok))) { int idx = lastIndexOf(name, '.'); String holderFQN = takeFirst(idx, name); String functionName = dropFirst(idx+1, name); //print(functionName + " => " + pkg); doNotIncludeFunction.add(functionName); functionToStaticHolder.put(functionName, holderFQN); } } static boolean printMapLikes = false; static boolean printMapLikes() { return printMapLikes || contains(definitions, "printMapLikesEtc"); } // delete import if marked as "need latest" static void onImportFound(List tok, IntRange r) { String id = get(tok, r.end-3); if (needLatest.contains(id)) { print("Purging import: " + joinSubList(tok, r)); // request standard class again (sometimes necessary) boolean isSC = standardClassesMap().containsKey(id); if (isSC) { print("Re-including class " + id); replaceTokens_reTok(tok, r, "please include class " + id + ". "); } else 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 c == null ? "null" : new String(c); } static String str(char[] c, int offset, int count) { return new String(c, offset, count); } static boolean boolOptPar(ThreadLocal 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 HashSet lithashset(A... items) { HashSet 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 boolean printAlsoToSystemOut = true; 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 print_byThread; // special handling by thread - prefers F1 static volatile Object print_allThreads; static volatile Object print_preprocess; static void print() { print(""); } static A print(String s, A o) { print(combinePrintParameters(s, o)); return o; } // slightly overblown signature to return original object... static 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); if (printAlsoToSystemOut) System.out.print(s); vmBus_send("printed", mc(), s); } static void print_autoRotate() { } static boolean checkTokCondition(Object condition, List tok, int i) { if (condition instanceof TokCondition) return ((TokCondition) condition).get(tok, i); return checkCondition(condition, tok, i); } static List 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 Map syncMap() { return synchroHashMap(); } static Map syncMap(Map map) { return synchronizedMap(map); } static Map mruCache(int maxSize) { return synchronizedMRUCache(maxSize); } static TreeSet ciSet() { return caseInsensitiveSet(); } static A getFuture(Future f) { try { return f == null ? null : f.get(); } catch (Exception __e) { throw rethrow(__e); } } static NowFuture 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 void pcallFail(Throwable e) { pcallPolicyForThread().handlePcallFail(e); } static void pcallFail(String msg) { pcallFail(new Throwable(msg)); } static volatile int numberOfCores_value; static int numberOfCores() { if (numberOfCores_value == 0) numberOfCores_value = Runtime.getRuntime().availableProcessors(); return numberOfCores_value; } static 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 getThreadLocal(ThreadLocal tl) { return tl == null ? null : tl.get(); } static A getThreadLocal(ThreadLocal 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 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 f) { return tempSetThreadLocal(print_byThread(), f); } // get purpose 1: access a list/array/map (safer version of x.get(y)) static A get(List l, int idx) { return l != null && idx >= 0 && idx < l(l) ? l.get(idx) : null; } // seems to conflict with other signatures /*static B get(Map map, A key) { ret map != null ? map.get(key) : null; }*/ static 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> callF_cache = newDangerousWeakHashMap(); static A callF(F0 f) { return f == null ? null : f.get(); } static B callF(F1 f, A a) { return f == null ? null : f.get(a); } static A callF(IF0 f) { return f == null ? null : f.get(); } static B callF(IF1 f, A a) { return f == null ? null : f.get(a); } static B callF(A a, IF1 f) { return f == null ? null : f.get(a); } static C callF(F2 f, A a, B b) { return f == null ? null : f.get(a, b); } static C callF(IF2 f, A a, B b) { return f == null ? null : f.get(a, b); } static void callF(VF1 f, A a) { if (f != null) f.get(a); } static void callF(A a, IVF1 f) { if (f != null) f.get(a); } static void callF(IVF1 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) // no way josé return callMCWithVarArgs((String) f, args); 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 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 callF_makeCache(Class c) { ArrayList 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 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 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(BitSet bs) { return !empty(bs); } static boolean nempty(Map m) { return !empty(m); } static boolean nempty(Iterator i) { return i != null && i.hasNext(); } static boolean nempty(IMultiMap mm) { return mm != null && mm.size() != 0; } static boolean nempty(Object o) { return !empty(o); } static boolean nempty(IntRange r) { return !empty(r); } static boolean nempty(Rect r) { return r != null && r.w != 0 && r.h != 0; } static boolean nempty(IntSize l) { return l != null && l.size() != 0; } static String fsI(String id) { return formatSnippetID(id); } static String fsI(long id) { return formatSnippetID(id); } static String nSnippets(long n) { return n2(n, "snippet"); } static String nSnippets(Collection l) { return nSnippets(l(l)); } static String nSnippets(Map map) { return nSnippets(l(map)); } static Set syncSet() { return synchroHashSet(); } static Set syncSet(Collection l) { return addAllAndReturnCollection(synchroHashSet(), l); } static HashSet cloneHashSet(Collection set) { if (set == null) return new HashSet(); synchronized(collectionMutex(set)) { HashSet < A > s = new HashSet<>(l(set)); s.addAll(set); return s; } } static Set tok_mapLikeFunctions_set = emptySet(); static Set tok_mapLikeFunctions() { return tok_mapLikeFunctions_set; } static Set tok_mapMethodLikeFunctions_set = asHashSet( splitAtSpace("mapMethod uniquifyByField indexByField collect")); static Set tok_mapMethodLikeFunctions() { return tok_mapMethodLikeFunctions_set; } static boolean hasCodeTokens(List 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(IMultiMap mm) { return mm == null ? 0 : mm.size(); } static int l(IntRange r) { return r == null ? 0 : r.length(); } static int l(IntSize o) { return o == null ? 0 : o.size(); } static List singlePlusList(A a, Collection l) { return itemPlusList(a, l); } static Object first(Object list) { return first((Iterable) list); } static A first(List list) { return empty(list) ? null : list.get(0); } static A first(A[] bla) { return bla == null || bla.length == 0 ? null : bla[0]; } static Pair first(Map map) { return mapEntryToPair(first(entrySet(map))); } static Pair first(MultiMap mm) { if (mm == null) return null; var e = first(mm.data.entrySet()); if (e == null) return null; return pair(e.getKey(), first(e.getValue())); } static A first(IterableIterator i) { return first((Iterator) i); } static A first(Iterator i) { return i == null || !i.hasNext() ? null : i.next(); } static A first(Iterable i) { if (i == null) return null; Iterator 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 first(Pair p) { return p == null ? null : p.a; } static A first(T3 t) { return t == null ? null : t.a; } static Byte first(byte[] l) { return empty(l) ? null : l[0]; } static Double first(double[] l) { return empty(l) ? null : l[0]; } static A first(A[] l, IF1 pred) { return firstThat(l, pred); } static A first(Iterable l, IF1 pred) { return firstThat(l, pred); } static A first(IF1 pred, Iterable l) { return firstThat(pred, l); } static A first(AppendableChain a) { return a == null ? null : a.element; } 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 List dropFirst(List l) { return dropFirst(1, l); } static List dropFirst(int n, Iterable i) { return dropFirst(n, toList(i)); } static List dropFirst(Iterable i) { return dropFirst(toList(i)); } static List dropFirst(int n, List l) { return n <= 0 ? l : new ArrayList(l.subList(Math.min(n, l.size()), l.size())); } static List dropFirst(List 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); } static Chain dropFirst(Chain c) { return c == null ? null : c.next; } // TODO: extended multi-line strings static int javaTok_n, javaTok_elements; static boolean javaTok_opt = false; static List javaTok(String s) { ++javaTok_n; ArrayList 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 javaTok(List tok) { return javaTokWithExisting(join(tok), tok); } static void replaceTokens_reTok(List tok, int i, int j, String s) { replaceTokens(tok, i, j, s); reTok(tok, i, j); } static void replaceTokens_reTok(List tok, IntRange r, String s) { replaceTokens_reTok(tok, r.start, r.end, s); } static String unnull(String s) { return s == null ? "" : s; } static Collection unnull(Collection l) { return l == null ? emptyList() : l; } static List unnull(List 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 float[] unnull(float[] l) { return l == null ? emptyFloatArray() : l; } static Map unnull(Map l) { return l == null ? emptyMap() : l; } static Iterable unnull(Iterable i) { return i == null ? emptyList() : i; } static A[] unnull(A[] a) { return a == null ? (A[]) emptyObjectArray() : a; } static BitSet unnull(BitSet b) { return b == null ? new BitSet() : b; } static Pt unnull(Pt p) { return p == null ? new Pt() : p; } //ifclass Symbol static Symbol unnull(Symbol s) { return s == null ? emptySymbol() : s; } //endif static Pair unnull(Pair 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 String tok_moveImportsUp(String src) { return join(tok_moveImportsUp(javaTok(src))); } static List tok_moveImportsUp(List 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 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 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 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 libraries_out = new ArrayList(); List 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 String join(String glue, Iterable strings) { if (strings == null) return ""; if (strings instanceof Collection) { if (((Collection) strings).size() == 1) return strOrEmpty(first((Collection) strings)); } StringBuilder buf = new StringBuilder(); Iterator i = strings.iterator(); if (i.hasNext()) { buf.append(strOrEmpty(i.next())); while (i.hasNext()) buf.append(glue).append(strOrEmpty(i.next())); } return buf.toString(); } public static String join(String glue, String... strings) { return join(glue, Arrays.asList(strings)); } public static String join(String glue, Object... strings) { return join(glue, Arrays.asList(strings)); } static String join(Iterable strings) { return join("", strings); } static String join(Iterable 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); } // transformNow's are only run once static void tok_metaTransformNow(List 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); } } // legacy mode //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 ping_actions = newWeakHashMap(); static ThreadLocal ping_isCleanUpThread = new ThreadLocal(); // ignore pingSource if not PingV3 static boolean ping(PingSource pingSource) { return ping(); } // 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 ArrayList cloneList(Iterable l) { return l instanceof Collection ? cloneList((Collection) l) : asList(l); } static ArrayList cloneList(Collection l) { if (l == null) return new ArrayList(); synchronized(collectionMutex(l)) { return new ArrayList(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 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 tok, String in, String out) { return jreplace(tok, in, out, false, true, null); } static boolean jreplace(List tok, String in, String out, Object condition) { return jreplace(tok, in, out, false, true, condition); } static boolean jreplace(List tok, String in, ITokCondition condition, String out) { return jreplace(tok, in, out, (Object) condition); } static boolean jreplace(List tok, String in, String out, IF2, Integer, Boolean> condition) { return jreplace(tok, in, out, (Object) condition); } static boolean jreplace(List 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 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 tok) { int i; mainLoop: while ((i = jfind(tok, "selfType", (_tok, nIdx) -> { String prev = get(_tok, nIdx-1); String next = get(_tok, nIdx+3); return isIdentifier(next) || eqOneOf(next, ".", "(") || eq(prev, "(") && eq(next, ")") || eqOneOf(prev, "instanceof", "cast"); })) >= 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 (eqOneOf(t, "class", "interface", "enum") && isIdentifier(get(tok, j+2))) { String type = tok_typeArgs_declToInvocation(tok_scanType(tok, j+2)); if (eqGet(tok, i+2, ".") && eqGet(tok, i+4, "class")) type = tok_dropTypeParameters(type); tokSet_reTok(tok, i, type); continue mainLoop; } j -= 2; } tok.set(i, "Object"); // avoid endless loop if no outer class found } } // process ifdef x ... endifdef blocks static void tok_ifdef(List tok, IF1 isDefined) { // ifdef x or y jreplace_dyn(tok, "ifdef or ", (_tok, cIdx) -> { String flag1 = tok.get(cIdx+2), flag2 = tok.get(cIdx+6); boolean value = isDefined.get(flag1) || isDefined.get(flag2); //print("ifdef: " + flag1 + " | " + flag2 + " = " + value); return "ifdef " + value; }); tok_conditionals(tok, "ifdef", "endifdef", isDefined, true, false); } // extra commas - e.g. ll(1, 2,) => ll(1, 2) static void tok_dropExtraCommas(List tok) { jreplace(tok, ",)", ")"); } // 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 tok = javaTok(s); jreplace_dyn_allowNull(tok, in, replacer, condition); return join(tok); } static boolean jreplace_dyn_allowNull(List tok, String in, TokReplacer replacer) { return jreplace_dyn_allowNull(tok, in, replacer, null); } static boolean jreplace_dyn_allowNull(List tok, String in, TokReplacer replacer, ITokCondition condition) { return jreplace_dyn_allowNull(tok, in, replacer, condition, false, true); } static boolean jreplace_dyn_allowNull(List tok, String in, TokReplacer replacer, ITokCondition condition, boolean ignoreCase, boolean reTok) { List 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); } static boolean eqGet(List l, int i, Object o) { return eq(get(l, i), o); } static boolean eqGet(Map 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 tok, List 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 tok, List out) { tok_collectTransformers(tok, out, "meta-transform"); } static void tok_collectTransformers(List tok, List out, String keyword) { int i = -1; while ((i = jfind(tok, i+1, keyword + " {")) >= 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 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 tok, String in, String out) { return jreplace1(tok, in, out, false, true, null); } static boolean jreplace1(List tok, String in, String out, Object condition) { return jreplace1(tok, in, out, false, true, condition); } static boolean jreplace1(List tok, String in, String out, boolean ignoreCase, boolean reTok, Object condition) { List tokin = javaTok(in); jfind_preprocess(tokin); boolean anyChange = false; int i = 1; while ((i = findCodeTokens(tok, i, ignoreCase, toStringArray(codeTokensOnly(tokin)), condition)) >= 0) { List 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); int l = l(tok); if (reTok) // would this ever be false?? reTok(tok, i, end); i = end+l(tok)-l; anyChange = true; } return anyChange; } static boolean jreplace1_debug = false; // out: func(L tok, int cIndex) -> S // condition: func(L 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 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 tok, String in, Object out) { return jreplace_dyn(tok, in, out, false, true, null); } static boolean jreplace_dyn(List tok, String in, IF0 out) { return jreplace_dyn(tok, in, if0ToIF2(out)); } static boolean jreplace_dyn(List tok, String in, ITokCondition cond, IF0 out) { return jreplace_dyn(tok, in, cond, if0ToIF2(out)); } static boolean jreplace_dyn(List tok, String in, IF1 out) { return jreplace_dyn(tok, in, (_tok, cIdx) -> out.get(cIdx)); } static boolean jreplace_dyn(List tok, String in, IF2, Integer, String> out) { return jreplace_dyn(tok, in, (Object) out); } static boolean jreplace_dyn(List tok, String in, IF2, Integer, String> out, IF2, Integer, Boolean> condition) { return jreplace_dyn(tok, in, (Object) out, (Object) condition); } static boolean jreplace_dyn(List tok, String in, Object out, Object condition) { return jreplace_dyn(tok, in, out, false, true, condition); } static boolean jreplace_dyn(List tok, String in, Object out, boolean ignoreCase, boolean reTok, Object condition) { List 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_elegantVSInlined(List tok) { for (int i : rjfindAll(tok, "elegant {")) { int iElegant = i+2; int iEndOfElegant = tok_scanBlock_idx(tok, iElegant); int iEnd = iEndOfElegant; String replacement; if (eqGet(tok, iEndOfElegant, "inlined")) { int iInlined = iEndOfElegant+2; int iEndOfInlined = iEnd = tok_scanBlock_idx(tok, iInlined+2); replacement = joinSubList(tok, iInlined+1, iEndOfInlined-2); } else replacement = joinSubList(tok, iElegant+1, iEndOfElegant-2); tokReplace_reTok(tok, i, iEnd-1, replacement); } } static void tok_overridableFunctionDefs(List tok, Set overriableFunctions_out) { int i; while ((i = jfind(tok, "static overridable ")) >= 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(__52 -> tok_lastIdentifier(__52), 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 boolean warn_on = true; static ThreadLocal> warn_warnings = new ThreadLocal(); static void warn(String s) { if (warn_on) print("Warning: " + s); } static void warn(String s, List warnings) { warn(s); if (warnings != null) warnings.add(s); addToCollection(warn_warnings.get(), s); } static List tok_cleanImports(List tok) { List index = toContentsIndexedList(tok); List imports = tok_findImports_returnRanges(tok); BitSet exclude = new BitSet(); for (IntRange r : imports) set(exclude, r.end-4); List 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 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 boolean containsOneOf(Collection 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 boolean containsOneOf(Collection l, Set 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 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 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 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 tok, String s) { tokPrepend(tok, 0, s); } static void tokPrepend(List tok, int i, String s) { tok.set(i, s + tok.get(i)); } static List reTok(List tok) { replaceCollection(tok, javaTok(tok)); return tok; } static List reTok(List tok, int i) { return reTok(tok, i, i+1); } static List reTok(List 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 t = javaTok(joinSubList(tok, i, j)); replaceListPart(tok, i, j, t); // fallback to safety // reTok(tok); return tok; } static List reTok(List tok, IntRange r) { if (r != null) reTok(tok, r.start, r.end); return tok; } static String concatMap_strings(Object f, Iterable l) { return join((List) map(f, l)); } static String concatMap_strings(Object f, Object[] l) { return join((List) map(f, l)); } static String concatMap_strings(Iterable l, Object f) { return concatMap_strings(f, l); } static String concatMap_strings(Iterable l, IF1 f) { return concatMap_strings(f, l); } static String concatMap_strings(IF1 f, Iterable l) { return concatMap_strings((Object) f, l); } static String concatMap_strings(IF1 f, 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 tok) { try { splitJavaFiles(tok, newFile("output")); } catch (Exception __e) { throw rethrow(__e); } } static void splitJavaFiles(List tok, File outDir) { try { List 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 subtok = cncSubList(tok, from, to); String src = join(subtok); //print(shorten(src, 80)); String pack = tok_packageName(subtok); print("Package: " + quote(pack)); List> classes = allClasses(subtok); /*for (L 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 tok) throws IOException { saveMainJava(join(tok)); } // process scope x. ... end scope blocks static void tok_scopes(List tok, Object... __) { if (!tok.contains("scope")) return; boolean autoCloseScopes = boolPar("autoCloseScopes", __); // New syntax: scope bla { ... } replaceKeywordBlock(tok, "scope ", "scope $2. ", " end scope "); int i; // Old syntax: scope bla ... end scope while ((i = rjfind(tok, "scope ", (_tok, nIdx) -> !subListContains(_tok, nIdx-1, nIdx+6, "aka"))) >= 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 names = new HashSet(); HashSet functions = new HashSet(); clearTokens(tok, i, start-1); List 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+3); } } static void tok_dropMetaComments(List 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 tok) { int i; boolean re = false; jreplace(tok, "record > {", "record $2 extends $4 {"); jreplace(tok, "record > <> {", "record $2 extends $4 $5 $6 $7 {"); jreplace(tok, "record {", "record $2() {"); jreplace(tok, "record implements", "record $2() implements"); jreplace(tok, "record extends", "record $2() extends"); while ((i = jfind_any(tok, "record (", "record <")) >= 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 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 tArgs = subList(tok, argsFrom-1, argsTo); tok_typesAndNamesOfParams_keepModifiers.set(true); List> argsWithModifiers = tok_typesAndNamesOfParams(tArgs, "typelessMeansObject" , true); List> args = tok_typesAndNamesOfParams(tArgs, "typelessMeansObject" , true); List contents = subList(tok, idx+1, j); boolean hasDefaultConstructor = tok_hasDefaultConstructor(contents, name); // Make fields for (Pair p : argsWithModifiers) buf.append("\n " + jreplace(p.a, "...", "[]") + " " + p.b + ";"); if (nempty(args) && !hasDefaultConstructor) buf.append("\n *() {}"); // add full constructor if not there String ctorHead = "\n *(" + joinWithComma(map(args, p -> dropPrefix("new ", p.a) + " *" + p.b)) + ")"; var comments = trimAll(getJavaLineCommentsWithoutNestedBlocks(contents)); printVars("ctorHead", ctorHead, "comments", comments); if (!contains(comments, "!customConstructor") && jfind(contents, tok_escapeAsterisk(ctorHead)) < 0) buf.append(ctorHead + " {}"); // Make toString if (!mods.contains("noToString") && !(jfind(contents, "toString {") >= 0 || jfind(contents, "toString()") >= 0)) buf.append("\n toString { ret " + "shortClassName_dropNumberPrefix(this)" + (empty(args) ? "" : " + \"(\" + " + join(" + \", \" + ", secondOfPairs(args)) + " + \")\"") + "; }"); // Make equals and hashCode 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 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 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 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 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); } } // Yay funny naming time! ("shipping") /* transient event interface onRecordAdded as OnRecordAdded shipping RecordAdded; => stuff */ static void tok_eventInterfaces(List tok) { int i; while ((i = jfind(tok, "transient event interface as shipping ;")) >= 0) { int iStart = i; i += 2; int iSemicolon = indexOf(tok, iStart, ";"); String listenerType = get(tok, i+4); String method = get(tok, i+8); String eventType = get(tok, i+12); replaceTokens_reTok(tok, iStart, iSemicolon+1, tok_formatDollarVars("\r\n interface $intf {\r\n void $method($eventType event);\r\n }\r\n \r\n transient L<$Listener> $listeners;\r\n synchronized selfType $add($Listener l) { $listeners = addOrCreate($listeners, l); this; }\r\n synchronized Cl<$Listener> $listeners() { ret cloneList($listeners); }\r\n void $method($Event event) { for (l : $listeners()) pcall { l?.$method(event); } }\r\n ", "method", method, "intf" , listenerType, "eventType", eventType, "Event" , eventType, "add" , method, "Listener" , listenerType, "listeners" , method + "_listeners")); } } /* event change; => transient LinkedHashSet onChange; public selfType onChange(Runnable r) { onChange = syncAddOrCreate(onChange, r); this; } void change() { if (onChange != null) for (listener : onChange) pcallF_typed(listener); } ; } */ static void tok_eventFunctions(List tok) { int i; while ((i = jfind(tok, "event ", nIdx -> !eqGet(tok, nIdx+3, "aka"))) >= 0) { int iModifiers = tok_leftScanModifiers(tok, i); String modifiers = joinSubList(tok, iModifiers, i-1); int iSemicolon = i+4; List 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; } int iEnd = iSemicolon+1; String body = ""; if (eqGet(tok, iSemicolon, "{")) { iEnd = tok_findEndOfBlock(tok, iSemicolon); body = joinSubList(tok, iSemicolon+1, iEnd-1); } else if (neqGet(tok, iSemicolon, ";")) throw fail("Semicolon expected at end: " + joinSubList(tok, i, iSemicolon+1)); String change = tok.get(i+2), prefix = ""; if (startsWithCamelCaseWord(change, "on")) change = firstToLower(dropFirst(2, change)); else if (startsWithCamelCaseWord(change, "fire")) { prefix = "fire"; change = firstToLower(dropFirst(4, change)); } String onChange = "on" + firstToUpper(change); String removeListener = "remove" + firstToUpper(change) + "Listener"; List> args = tok_typesAndNamesOfParams(tokArgs); List types = pairsA(args); String args1 = join(dropFirstAndLast(tokArgs)); String args2 = joinWithComma(pairsB(args)); String typeParams = joinWithComma(map(__53 -> tok_toNonPrimitiveTypes(__53), types)); String listenerType = empty(args) ? "Runnable" : "IVF" + l(args) + "<" + typeParams + ">"; String r = empty(args) ? "r" : "f"; String fireChange = empty(prefix) ? change : prefix + firstToUpper(change); replaceTokens_reTok(tok, iModifiers, iEnd, (modifiers + " transient Set<" + listenerType + "> " + onChange + ";\n") + ("public " + modifiers + " selfType " + onChange + "(" + listenerType + " " + r + ") { " + onChange + " = createOrAddToSyncLinkedHashSet(" + onChange + ", " + r + "); this; }\n") + ("public " + modifiers + " selfType " + removeListener + "(" + listenerType + " " + r + ") { main remove(" + onChange + ", " + r + "); this; }\n") + ("public " + modifiers + " void " + fireChange + "(" + args1 + ") { " + body + " ") + ("if (" + onChange + " != null) for (listener : " + onChange + ") ") + "pcallF_typed(" + joinNemptiesWithComma("listener", 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 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 tok) { jreplace(tok, "for (unpair , :", "for (unpair $4 $5, $4 $7 :"); jreplace(tok, "for ( , : unpair", "for (unpair $3 $4, $3 $6 :"); jreplace(tok, "for ( , : unpair", "for (unpair $3 $4, $6 $7 :"); int i = -1; while ((i = jfind(tok, i+1, "for (unpair , :")) >= 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); } // typeless version i = -1; while ((i = jfind(tok, i+1, "for (, : unpair")) >= 0) { String var1 = tok.get(i+4); String var2 = tok.get(i+8); 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+3, "var " + pairVar + ":"); tok.set(iCurly, "{ " + "var " + var1 + " = pairA(" + pairVar + "); " + "var " + var2 + " = pairB(" + pairVar + "); "); reTok(tok, i, iCurly+1); } } static boolean tok_doubleFor_v3_debug = false; static void tok_doubleFor_v3(List tok) { // The problem with going all "var" is that // if the map is of a raw type (e.g. Map), _entrySet(map) is of type // Set which means we can't call getKey()/getValue() on the entries. // We can, however, all it for typed maps. jreplace(tok, "for (, :", "for (var $3, var $5 :"); 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> 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 keyType = first(first(args)); String valueType = first(second(args)); String entryVar = makeVar(); String entryType = eq(keyType, "var") || eq(valueType, "var") ? "var" : "Map.Entry"; replaceTokens(tok, argsFrom, iColon-1, entryType + " " + 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 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 tok) { int i; while ((i = jfind_check("cast", tok, "if ( cast ")) >= 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)); tok_insertCasts_noReTok(tok, iEndOfType, end, var, type); reTok(tok, i+6, end); } } // # 123 => "#123" static void tok_directSnippetRefs(List tok) { int i = -1; while ((i = jfind(tok, i+1, "#", new TokCondition() { public boolean get(final List 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); } } // a cast B ? a.b : ... // => a instanceof B ? ((B) a).b : ... static void tok_castQuestionDot(List tok) { for (int i : jfind_all_reversed(tok, " cast ?")) { int iEndOfType = indexOf(tok, i, "?"); int iColon = indexOf(tok, iEndOfType, ":"); String var = tok.get(i), type = joinSubList(tok, i+4, iEndOfType-1); String rawType = tok_dropTypeParameters(type); tok_insertCasts_reTok(tok, iEndOfType, iColon, var, type); tok.set(i+2, "instanceof"); } } static void tok_doPing(List tok) { jreplace(tok, "do ping {", "do { ping();"); int i; while ((i = jfind(tok, "do ping ")) >= 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 replaceKeywordBlock(List tok, String keyword, String beg, String end) { return replaceKeywordBlock(tok, keyword, beg, end, false, null); } static List replaceKeywordBlock(List tok, String keyword, String beg, String end, Object cond) { return replaceKeywordBlock(tok, keyword, beg, end, false, cond); } static List replaceKeywordBlock(List 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 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 " {" // func: tok, C token index of keyword -> S[] {beg, end} static List replaceKeywordPlusQuotedBlock(List tok, String keyword, Object func) { for (int i = 0; i < 1000; i++) { int idx = jfind(tok, keyword + " {"); 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 tok, String in) { return jfind(tok, 1, in); } static int jfind(List tok, int startIdx, String in) { return jfind(tok, startIdx, in, (ITokCondition) null); } static int jfind(List tok, String in, Object condition) { return jfind(tok, 1, in, condition); } static int jfind(List tok, String in, IIntPred condition) { return jfind(tok, 1, in, condition); } static int jfind(List tok, int startIndex, String in, IIntPred condition) { return jfind(tok, startIndex, in, tokCondition(condition)); } static int jfind(List tok, String in, ITokCondition condition) { return jfind(tok, 1, in, condition); } static int jfind(List tok, int startIndex, String in, ITokCondition condition) { return jfind(tok, startIndex, in, (Object) condition); } static int jfind(List 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 tok, List tokin) { return jfind(tok, 1, tokin); } static int jfind(List tok, int startIdx, List tokin) { return jfind(tok, startIdx, tokin, null); } static int jfind(List tok, int startIdx, String[] tokinC, Object condition) { return findCodeTokens(tok, startIdx, false, tokinC, condition); } static int jfind(List tok, int startIdx, List tokin, Object condition) { return jfind(tok, startIdx, codeTokensAsStringArray(tokin), condition); } static List jfind_preprocess(List 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 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 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 tok) { jreplace(tok, "module implements", "module $2 extends DynModule implements"); jreplace(tok, "module {", "module $2 extends DynModule {"); jreplace(tok, "module {", "module " + stefansOS_defaultModuleClassName() + " {"); jreplace(tok, "module > ", "module " + stefansOS_defaultModuleClassName() + " > $3"); int i = -1; while ((i = jfind(tok, i+1, "module ", // check for interference with other productions (_tok, nIdx) -> !eqGetOneOf(_tok, nIdx+3, "instanceof", "default", "aka"))) >= 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 _get(List 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 _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 replaceKeywordBlock_dyn2_legacy(List 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(BitSet bs) { return bs == null || bs.isEmpty(); } 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(IMultiMap mm) { return mm == null || mm.size() == 0; } static boolean empty(File f) { return getFileSize(f) == 0; } static boolean empty(IntRange r) { return r == null || r.empty(); } static boolean empty(Rect r) { return !(r != null && r.w != 0 && r.h != 0); } static boolean empty(Chain c) { return c == null; } static boolean empty(AppendableChain c) { return c == null; } static boolean empty(IntSize l) { return l == null || l.size() == 0; } static void tok_retShortForReturn(List tok) { jreplace(tok, "ret", "return", new TokCondition() { public boolean get(final List tok, final int i) { // haphazard attempts to find out if we are actually dealing // with a variable called "ret" 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, "=", ")"); }}); } // returns index of endToken static int scanOverExpression(List tok, Map bracketMap, int i, String endToken) { while (i < l(tok)) { if (eq(endToken, tok.get(i))) return i; Integer j = bracketMap.get(i); if (j != null) i = j+1; else i++; } return i; } // map: index of opening bracket -> index of closing bracket static Map getBracketMap(List tok) { return getBracketMap(tok, getBracketMap_opening, getBracketMap_closing); } static Map getBracketMap(List tok, Collection opening, Collection closing) { return getBracketMap(tok, opening, closing, 0, l(tok)); } static Map getBracketMap(List tok, Collection opening, Collection closing, int from, int to) { TreeMap map = new TreeMap(); List stack = new ArrayList(); for (int i = from|1; i < to; i+= 2) { Object t = tok.get(i); if (opening.contains(t)) stack.add(i); else if (closing.contains(t)) if (!empty(stack)) map.put(liftLast(stack), i); } return map; } static Map getBracketMap(List tok, IF1 opening, IF1 closing) { return getBracketMap(tok, opening, closing, 0, l(tok)); } static Map getBracketMap(List tok, IF1 opening, IF1 closing, int from, int to) { TreeMap map = new TreeMap(); List stack = new ArrayList(); for (int i = from|1; i < to; i+= 2) { String t = tok.get(i); if (opening.get(t)) stack.add(i); else if (closing.get(t)) if (!empty(stack)) map.put(liftLast(stack), i); } return map; } static Set getBracketMap_opening = lithashset("{", "("); static Set getBracketMap_closing = lithashset("}", ")"); static void replaceTokens(List tok, IntRange r, String s) { replaceTokens(tok, r.start, r.end, s); } static void replaceTokens(List tok, int i, int j, String s) { clearAllTokens(tok, i+1, j); tok.set(i, s); } static void replaceTokens(List tok, String s) { clearAllTokens(tok, 1, l(tok)); tok.set(0, s); } static boolean eqOneOf(Object o, Object... l) { if (l != null) for (Object x : l) if (eq(o, x)) return true; return false; } // Return value is C token static int tok_findBeginningOfStatement(List tok, int i) { i |= 1; int level = 0; while (i > 1) { String t = get(tok, i); if (eqOneOf(t, "{", "(")) { if (level-- < 0) break; } else if (eqOneOf(t, "}", ")")) level++; else if (level == 0 && eqGetOneOf(tok, i-2, "}", "{", ";")) break; i -= 2; } return i; } static String joinSubList(List l, int i, int j) { return join(subList(l, i, j)); } static String joinSubList(List l, int i) { return join(subList(l, i)); } static String joinSubList(List l, IntRange r) { return r == null ? null : joinSubList(l, r.start, r.end); } static String getVarDeclarationName(List tok) { return get(tok, tok_findVarDeclarationName(tok)); } static List subList(List l, int startIndex) { return subList(l, startIndex, l(l)); } static List subList(int startIndex, List l) { return subList(l, startIndex); } static List subList(int startIndex, int endIndex, List l) { return subList(l, startIndex, endIndex); } static List subList(List l, int startIndex, int endIndex) { if (l == null) return null; int n = l(l); startIndex = Math.max(0, startIndex); endIndex = Math.min(n, endIndex); if (startIndex > endIndex) return ll(); if (startIndex == 0 && endIndex == n) return l; return ourSubList_noRangeCheck(l, startIndex, endIndex); } static List subList(List l, IntRange r) { return subList(l, r.start, r.end); } static void tok_ifNullAssign(List tok) { for (int i : jfindAll_reversed(tok, "return if null =")) { String var = tok.get(i+2); int iEnd = findEndOfStatement(tok, i); tok.set(iEnd-1, ("; return " + var + "; }")); replaceTokens(tok, i, i+5*2-1, ("{ if (" + var + " == null) " + var + " =")); } jreplace(tok, " if null =", "if ($1 == null) $1 ="); } static int jfindOneOf(List tok, String... patterns) { for (String in : patterns) { int i = jfind(tok, in); if (i >= 0) return i; } return -1; } // debug "bla" + blubb; => { if (debug) print("bla" + blubb); } static void tok_debugStatements(List tok) { int i = -1; while ((i = jfind(tok, i+1, "debug ")) >= 0) { int j = tok_findEndOfStatement(tok, i); // index of semicolon+1 replaceTokens(tok, i, i+2, "{ if (debug) print("); tok.set(j-1, "); }"); i = j; } } static int jfind_check(String checkToken, List tok, String in) { return jfind_check(checkToken, tok, in, null); } static int jfind_check(String checkToken, List tok, String in, Object condition) { if (isIndexedList(tok) && !tok.contains(checkToken)) return -1; return jfind(tok, in, condition); } static Boolean not(Boolean b) { return b == null ? null : !b; } // i must point at the (possibly imaginary) opening bracket (any of the 2 types, not type parameters) // index returned is index of closing bracket + 1 static int findEndOfBracketPart(List cnc, int i) { int j = i+2, level = 1; while (j < cnc.size()) { if (eqOneOf(cnc.get(j), "{", "(")) ++level; else if (eqOneOf(cnc.get(j), "}", ")")) --level; if (level == 0) return j+1; ++j; } return cnc.size(); } static String substring(String s, int x) { return substring(s, x, strL(s)); } static String substring(String s, int x, int y) { if (s == null) return null; if (x < 0) x = 0; int n = s.length(); if (y < x) y = x; if (y > n) y = n; if (x >= y) return ""; return s.substring(x, y); } static String substring(String s, IntRange r) { return r == null ? null : substring(s, r.start, r.end); } // convenience method for quickly dropping a prefix static String substring(String s, CharSequence l) { return substring(s, lCharSequence(l)); } static int parseInt(String s) { return emptyString(s) ? 0 : Integer.parseInt(s); } static int parseInt(char c) { return Integer.parseInt(str(c)); } static void tok_beaConceptDecls(List tok) { { if (!(contains(tok, "beaConcept"))) return; } jreplace(tok, "beaConcept > ", "concept $2 > $4"); jreplace(tok, "beaConcept {", "concept $2 > BEAObject {"); } static boolean tok_doAsMethodName_strict = false; // Strict mode: // Sometimes you have to make sure to omit the space after "do" // do(...) // as opposed to // do (bla+bla).something(); while ...; << very unusual anyway // Non-strict mode: // do (bla+bla).something(); while ...; // is not possible anymore (but who does this?) // You can use spaces however you like static void tok_doAsMethodName(List tok) { if (!tok.contains("do")) return; for (int i = 1; i+2 < l(tok); i += 2) { String next = tok.get(i+2), prev = get(tok, i-2); if (tok.get(i).equals("do") && eq(next, "(") && (!tok_doAsMethodName_strict || eq(prev, ".") || empty(tok.get(i+1)))) tok.set(i, "dO"); } } static void tok_p_old(List tok) { if (!containsSubList(tok, "p", "", "-")) return; replaceKeywordBlock(tok, "p-pcall", "p { pcall {", "}}"); jreplace(tok, "p-autorestart", "p-autoupdate"); jreplace(tok, "p-autoupdate {", "p { autoUpdate();"); jreplace(tok, "p-noconsole-autoupdate {", "p-noconsole { autoUpdate();"); jreplace(tok, "p-subst-autoupdate {", "p-subst { autoUpdate();"); jreplace(tok, "p-subst-autorestart {", "p-subst { autoUpdate();"); jreplace(tok, "p-pretty {", "p-noconsole {"); replaceKeywordBlock(tok, "p-awt-noconsole", "p-awt {", ";\nhideConsole(); }"); replaceKeywordBlock(tok, "p-hideconsole", "p {", ";\nhideConsole(); }"); replaceKeywordBlock(tok, "p-substance-noconsole", "p-substance {", ";\nhideConsole(); }"); replaceKeywordBlock(tok, "p-nimbus-noconsole", "p-nimbus {", ";\nhideConsole(); }"); replaceKeywordBlock(tok, "p-subst-noconsole", "p-subst {", ";\nhideConsole(); }"); replaceKeywordBlock(tok, "p-noconsole", "p-subst {", ";\nhideConsole(); }"); replaceKeywordBlock(tok, "p-subst", "p-substance-thread {", "}"); replaceKeywordBlock(tok, "p-substance-thread", "p { substance();", "}"); replaceKeywordBlock(tok, "p-magellan-thread", "p { magellan();", "}"); replaceKeywordBlock(tok, "p-substance", "p-awt { substance();", "}"); replaceKeywordBlock(tok, "p-nimbus", "p-awt { nimbus();", "}"); replaceKeywordBlock(tok, "p-center", "p { centerConsole(); ", "}"); replaceKeywordBlock(tok, "p-experiment-tt", "p-experiment { tt(); ", "}"); jreplace(tok, "p-exp", "p-experiment"); replaceKeywordBlock(tok, "p-experiment", "p { pExperiment(); ", "}"); jreplace(tok, "p-type {", "p-typewriter {"); jreplace(tok, "p-tt {", "p-typewriter {"); replaceKeywordBlock(tok, "p-awt", "p { swing {", "}}"); replaceKeywordBlock(tok, "p-typewriter", "p { typeWriterConsole();", "}"); replaceKeywordBlock(tok, "p-lowprio", "p { lowPriorityThread(r " + "{", "}); }"); tok_p_repeatWithSleep(tok); } // -Syntax: switch to q(); // -rest of block is executed in Queue q() static void tok_switchTo(List tok) { int i = -1; while ((i = jfind(tok, i+1, "switch to")) >= 0) { int semicolon = findEndOfStatement(tok, i)-1; int endOfOuterBlock = findEndOfBracketPart(tok, semicolon)-1; clearTokens(tok, i, i+4); tok.set(semicolon, ".add(r {"); tok.set(endOfOuterBlock, "}); }"); reTok(tok, i, endOfOuterBlock+1); } } static void tok_forOver(List tok) { jreplace (tok, "for over :", "for (int $2 = 0; $2 < l($4); $2++)"); jreplace (tok, "for backwards over :", "for (int $2 = l($5)-1; $2 >= 0; $2--)"); // index var and implicitly typed element var jreplace (tok, "for , over : ", "for $2, var $4 over $6:"); // index var and explicitly typed element var jreplace (tok, "for , over : {", "for (int $2 = 0; $2 < l($7); $2++) { $4 $5 = $7.get($2);"); jreplace (tok, "for , backwards over : {", "for (int $2 = l($8)-1; $2 >= 0; $2--) { $4 $5 = $8.get($2);"); jreplace_dyn_allowDollarRefs(tok, "for immutable to : {", cIdx -> { String var = makeVar(); return ("for " + var + " to $5: { int $3 = " + var + ";"); }); } static List tok_equalsCast(List tok) { if (!tok.contains("cast")) return tok; int iVar = -1; while ((iVar = jfind(tok, iVar+1, " = cast")) >= 0) { int iTypeStart = tok_scanTypeBackwards(tok, iVar-2); int iCast = iVar+4; int j = scanToEndOfInitializer2(tok, iCast); String type = joinSubList(tok, iTypeStart, iVar-1); clearTokens(tok, iCast, iCast+1); if (!tok_typeIsObject(type)) { boolean needBrackets = j > iCast+4; tokPrepend(tok, iCast+2, "(" + type + ") " + (needBrackets ? "(" : "")); if (needBrackets) tokPrepend(tok, j+1, ")"); } reTok(tok, iCast, j+2); } return tok; } // S s = opt cast ...; static List tok_equalsOptCast(List tok) { if (!tok.contains("cast")) return tok; int iVar = -1; while ((iVar = jfind(tok, iVar+1, " = opt cast")) >= 0) { int iTypeStart = tok_scanTypeBackwards(tok, iVar-2); int iCast = iVar+6; int j = scanToEndOfInitializer2(tok, iCast); String type = joinSubList(tok, iTypeStart, iVar-1); replaceTokens(tok, iCast-2, iCast+2, "optCast " + type + "("); tokPrepend(tok, j+1, ")"); reTok(tok, iCast-2, j+2); } return tok; } static String tok_addSemicolon(List tok) { //assertOdd(l(tok)); String lastToken = get(tok, (l(tok)|1)-2); if (eqOneOf(lastToken, "}", ";")) return join(tok); return join(tok) + ";"; } static String tok_addSemicolon(String s) { return tok_addSemicolon(javaTok(s)); } static String tok_autoQuineFunc(List contents) { return tok_autoQuineFunc(contents, "toString"); } static String tok_autoQuineFunc(List contents, String funcName) { return " public S " + funcName + "() { ret " + quote(shorten(defaultMaxQuineLength(), trimJoin(contents))) + "; }"; } static boolean tok_repeatWithSleep_verbose = false; static List tok_repeatWithSleep(List tok) { int i; while ((i = jfind(tok, "repeat with sleep * {")) >= 0) { String seconds = tok.get(i+6); // int or id int idx = findCodeTokens(tok, i, false, "{"); int j = findEndOfBracketPart(tok, idx); if (tok_repeatWithSleep_verbose) print("idx=" + idx + ", j=" + j); clearTokens(tok, i, idx+1); tok.set(i, "repeat { pcall {"); tok.set(j-1, "} sleepSeconds(" + seconds + "); }"); reTok(tok, j-1, j); reTok(tok, i, idx+1); } while ((i = jfind(tok, "repeat with ms sleep * {")) >= 0) { String ms = tok.get(i+8); // int or id int idx = findCodeTokens(tok, i, false, "{"); int j = findEndOfBracketPart(tok, idx); if (tok_repeatWithSleep_verbose) print("idx=" + idx + ", j=" + j); clearTokens(tok, i, idx+1); tok.set(i, "repeat { pcall {"); tok.set(j-1, "} sleep(" + ms + "); }"); reTok(tok, j-1, j); reTok(tok, i, idx+1); } return tok; } static boolean tok_tokenBeforeLonelyReturnValue(List tok, int i) { String t = get(tok, i); if (l(t) == 1 && "{};".contains(t) || eq(t, "else")) return true; if (!eq(t, ")")) return false; int level = 0; while (i > 0) { if (eq(tok.get(i), ")")) ++level; if (eq(tok.get(i), "(")) --level; if (level == 0) return eq(get(tok, i-2), "if"); i -= 2; } return false; } static boolean eqGetOneOf(List l, int i, A... options) { return eqOneOf(get(l, i), options); } static String tok_expandIfQuoted(String s) { return applyTranspilationFunction(__54 -> tok_expandIfQuoted(__54), s); } static void tok_expandIfQuoted(List tok) { jreplace(tok, "if || ", "if (matchOneOf(s, m, $2, $5))"); // "bla * bla | blubb * blubb" jreplace_dyn(tok, "if ", new F2, Integer, String>() { public String get(List tok, Integer cIdx) { try { String s = unquote(tok.get(cIdx+2)); //print("multimatch: " + quote(s)); List l = new ArrayList(); for (String pat : splitAtJavaToken(s, "|")) { //print("multimatch part: " + quote(pat)); if (pat.contains("...")) l.add("matchX(" + quote(trim(pat)) + ", s, m)"); else if (javaTok(pat).contains("*")) l.add("match(" + quote(trim(pat)) + ", s, m)"); else l.add("match(" + quote(trim(pat)) + ", s)"); } return "if (" + join(" || ", l) + ")"; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "S s = unquote(tok.get(cIdx+2));\r\n //print(\"multimatch: \" + quote(s));\r\n ..."; }}, new TokCondition() { public boolean get(final List tok, final int i) { return javaTokC(unquote(tok.get(i+3))).contains("|"); }}); tok_transpileIfQuoted_dollarVars(tok); // "...bla..." jreplace(tok, "if ", "if (find3plusRestsX($2, s, m))", new TokCondition() { public boolean get(final List tok, final int i) { return startsAndEndsWith(unquote(tok.get(i+3)), "..."); }}); // "bla..." jreplace(tok, "if ", "if (matchStartX($2, s, m))", new TokCondition() { public boolean get(final List tok, final int i) { return unquote(tok.get(i+3)).endsWith("..."); }}); // "bla" jreplace(tok, "if ", "if (match($2, s))", new TokCondition() { public boolean get(final List tok, final int i) { return !javaTokC(unquote(tok.get(i+3))).contains("*"); }}); // "bla * bla" jreplace(tok, "if ", "if (match($2, s, m))"); jreplace(tok, "if match ", "if (match($3, s, m))"); } static void tok_pcall(List tok) { replaceKeywordBlock(tok, "pcall", "try {", "} catch (Throwable __e) { pcallFail(__e); }"); } // func returns S[] {beg, end} static List replaceKeywordBlockDyn(List tok, String keyword, Object func) { for (int i = 0; i < 1000; i++) { int idx = findCodeTokens(tok, keyword, "{"); if (idx < 0) break; int j = findEndOfBracketPart(tok, idx+2); String[] be = (String[]) callF(func); tok.set(idx, be[0]); tok.set(idx+1, " "); tok.set(idx+2, ""); tok.set(j-1, be[1]); reTok(tok, idx, j); } return tok; } // finds " {" and " {" // func: tok, C token index of keyword -> S[] {beg, end} static List replaceKeywordPlusQuotedOrIDBlock(List tok, String keyword, Object func) { for (int i = 0; i < 1000; i++) { int idx = jfind_any(tok, keyword + " {", keyword + " {"); 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 boolean neqOneOf(Object o, Object... l) { for (Object x : l) if (eq(o, x)) return false; return true; } static String quote(Object o) { if (o == null) return "null"; return quote(str(o)); } static String quote(String s) { if (s == null) return "null"; StringBuilder out = new StringBuilder((int) (l(s)*1.5+2)); quote_impl(s, out); return out.toString(); } static void quote_impl(String s, StringBuilder out) { out.append('"'); int l = s.length(); for (int i = 0; i < l; i++) { char c = s.charAt(i); if (c == '\\' || c == '"') out.append('\\').append(c); else if (c == '\r') out.append("\\r"); else if (c == '\n') out.append("\\n"); else if (c == '\t') out.append("\\t"); else if (c == '\0') out.append("\\0"); else out.append(c); } out.append('"'); } static int shorten_default = 100; static String shorten(CharSequence s) { return shorten(s, shorten_default); } static String shorten(CharSequence s, int max) { return shorten(s, max, "..."); } static String shorten(CharSequence s, int max, String shortener) { if (s == null) return ""; if (max < 0) return str(s); return s.length() <= max ? str(s) : subCharSequence(s, 0, min(s.length(), max-l(shortener))) + shortener; } static String shorten(int max, CharSequence s) { return shorten(s, max); } static int defaultMaxQuineLength_defaultValue = 80; static int defaultMaxQuineLength_value = defaultMaxQuineLength_defaultValue; static int defaultMaxQuineLength() { return defaultMaxQuineLength_value; } static String trimJoin(List s) { return trim(join(s)); } // It's rough but should work if you don't make anonymous classes inside the statement or something... // Also won't work with "for" // Return value is index of semicolon/curly brace+1 static int findEndOfStatement(List tok, int i) { int j = i; // Is it a block? if (eq(get(tok, i), "{")) return findEndOfBlock(tok, i)+1; // It's a regular statement. int n = l(tok); String t; while (j < n && !";".equals(t = tok.get(j))) if ("{".equals(t)) j = findEndOfBlock(tok, j)+1; else j += 2; return j+1; } static void tokPrepend_reTok(List tok, int i, String s) { tokPrepend(tok, i, s); reTok(tok, i, i+1); } static void clearTokens(List tok) { clearAllTokens(tok); } static void clearTokens(List tok, int i, int j) { clearAllTokens(tok, i, j); } static void clearTokens(List tok, IntRange r) { clearAllTokens(tok, r.start, r.end); } static int tok_findEndOfType(List tok) { return tok_findEndOfType(tok, 1); } // i = beginning of type (identifier) // index returned C index after type // now does packages/inner classes too static int tok_findEndOfType(List tok, int i) { while (licensed()) { if (eqGet(tok, i+2, ".") && isIdentifier(get(tok, i+4))) { i += 4; continue; } if (eqGet(tok, i+2, "<")) { i = findEndOfTypeArgs(tok, i+2)-1; continue; } if (eqGet(tok, i+2, "[")) { i = findEndOfBracketPart2(tok, i+2)-1; continue; } break; } return i+2; } static A assertEquals(Object x, A y) { return assertEquals("", x, y); } static A assertEquals(String msg, Object x, A y) { if (assertVerbose()) return assertEqualsVerbose(msg, x, y); if (!(x == null ? y == null : x.equals(y))) throw fail((msg != null ? msg + ": " : "") + y + " != " + x); return y; } static void assertEquals(Scorer scorer, Object x, Object y) { assertEquals(scorer, "", x, y); } static void assertEquals(Scorer scorer, String msg, Object x, Object y) { if (scorer == null) { assertEquals(msg, x, y); return; } scorer.add(eq(x, y), nullIfEmpty(msg)); } static void tok_expandLPair(List tok) { if (!tok.contains("LPair")) return; int n = l(tok)-6; for (int i = 1; i < n; i += 2) { { if (!(eq(tok.get(i), "LPair") && eq(tok.get(i+2), "<"))) continue; } int j = findEndOfTypeArgs(tok, i+2)-1; // j = index of > tok.set(i, "L>"); reTok(tok, i, j+1); n = l(tok)-6; } } static void tok_expandPairL(List tok) { if (!tok.contains("PairL")) return; int n = l(tok)-6; for (int i = 1; i < n; i += 2) { { if (!(eq(tok.get(i), "PairL") && eq(tok.get(i+2), "<"))) continue; } int j = findEndOfTypeArgs(tok, i+2)-1; // j = index of > tok.set(i, "Pair>"); reTok(tok, i, j+1); n = l(tok)-6; } } static void tok_expandLT3(List tok) { if (!tok.contains("LT3")) return; int n = l(tok)-6; for (int i = 1; i < n; i += 2) { { if (!(eq(tok.get(i), "LT3") && eq(tok.get(i+2), "<"))) continue; } int j = findEndOfTypeArgs(tok, i+2)-1; // j = index of > tok.set(i, "L>"); reTok(tok, i, j+1); n = l(tok)-6; } } // pattern, replacement, index of following token static List> tok_quicknew2_patterns = ll( t3("new ", "new $2()", 5), t3("new .", "new $2.$4()", 9), t3("new <>", "new $2<>()", 9), t3("new < >", "new $2<$4>()", 11)); static void tok_quicknew2(List tok) { tok_quicknew(tok); boolean needFix = false; // [abandoned, confusing, looks like a function definition] with arguments - new A a(...); => A a = new A(...); //jreplace(tok, "new (", "$2 $3 = new $2("); jreplace(tok, "for args " + "{", "for (int i = 0; i < args.length; i++) { final String arg = args[i];"); // Constructor calls without parentheses // So you can say something like: predictors.add(new P1); for (T3 t : tok_quicknew2_patterns) jreplace1(tok, t.a, t.b, new TokCondition() { public boolean get(final List tok, final int i) { return eqOneOf(_get(tok, i+t.c), "{", ",", ")", ";", ":", "!"); }}); jreplace(tok, "new Collection(", "new List("); jreplace(tok, "new List(", "new ArrayList("); jreplace(tok, "new Map(", "new HashMap("); jreplace(tok, "new Set(", "new HashSet("); jreplace(tok, "new (Hash)Set", "new HashSet"); // rough jreplace(tok, "new (Tree)Set", "new TreeSet"); jreplace(tok, "new (Hash)Map", "new HashMap"); jreplace(tok, "new (Tree)Map", "new TreeMap"); jreplace(tok, "\\*[] ;", "$2[] $6 = new $2[$4];"); // X x = new(...) => X x = new X(...) // X x = new {...} => X x = new X {...} // X x = new => X x = new jreplace(tok, ". = new", "$1.$3 $4 = new $1.$3", new TokCondition() { public boolean get(final List tok, final int i) { return tokCondition_shortNew(tok, i+13); }}); jreplace(tok, " = new", "$1 $2 = new $1", new TokCondition() { public boolean get(final List tok, final int i) { return tokCondition_shortNew(tok, i+9); }}); jreplace(tok, " = new \\*", "$1 $2 = new $1"); jreplace(tok, "\\* = new ", "$5 $2 = new $5"); // TODO: use backward type scanning needFix |= jreplace(tok, "<> = new", "$1 $2 $3 $4 $5 = new $1<>", new TokCondition() { public boolean get(final List tok, final int i) { return tokCondition_shortNew(tok, i+9+3*2); }}); needFix |= jreplace(tok, "<,> = new", "$1 $2 $3 $4 $5 $6 $7 = new $1<>", new TokCondition() { public boolean get(final List tok, final int i) { return tokCondition_shortNew(tok, i+9+5*2); }}); needFix |= jreplace(tok, "<<>> = new", "$1 $2 $3 $4 $5 $6 $7 $8 = new $1<>", new TokCondition() { public boolean get(final List tok, final int i) { return tokCondition_shortNew(tok, i+9+6*2); }}); needFix |= jreplace(tok, "<<>,> = new", "$1 $2 $3 $4 $5 $6 $7 $8 $9 $10 = new $1<>", new TokCondition() { public boolean get(final List tok, final int i) { return tokCondition_shortNew(tok, i+9+8*2); }}); // fix if (needFix) jreplace(tok, "<><>", "<>"); } static void tok_delegateTo(List tok) { ITokCondition cond = (_tok, nIdx) -> !(empty(_get(_tok, nIdx)) && eqGet(_tok, nIdx-1, ".")); int i; while ((i = jfind_any(tok, "delegate to", "delegate ,")) >= 0) { ping(); Set tokens = litset(tok.get(i+2)); int i2 = i+4; while (eqGet(tok, i2, ",")) { tokens.add(assertIdentifier(get(tok, i2+2))); i2 += 4; } assertEquals(get(tok, i2), "to"); int repStart = i2+2; 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 " + tokens + " with " + replacement + ""); int end = findEndOfBlock(tok, repEnd)-1; for (int j = repEnd+2; j < end; j += 2) { ping(); if (!tokens.contains(tok.get(j))) continue; // skip if it's a field or method access if (empty(get(tok, j-1)) && eqGet(tok, j-2, ".")) continue; // skip creation of an non-static inner class instance // (a.new B) if (eqGet(tok, j-2, "new") && eqGet(tok, j-4, ".")) continue; tokPrepend(tok, j, replacement); } reTok(tok, i, end); } } static void tok_replaceWith(List tok) { int i; while ((i = jfind(tok, "replace 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); } } // "replace var x with" is like "replace x with" except it doesn't // replace .x (this.x etc) static void tok_replaceVarWith(List tok) { int i; while ((i = jfind(tok, "replace var with")) >= 0) { ping(); String token = tok.get(i+4); int repStart = i+8; 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) && !eqGet(tok, j-2, ".")) tok.set(j, replacement); } reTok(tok, i, end); } } // "!", "?!" etc. static void tok_exclamPostfix(List tok) { jreplace(tok, "*!", "$1.get()", new TokCondition() { public boolean get(final List 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 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; }}); } // e.g.: temp resourceHolder = (); // to : temp var resourceHolder = resourceHolder(); static void tok_varNamedLikeFunction(List tok) { jreplace(tok, "temp = ();", "temp var $2 = $2();"); } static void tok_onCleanExit(List tok) { int i; while ((i = jfind(tok, "on clean exit {")) >= 0) { int iCurly = indexOf(tok, i, "{"); int iCurlyEnd = findEndOfBracketPart(tok, iCurly)-1; int iRest = iCurlyEnd+2; int iEndOfOuterBlock = findEndOfBracketPart(tok, iCurlyEnd)-1; String code = joinSubList(tok, iCurly, iCurlyEnd+1); String var = makeVar(); tokPrepend_reTok(tok, iEndOfOuterBlock, ("} on fail { set " + var + "; } finally { if (!" + var + ") " + code + " } } ")); tokReplace_reTok(tok, i, iRest, ("{ bool " + var + "; try { ")); } } // +var => "var", +var static void tok_expandVarCopies(List tok) { for (int i = 3; i+2 < l(tok); i += 2) { if (!eq(tok.get(i), "+")) continue; if (!eqOneOf(tok.get(i-2), "(", ",", "{")) continue; String s = tok.get(i+2); if (!isIdentifier(s)) continue; tok.set(i, quote(s) + ", "); reTok(tok, i, i+1); } } static void tok_replaceColonEqualsSyntax(List tok) { int i; // "field := value" for defining fields e.g. in "uniq" while ((i = jfind_check(":", tok, " :=")) >= 0) { String id = tok.get(i); // special case for null := which we interpret as actually null, // not "null" String string = eq(id, "null") ? id : quote(id); tok.set(i, string); tok.set(i+2, ","); tok.set(i+4, ""); reTok(tok, i, i+5); } // "quoted" := value while ((i = jfind_check(":", tok, " :=")) >= 0) { tok.set(i+2, ","); tok.set(i+4, ""); reTok(tok, i, i+5); } // := value while ((i = jfind_check(":", tok, " :=")) >= 0) { tok.set(i+2, ","); tok.set(i+4, ""); reTok(tok, i, i+5); } // all other cases: just replace with comma jreplace(tok, ":=", ","); } static void tok_unpair(List tok) { if (!tok.contains("unpair")) return; int i; while ((i = jfind(tok, "var , = unpair")) >= 0) { int iUnpair = indexOf(tok, "unpair", i); int j = findEndOfStatement(tok, iUnpair); String var1 = tok.get(i+2); String var2 = tok.get(i+6); String v = makeVar(); replaceTokens(tok, i, iUnpair+1, "var " + v + " ="); tok.set(j-1, "; var " + var1 + " = " + v + ".a; var " + var2 + " = " + v + ".b;"); reTok(tok, i, j); } jreplace(tok, " , = unpair", "$1 $2, $1 $4 = unpair"); while ((i = jfind(tok, " , = unpair")) >= 0) { int idx = indexOf(tok, "unpair", i); int j = findEndOfStatement(tok, idx); String type1 = tok.get(i), var1 = tok.get(i+2); String type2 = tok.get(i+6), var2 = tok.get(i+8); String v = makeVar(); //printVars(+type1, +var1, +type2, +var2); tok.set(i+4, ";"); tok.set(idx-2, ";"); tok.set(idx, "Pair<" + tok_toNonPrimitiveTypes(type1) + "," + tok_toNonPrimitiveTypes(type2) + "> " + v + "="); tok.set(j-1, "; " + var1 + " = " + v + ".a; " + var2 + " = " + v + ".b;"); reTok(tok, i, j); } while ((i = jfind(tok, " , < , > = unpair")) >= 0 || (i = jfind(tok, " , <> = unpair")) >= 0) { print("unpair"); int idx = indexOf(tok, "unpair", i); int j = findEndOfStatement(tok, idx); String type1 = tok.get(i), var1 = tok.get(i+2); String type2 = joinSubList(tok, i+5, idx-5), var2 = tok.get(idx-4); String v = makeVar(); tok.set(i+4, ";"); tok.set(idx-2, ";"); tok.set(idx-1, ""); tok.set(idx, "Pair<" + type1 + "," + type2 + "> " + v + "="); tok.set(j-1, "; " + var1 + " = " + v + ".a; " + var2 + " = " + v + ".b;"); reTok(tok, i, j); } } static void tok_cachedFunctions_new(List tok) { try { int i = -1; while ((i = jfind(tok, i+1, "cached ")) >= 0) { Collection modifiers = tok_modifiersLeftOf(tok, i); int iMod = tok_leftScanModifiers(tok, i); int bracket = indexOf(tok, "(", i); String fName = assertIdentifier(tok.get(bracket-2)); int iMod2 = tok_rightScanModifiers(tok, i+2); printVars("tok_cachedFunctions_new", "modifiers", modifiers); modifiers.addAll(codeTokensFromSubList(tok, i+2, iMod2)); String type = joinSubList(tok, iMod2, bracket-3); String boxedType = tok_toNonPrimitiveTypes(type); String mods = joinWithSpace(listMinus(modifiers, "final")); String mods2 = joinWithSpace(listMinus(modifiers, "transient")); printVars("tok_cachedFunctions_new", "mods", mods, "mods2", mods2); replaceTokens_reTok(tok, iMod, bracket-1, (mods + " Cache<" + boxedType + "> " + fName + "_cache = new Cache<>(lambda0 " + fName + "_load);\n") + (mods2 + " " + type + " " + fName + "() { ret " + fName + "_cache!; }\n\n") + (mods2 + " " + boxedType + " " + fName + "_load")); } } catch (Throwable __e) { pcallFail(__e); }} static void tok_timedCachedFunctions(List tok) { try { int i; while ((i = jfind(tok, "timedCached[.] ")) >= 0) { int bracket1 = indexOf(tok, "]", i); String time = joinSubList(tok, i+4, bracket1-1); int bracket = indexOf(tok, "(", bracket1); String fName = assertIdentifier(tok.get(bracket-2)); String type = joinSubList(tok, bracket1+2, bracket-3); String boxedType = tok_toNonPrimitiveTypes(type); var modifiersList = tok_modifiersLeftOf(tok, i); String modifiers = joinWithSpace(modifiersList); String functionModifiers = joinWithSpace(listMinus(modifiersList, "transient")); replaceTokens(tok, i, bracket-1, ("TimedCache<" + boxedType + "> " + fName + "_cache = new <>(" + time + ", lambda0 " + fName + "_load);\n") + (functionModifiers + " " + type + " " + fName + "() { ret " + fName + "_cache!; }\n\n") + (functionModifiers + " " + boxedType + " " + fName + "_load")); reTok(tok, i, bracket-3); } } catch (Throwable __e) { pcallFail(__e); }} // "optPar int bla = 5;" => "int bla = optPar bla(_, 5);" static void tok_optPar(List tok) { jreplace(tok, "boolPar ", "optPar bool $2", new TokCondition() { public boolean get(final List tok, final int i) { return eqGetOneOf(tok, i+5, "=", ";"); }}); int i; while ((i = jfindOneOf(tok, "optPar ", "optPar <", "optPar [")) >= 0) { int iSemicolon = tok_findEndOfStatement(tok, i)-1; int iEquals = indexOf_between(tok, "=", i, iSemicolon); clearTokens(tok, i, i+2); // drop optPar if (iEquals < 0) { // no initializer String var = tok.get(iSemicolon-2); String type = joinSubList(tok, i+2, iSemicolon-3); if (eqOneOf(type, "bool", "boolean")) tok.set(iSemicolon, " = boolPar " + var + "(_);"); else tok.set(iSemicolon, " = cast optPar " + var + "(_);"); } else { String var = tok.get(iEquals-2); tok.set(iEquals, "= optPar " + var + "(_, "); tok.set(iSemicolon, ");"); } reTok(tok, i, iSemicolon+1); } } static void tok_typeAA(List tok, Set pairClasses) { int n = l(tok)-6; boolean change = false; for (int i = 1; i < n; i += 2) { if (!eq(get(tok, i+2), "<")) continue; String t = tok.get(i); { if (!(contains(pairClasses, t) || eq(t, "Entry") && eqGet(tok, i-2, ".") && eqGet(tok, i-4, "Map"))) continue; } if (tok_isSingleTypeArg(tok, i+2)) { int j = findEndOfTypeArgs(tok, i+2)-1; String type = joinSubList(tok, i+4, j); replaceTokens_reTok(tok, i+4, j, type + ", " + type); change = true; } } } static void tok_typeAAA(List tok, Set tripleClasses) { int n = l(tok)-6; boolean change = false; for (int i = 1; i < n; i += 2) { if (!eq(get(tok, i+2), "<")) continue; String t = tok.get(i); { if (!(contains(tripleClasses, t))) continue; } if (tok_isSingleTypeArg(tok, i+2)) { int j = findEndOfTypeArgs(tok, i+2)-1; String type = joinSubList(tok, i+4, j); replaceTokens_reTok(tok, i+4, j, type + ", " + type + ", " + type); change = true; } } } static void tok_typeAO(List tok, Set pairClasses) { int n = l(tok)-6; boolean change = false; for (int i = 1; i < n; i += 2) { if (!eq(get(tok, i+2), "<")) continue; String t = tok.get(i); { if (!(contains(pairClasses, t))) continue; } if (tok_isSingleTypeArg(tok, i+2)) { int j = findEndOfTypeArgs(tok, i+2)-1; String type = joinSubList(tok, i+4, j); replaceTokens_reTok(tok, i+4, j, type + ", Object"); change = true; } } } static HashSet litset(A... items) { return lithashset(items); } // macro declareS { S s = blubbi(); } // // void myThing { // declareS // expands to: S s = blubbi(); // print(s); // } static void tok_localMacro(List tok) { int i; while ((i = jfind_reversed(tok, "macro {")) >= 0) { ping(); String macroName = tok.get(i+2); int iMacroOpeningBracket = i+4; int iMacroClosingBracket = findEndOfBlock(tok, iMacroOpeningBracket)-1; String replacement = joinSubList(tok, iMacroOpeningBracket+1, iMacroClosingBracket); // do the replacement print("Replacing macro " + macroName + " with <" + trim(replacement) + ">"); int end = findEndOfBlock(tok, iMacroClosingBracket)-1; for (int j = iMacroClosingBracket+2; j < end; j += 2) { ping(); if (eq(tok.get(j), macroName)) tok.set(j, replacement); } // delete macro declaration clearTokens(tok, i, iMacroClosingBracket+1); reTok(tok, i, end); } } static List tok_expandStarConstructors(List tok) { int n = tok.size(); mainLoop: for (int i = 3; i < n-6; i += 2) { String t = tok.get(i); if (!t.equals("*")) continue; String l = tok.get(i-2); if (!tok.get(i+2).equals("(")) continue; if (!eqOneOf(l, "}", "public", "private", "protected", ";", "{", "endif", "endifdef", "endifndef", ">", "") && neq(get(tok, i-4), "ifclass")){ print("Skipping star constructor: " + quote(l)); continue; } // ok, it seems like a constructor declaration. // Now find class name by going backwards. int j = i, level = 1; while (j > 0 && level > 0) { t = tok.get(j); if (t.equals("}")) ++level; if (t.equals("{")) --level; j -= 2; } // search for class name while (j > 0) { t = tok.get(j); String className; if (eqOneOf(t, "class", "record", "srecord", "noeq", "enum") && isIdentifier(className = tok.get(j+2))) { tok.set(i, className); // exchange constructor name! // now for the parameters. // Syntax: *(Learner *learner) { // We will surely add type inference here in time... :) j = i+2; while (!tok.get(j).equals("{")) j += 2; // skip calling super/this constructor if (eqGetOneOf(tok, j+2, "super", "this")) j = tok_findEndOfStatement(tok, j+2)-1; // find * arguments (copy to fields of same name) int block = j+1; for (int k = i+2; k < block-1; k += 2) if (tok.get(k).equals("*")) { removeSubList(tok, k, k+2); block -= 2; String name = tok.get(k); tok.addAll(block, Arrays.asList(new String[] { "\n ", "this", "", ".", "", name, " ", "=", " ", name, "", ";" })); } continue mainLoop; } j -= 2; } } return tok; } static void tok_kiloConstants(List tok) { if (!tok.contains("K")) return; jreplace(tok, " K", "($1*1024)"); } // references to objects in other realm (replace with Object) static void tok_virtualTypes(List tok) { int i = -1; while ((i = jfind(tok, i+1, "virtual ")) >= 0) { replaceTokens_reTok(tok, i, tok_findEndOfType(tok, i+2)-1, "Object"); } } static List tok_autoLongConstants(List tok) { int n = l(tok); for (int i = 1 ; i < n; i += 2) { String t = tok.get(i); if (isInteger(t) && !eq(get(tok, i+2), "L") && !eqOneOf(get(tok, i-2), /*"-",*/ /* huh? */ "." /* float/double */) && !longIsInt(parseLong(t))) tokAppend(tok, i, "L"); } return tok; } // unimplemented S bla(); => S bla() { throw unimplemented(); } static void tok_unimplementedMethods(List tok) { int i = -1; while ((i = jfind(tok, i+1, "unimplemented")) >= 0) { String t = get(tok, i+2); { if (!(isIdentifier(t) || eq(t, "<"))) continue; } int j = tok_findEndOfMethodHeader(tok, i)+1; replaceTokens(tok, i, i+2, ""); tokReplace(tok, j-1, " { throw unimplemented(); }"); reTok(tok, i, j); } } static void tok_switchableFields(List tok) { int i = -1; while ((i = jfind(tok, i+1, "switchable ")) >= 0) { String var = getVarDeclarationName(subList(tok, i+1)); tokSet_withReTok(tok, i, "sbool _switchableField_" + var + " = true;"); } } static void tok_autoDisposeFields(List tok) { int i = -1; while ((i = jfind(tok, i+1, "autoDispose ")) >= 0) { String var = getVarDeclarationName(subList(tok, i+1)); tokSet_withReTok(tok, i, ""); tokPrepend_withReTok(tok, leftScanModifiers(tok, i), "void cleanMeUp_" + var + "() { dispose " + var +"; } "); } } // visual bla(super); => visualize { ret bla(super.visualize()); } // cachedVisual bla(super); => cachedVisualize { ... } static void tok_shortVisualize(List tok) { int i = -1; while ((i = jfind_any(tok, i+1, "visual ", "cachedVisual ")) >= 0) { int j = tok_findEndOfStatement(tok, i); for (int k = i; k < j; k += 2) if (eqGet(tok, k, "super") && neqGet(tok, k+2, ".")) tokSet(tok, k, "super.visualize()"); tokSet(tok, j-1, "; }"); String head = eqGet(tok, i, "cachedVisual") ? "cachedVisualize" : "visualize"; tokSet(tok, i, head + " { ret"); reTok(tok, i, j); } } static void tok_whileGreaterThan(List tok) { int i = -1; while ((i = jfind(tok, "while >= (")) >= 0) { int iOpening = indexOf(tok, "(", i); int iClosing = findEndOfBracketPart(tok, iOpening)-1; tokSet_reTok(tok, iClosing, ") >= 0)"); replaceTokens_reTok(tok, i+2, iOpening+1, "(("); } } // if condition then code end static void tok_ifThenEnd(List tok) { int i = -1; while ((i = jfind(tok, i+1, "if ")) >= 0) { int iThen = indexOf(tok, i, "then"); if (iThen < 0) { print("No then for if"); continue; } int iEnd = tok_findTokenSkippingCurlyBrackets(tok, iThen, "end"); if (iEnd < 0) { print("No end for if"); continue; } tokSet(tok, iEnd, "}"); replaceTokens_reTok(tok, iThen-1, iThen+1, ") {"); replaceTokens_reTok(tok, i, i+2, "if ("); } } static void tok_autoInitVars(List tok) { jreplace(tok, "boolean ;", "boolean $2 = false;", new TokCondition() { public boolean get(final List tok, final int i) { return !contains(tok_modifiersLeftOf(tok, i+1), "final"); }}); } static void tok_fixBadTypeParameterOrder(List tok) { // e.g. void bla() => void bla() jreplace(tok, "void <>", "<$3> void"); } static void tok_svoidEtc(List tok) { jreplace(tok, "svoid", "static void"); } static void tok_questionDot(List tok) { jreplace_dyn(tok, "->?.", () -> { String var = makeVar(); return var + " -> " + var + "?."; }); jreplace(tok, "if ( ?. ?.")) >= 0) { String var = tok.get(i); boolean isExpression = eqGetOneOf(tok, i-2, "ret", "return", ",", "=", "(", "?", "+", ">"); // too few if (!isExpression) { int j = tok_findEndOfStatement(tok, i)-1; tokAppend_reTok(tok, j, " }"); tokReplace_reTok(tok, i, i+6, ("{ if (" + var + " != null) " + var + ".")); } else { String expr = (var + " == null ? null : " + var + "."); boolean needBrackets = eqGet(tok, i-2, "+"); if (needBrackets) { expr = "(" + expr; int j = tok_endOfExpression(tok, i)-1; tokPrepend_reTok(tok, j, ")"); } tokReplace_reTok(tok, i, i+6, expr); } } jreplace_dyn(tok, "()?.", new F2, Integer, String>() { public String get(List tok, Integer i) { try { int iQ = indexOf(tok, i, "?"); String expr = joinSubList(tok, i, iQ-1); boolean isExpression = eqGetOneOf(tok, i-2, "ret", "return", ",", "=", "(", "?"); // too few String var = makeVar(); if (!isExpression) { int j = tok_findEndOfStatement(tok, i)-1; tokAppend_reTok(tok, j, " }"); return ("{ var " + var + " = " + expr + "; if (" + var + " != null) " + var + "."); } else { // experimental int j = tok_findEndOfExpression(tok, i)-1; tokAppend_reTok(tok, j, ")"); return ("rCallF(" + expr + ", " + var + " -> " + var + " == null ?: " + var + "."); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "int iQ = indexOf(tok, i, \"?\");\r\n S expr = joinSubList(tok, i, iQ-1);\r\n ..."; }}); } static void tok_embeddedFunctions(List tok) { int i; while ((i = jfind(tok, "embedded ")) >= 0) { int j = tok_findEndOfMethodDecl(tok, i); // points to N after function String functionName = tok_functionName(subList(tok, i)); String className = makeVar("C"), varName = makeVar(); // drop keyword, rewrite function to class, create object //tok.set(i, "/* make final to optimize */ class " + className + " {"); tok.set(i, "final class " + className + " {"); tokAppend(tok, j-1, " } " + " final " + className + " " + varName + " = new " + className + "();"); // redirect calls to object int end = findEndOfBlock(tok, j)-1; for (j |= 1; j < end; j += 2) if (eq(tok.get(j), functionName) && eqGet(tok, j+2, "(")) tokPrepend(tok, j, varName + "."); reTok(tok, i, end); } } static void tok_quickNewArray(List tok) { jreplace_dyn_allowDollarRefs(tok, "[] = new[", cIdx -> { int iTypeStart = tok_leftScanType(tok, cIdx); String type = joinSubList(tok, iTypeStart, cIdx-1); return "[] $3 = new " + type + "["; } ); } static void tok_once(List tok) { replaceKeywordBlock(tok, "once", "do {", "} while (false);"); } // Note: the variable names must match the record field names // as we still need a way to find the field names from here static void tok_ifRecordMatch(List tok) { int i; while ((i = jfind_check("is", tok, "if is (")) >= 0) { int iOpening = indexOf(tok, i, "("); int iClosing = indexOf(tok, iOpening+2, ")"); String var = tok.get(i+2), className = tok.get(i+6); String cast = "((" + className + ") " + var + ")"; int start = iClosing+2; tok_statementToBlock(tok, start); int end = findEndOfStatement(tok, start); StringBuilder statement = new StringBuilder(("if (" + var + " instanceof " + className)); StringBuilder decls = new StringBuilder(); List> vars = tok_typesAndNamesOfParams(subList(tok, iOpening+1, iClosing)); for (Pair v : vars) { String type = v.a, name = v.b; String nonPrim = tok_toNonPrimitiveTypes(type); if (!tok_typeIsObject(type)) statement.append((" && " + cast + "." + name + " instanceof " + nonPrim)); decls.append(("\n" + type + " " + name + " = cast " + cast + "." + name + ";")); } replaceTokens_reTok(tok, i, start+1, statement + ") {" + decls); } } static void tok_returnSelf(List tok) { int i; mainLoop: while ((i = jfind(tok, "returnSelf ")) >= 0) { IntRange block = tok_findFirstBlock(tok, i); tok.set(i, "selfType"); tokPrepend(tok, block.end-1, " ret this; "); } } static void tok_tildeCalls(List tok) { int iTilde; jreplace(tok, ".~", "~."); // calls without type while ((iTilde = jfind(tok, "~.(")) >= 0) { int iStart = tok_findBeginningOfJavaXTerm(tok, iTilde-2); String fname = tok.get(iTilde+4); tokPrepend(tok, iStart, "call("); replaceTokens(tok, iTilde, iTilde+8, ", " + quote(fname) + (eqGet(tok, iTilde+8, ")") ? "" : ", ")); reTok(tok, iStart, iTilde+8); } // calls with type while ((iTilde = jfind(tok, "~. (")) >= 0) { int iStart = tok_findBeginningOfJavaXTerm(tok, iTilde-2); String type = get(tok, iTilde+4); int iFname = iTilde+6; String fname = tok.get(iFname); // TODO: brackets around the whole thing tokPrepend(tok, iStart, "(" + type + ") call("); replaceTokens(tok, iTilde, iFname+4, ", " + quote(fname) + (eqGet(tok, iFname+4, ")") ? "" : ", ")); reTok(tok, iStart, iFname+4); } // field access while ((iTilde = jfind(tok, "~.")) >= 0) { int iStart = tok_findBeginningOfJavaXTerm(tok, iTilde-2); String fieldName = tok.get(iTilde+4); tokPrepend(tok, iStart, "getOpt " + fieldName + "("); replaceTokens(tok, iTilde, iTilde+5, ")"); reTok(tok, iStart, iTilde+5); } } static void tok_swappableFunctions(List tok) { jreplace(tok, "swappable static", "static swappable"); jreplace(tok, "pswappable ", "persistently swappable $2"); jreplace(tok, "persistent swappable ", "persistently swappable $3"); jreplace(tok, "transient swappable ", "swappable $3"); int i; while ((i = jfind_any(tok, "swappable (", "swappable <", "swappable .", "swappable [")) >= 0) { // left-scan for modifiers int iModEnd = i; boolean persistently = eqGet(tok, i-2, "persistently"); if (persistently) iModEnd -= 2; int iMod = leftScanModifiers(tok, iModEnd); String modifiers = joinSubList(tok, iMod, iModEnd); // scan annotations int iAnnot = iMod; boolean atOverride = subListEquals(tok, iAnnot-4, "@", "", "Override"); if (atOverride) iAnnot -= 4; // scan return type, find function name int iEndOfType = tok_findEndOfType(tok, i+2); String returnType = joinSubList(tok, i+2, iEndOfType-1); String name = assertIdentifier(tok.get(iEndOfType)); int iArgs = iEndOfType+2; assertEquals("(", get(tok, iArgs)); try { int iCurly = indexOf(tok, iEndOfType, "{"); int iArgsEnd = lastIndexOf(tok, iCurly, ")"); assertTrue(iArgsEnd >= 0); String throwsClauses = joinSubList(tok, iArgsEnd+1, iCurly-1); // TODO List tokArgs = subList(tok, iArgs+1, iArgsEnd); List> args = tok_typesAndNamesOfParams(tokArgs); String args1 = join(tokArgs); String args2 = joinWithComma(pairsB(args)); boolean isVoidMethod = eq(returnType, "void"); List types = pairsA(args); if (!isVoidMethod) types.add(returnType); String typeParams = joinWithComma(map(type -> tok_varArgTypeToArray(tok_toNonPrimitiveTypes(type)), types)); // TODO: modifiers String base = name + "_base", fallback = name + "_fallback"; String mods = modifiers + (persistently || containsJavaToken(modifiers, "static") ? "" : "transient "); String mainFunctionModifiers = modifiers; String baseFunctionModifiers = modifiers; if (atOverride) mainFunctionModifiers = "@Override " + mainFunctionModifiers; String src; if (isVoidMethod) if (empty(args)) // no args, returning void src = mods + ("Runnable " + name + ";\n") + (mainFunctionModifiers + returnType + " " + name + "(" + args1 + ") { if (" + name + " != null) " + name + ".run(); else " + base + "(" + args2 + "); }\n") + ("final " + modifiers + returnType + " " + fallback + "(Runnable _f, " + args1 + ") { if (_f != null) _f.run(); else " + base + "(); }\n") + (baseFunctionModifiers + returnType + " " + base + "(" + args1 + ") {"); else { // args, returning void String varType = ("IVF" + (l(args)) + "<" + typeParams + ">"); src = (mods + " " + varType + " " + name + ";\n") + (mainFunctionModifiers + returnType + " " + name + "(" + args1 + ") { if (" + name + " != null) " + name + ".get(" + args2 + "); else " + base + "(" + args2 + "); }\n") + ("final " + modifiers + returnType + " " + fallback + "(" + varType + " _f, " + args1 + ") { if (_f != null) _f.get(" + args2 + "); else " + base + "(" + args2 + "); }\n") + (baseFunctionModifiers + returnType + " " + base + "(" + args1 + ") {"); } else { // zero or more args, not returning void String varType = ("IF" + (l(args)) + "<" + typeParams + ">"); src = (mods + " " + varType + " " + name + ";\n") + (mainFunctionModifiers + returnType + " " + name + "(" + args1 + ") { ret " + name + " != null ? " + name + ".get(" + args2 + ") : " + base + "(" + args2 + "); }\n") + ("final " + modifiers + returnType + " " + fallback + "(" + varType + " _f, " + args1 + ") { ret _f != null ? _f.get(" + args2 + ") : " + base + "(" + args2 + "); }\n") + (baseFunctionModifiers + returnType + " " + base + "(" + args1 + ") {"); } replaceTokens_reTok(tok, iAnnot, iCurly+1, src); } catch (Throwable e) { throw fail("Was processing function " + name, e); } } } static void tok_optParLambda(List tok) { jreplace(tok, "optParLambda1 ", "optPar $2(_, lambda1 $2)"); } static void tok_runnableClasses(List tok) { jreplace(tok, "runnable static record", "static runnable record"); int i; while ((i = jfind(tok, "runnable ", (_tok, nIdx) -> eqOneOf(tok.get(nIdx+3), "record", "class"))) >= 0) { int iOpening = indexOf(tok, i, "{"); int iClosing = tok_findEndOfBlock(tok, iOpening)-1; tokSet_reTok(tok, iClosing, "}}"); tokSet_reTok(tok, iOpening, "implements Runnable { run {"); clearTokens_reTok(tok, i, i+2); } /*replaceKeywordBlock(tok, "runnable class ", "class $3 implements Runnable { run {", "}}");*/ } static void tok_swapStatement(List tok) { jreplace_dyn(tok, "swap , ;", (_tok, cIdx) -> { String var = makeVar(), type = tok.get(cIdx+2), v1 = tok.get(cIdx+4), v2 = tok.get(cIdx+8); return ("{ " + type + " " + var + " = " + v1 + "; " + v1 + " = " + v2 + "; " + v2 + " = " + var + "; }"); }); } // void blu(optional S bla) { ... } // => void blu(S bla default null) { ... } static void tok_optionalArguments(List tok) { for (int i : jfindAll_reverse(tok, "optional ", (_tok, nIdx) -> eqGetOneOf(tok, nIdx-1, ",", "("))) { int iEndOfType = tok_endOfType(tok, i+2); String var = tok.get(iEndOfType); String type = joinSubList(tok, i+2, iEndOfType); tokReplace_reTok(tok, i, iEndOfType+1, (type + " " + var + " default null")); } } static void tok_usualDefaults(List tok) { jreplace(tok, "TimeZone usual default", "$1 $2 default defaultTimeZone()"); } static boolean tok_defaultArguments_debug = true; // only one default argument per declaration for now // example: // static LS parse(S productions, S sentenceClass default "sentence", S input) { ... } static void tok_defaultArguments(List tok) { while (licensed()) { boolean change = false; for (int i : jfindAll_reversed(tok, " default", new TokCondition() { public boolean get(final List tok, final int i) { return !eqGetOneOf(tok, i-1, "ifclass", "ifdef", "ifndef") && !isJavaModifier(_get(tok, i+1)); }})) { int iOpening = lastIndexOf(tok, i, "("); int iClosing = findEndOfBracketPart2(tok, iOpening)-1; boolean hasBody = tok_hasBody(tok, iClosing+2); //S args = joinSubList(tok, iOpening+2, iClosing-1); // function name int iName = iOpening-2; String name = get(tok, iName); boolean isConstructor = eq(name, "*"); if (!isConstructor && !isIdentifier(name)) continue; int iAkas = tok_leftScanAkas(tok, iName); name = get(tok, iAkas); int iJavaxMods = tok_leftScanJavaxModifiers(tok, iAkas); int iType = isConstructor ? iJavaxMods : tok_leftScanType(tok, iJavaxMods); int iStart = tok_leftScanTypeArgsOpt(tok, iType); int iModsEnd = iStart; iStart = leftScanModifiers(tok, iModsEnd); Collection modifiers = tok_modifiersLeftOf(tok, iModsEnd); if (!hasBody && !modifiers.contains("abstract")) modifiers.add("default"); modifiers.remove("abstract"); //print("Found method head: " + joinSubList(tok, iStart, iClosing+1)); int iEndOfExpr = tok_findEndOfExpression(tok, i+4)+1; // should point at comma or closing bracket String expr = joinSubList(tok, i+4, iEndOfExpr); int iParamTypeStart = tok_leftScanType(tok, i); List _args1 = subList(tok, iOpening+1, iParamTypeStart); List _args2 = subList(tok, iEndOfExpr+1, iClosing+2); List args1 = tok_parseArgsDeclList2(_args1); List args2 = tok_parseArgsDeclList2(_args2); List> args1withTypes = map(__55 -> tok_typeAndNameOfParam(__55), args1); List> args2withTypes = map(__56 -> tok_typeAndNameOfParam(__56), args2); List type = subList(tok, iType-1, iName); boolean isVoid = isConstructor || containsOneOf(codeTokens(type), javaxVoidAliases()); if (eq(expr, "new")) expr = "new " + joinSubList(tok, iParamTypeStart, i-1) + "()"; String rewrittenHead = spaceCombine(modifiers, joinSubList(tok, iModsEnd, iOpening+1) + joinWithComma(concatLists(args1, args2)) + ")"); if (tok_defaultArguments_debug) printVars("tok_defaultArguments", "expr", expr, "_args1", _args1, "_args2", _args2, "args1", args1, "args2", args2, "type", type, "isVoid", isVoid, "rewrittenHead", rewrittenHead, "args1withTypes", args1withTypes, "args2withTypes", args2withTypes); String forwardCall = (isVoid ? "" : "return ") + (isConstructor ? "this" : name) + "(" + joinWithComma(concatLists( pairsB(args1withTypes), ll(expr), pairsB(args2withTypes))) + ");"; clearTokens_reTok(tok, i+1, iEndOfExpr-1); tokPrepend_reTok(tok, iStart, rewrittenHead + " { " + forwardCall + " }\n"); change = true; } if (!change) break; } } // e.g. // void tailCall aka replace(Computable x) {...} // to: // void tailCall(Computable x) {...} // final void replace(Computable x) { tailCall(x); } // (or the other way around) static void tok_akaFunctionNames(List tok) { int i; boolean useFinal = true; while ((i = jfind(tok, " aka ")) >= 0) { int iName1 = i, _iLastName = i+4; while (eqGet(tok, _iLastName+2, "aka") && isIdentifier(get(tok, _iLastName+4))) _iLastName += 4; int iLastName = _iLastName; // find arguments int iOpening = indexOf(tok, iLastName, "("); int iClosing = findEndOfBracketPart2(tok, iOpening)-1; // find all names List names = new ArrayList(); for (int j = iName1; j <= iLastName; j += 4) names.add(tok.get(j)); // find javax modifiers, return type & modifiers int iType = tok_leftScanJavaxModifiers(tok, iName1); iType = tok_leftScanType(tok, iType); int iStart = leftScanModifiers(tok, tok_leftScanTypeArgsOpt(tok, iType)); // parse argument list List _args = subList(tok, iOpening+1, iClosing); List args = tok_parseArgsDeclList2(_args); // analyze return type List type = subList(tok, iType-1, iName1); // return type boolean isVoid = containsOneOf(codeTokens(type), javaxVoidAliases()); // drop all but first name clearTokens(tok, iName1+1, iLastName+1); int iBodyOpen = indexOfAny(tok, iClosing, "{", ";"); boolean hasBody = eqGet(tok, iBodyOpen, "{"); // The following logic is nasty, but the tests in test_tok_akaFunctionNames // make it alright // modifiers include return type actually List tokModifiers = cloneSubList(tok, iStart, iName1-1); boolean isAbstract = tokModifiers.remove("abstract"); boolean isDefault = tokModifiers.contains("default"); tokModifiers.remove("synchronized"); if (!isDefault && !isAbstract && !hasBody) { isDefault = true; tokModifiers.add(0, "default "); } String modifiers = join(tokModifiers); if (isDefault && !hasBody) replaceElementInSubList(tok, iStart, iType, "default", ""); // make synonyms final unless we're in an interface if (!isDefault && !contains(tokModifiers, "final")) modifiers = "final " + modifiers; String _modifiers = modifiers; //S exceptionClauses = joinSubList(tok, iClosing+1, iBodyOpen-1); // add synonyms tokPrepend(tok, iStart, joinMap(dropFirst(names), name -> _modifiers + " " + name // arguments and declared exceptions + joinSubList(tok, iLastName+1, iBodyOpen-1) + "{ " + stringIf(!isVoid, "return ") + first(names) + "(" + joinWithComma(lmap(__57 -> tok_lastIdentifier(__57), args)) + "); }\n")); reTok(tok, iStart, iLastName+1); } } static void tok_simplyCachedFunctions(List tok) { try { int i = -1; while ((i = jfind(tok, i+1, "simplyCached ")) >= 0) { Collection modifiers = tok_modifiersLeftOf(tok, i); int iMod = tok_leftScanModifiers(tok, i); int bracket = indexOf(tok, "(", i); String fName; try { fName = assertIdentifier(tok.get(bracket-2)); } catch (Throwable _e) { printTokenContext(tok, iMod, bracket-2); throw rethrow(_e); } int iMod2 = tok_rightScanModifiers(tok, i+2); modifiers.addAll(codeTokensFromSubList(tok, i+2, iMod2)); String type = joinSubList(tok, iMod2, bracket-3); String boxedType = tok_toNonPrimitiveTypes(type); String fieldMods = joinWithSpace(listMinus(modifiers, "final", "abstract")); String functionMods = joinWithSpace(listMinus(modifiers, "transient", "abstract")); String loadFunctionMods = joinWithSpace(listMinus(modifiers, "transient")); boolean isVoid = eq(type, "void"); String var = isVoid ? "ran_" + fName : fName + "_cache"; String implFunc = isVoid ? fName + "_impl" : fName + "_load"; String varType = isVoid ? "bool" : boxedType; String replacement = // variable declaration (fieldMods + " " + varType + " " + var + ";\n") + (functionMods + " " + type + " " + fName + "() { ") // function body + (isVoid ? ("if (" + var + ") ret; set " + var + "; " + implFunc + "();") : ("if (" + var + " == null) " + var + " = " + fName + "_load(); ret " + var + ";")) + "}\n\n" // beginning of impl function + (loadFunctionMods + " " + type + " " + implFunc); replaceTokens_reTok(tok, iMod, bracket-1, replacement); } } catch (Throwable __e) { pcallFail(__e); }} // adds default constructor to classes with "persistable" modifier // also allows "persistent" static void tok_persistableClasses(List tok) { int i; while((i = jfind_any(tok, new TokCondition() { public boolean get(final List tok, final int i) { for (int j = i+1; isIdentifier(_get(tok, j)); j += 2) if (eqGet(tok, j, "class")) return true; return false; }}, "persistable", "persistent")) >= 0) { int iClass = indexOf(tok, "class", i); String className = get(tok, iClass+2); int idx = indexOf(tok, iClass, "{"); int j = findEndOfBracketPart(tok, idx); List contents = subList(tok, idx+1, j); boolean hasDefaultConstructor = tok_hasDefaultConstructor(contents, className); printVars_str("tok_persistableClasses: ", "hasDefaultConstructor", hasDefaultConstructor, "className", className); if (!hasDefaultConstructor) tokAppend_reTok(tok, idx, "\n *() {}"); clearTokens_reTok(tok, i, i+2); // drop persistable keyword } } static void tok_transientClasses(List tok) { int i; while ((i = jfindOneOf(tok, "transient class", "transient class", "transient class")) >= 0) { IntRange body = tok_findCurlyBody(tok, i); tokAppend_reTok(tok, body.start, "\nbool _isTransient() { true; }"); clearTokens_reTok(tok, i, i+2); } } // e.g. (::bla) => (main::bla) static void tok_shortMethodReferences(List tok) { jreplace(tok, "::", "main::", new TokCondition() { public boolean get(final List tok, final int i) { String next = _get(tok, i+5); return i > 0 && !isIdentifier(_get(tok, i-1)) && (eq(next, "<") || isIdentifier(next)); }}); } static void tok_orCase(List tok) { jreplace_dyn(tok, "orCase", (_tok, cIdx) -> stringUnless(eqGet(tok, cIdx-2, "{"), "break; ") + "case", (_tok, nIdx) -> { String next = get(tok, nIdx+3); return isIdentifier(next) || isInteger(next) || isQuoted(next); }); } static void tok_beforeMethods(List tok) { replaceKeywordBlock(tok, "void :: before", "void $2() {", "super.$2(); }"); } static void tok_afterMethods(List tok) { replaceKeywordBlock(tok, "void :: after", "void $2() { super.$2();", "}"); } static void tok_returnAsFunctionName(List tok) { // distinguish from end of meta command ITokCondition cond = (_tok, nIdx) -> empty(get(tok, nIdx+2)); jreplace(tok, ".ret", "._return", cond); jreplace(tok, ".return", "._return", cond); } // get/set fieldName (refers to this.fieldName) // get/set fieldName(expr) (refers to expr.fieldName) static void tok_transpileGetSet(List tok) { jreplace(tok, "set/get ", "get/set $4"); for (int i : jfindAll_reverse(tok, "get/set ")) { String field = tok.get(i+6); int iOpening = i+8; int iClosing; if (eq(get(tok, iOpening), "(")) iClosing = tok_findEndOfBracketPart(tok, iOpening)-1; else iClosing = 0; String expr = iClosing == 0 ? "this" : tok_join(tok, iOpening+1, iClosing); int iEnd = iClosing == 0 ? iOpening-2 : iClosing; tokReplace_reTok(tok, i, iEnd+1, replaceDollarVars("iSetAndGet($expr, " + "(e, v) -> { e.$field = v; }, " + "e -> e.$field)", "expr", expr, "field", field)); } } // e.g. pcall myFunc(...) static void tok_pcallPrefix(List tok) { jreplace_dyn(tok, "pcall (", (_tok, i) -> { String fname = tok.get(i+2); int iClosing = tok_findEndOfBracketPart(tok, i+4)-1; tokAppend_reTok(tok, iClosing, ")"); return "pcallF(() -> " + fname + "("; }); } static void tok_numberFunctionNames(List tok) { int n = l(tok); List reToks = new ArrayList(); for (int i = 1; i < n-2; i += 2) { String number, id; if (isInteger(number = tok.get(i)) && empty(tok.get(i+1)) && isIdentifier(id = tok.get(i+2))) { try { { if (eq(number, "0") && swicOneOf(id, "x", "b")) continue; } // skip hex/binary constants { if (eqic(id, "f")) continue; } // skip float constants // skip exponential floating-point constants (e.g. 1e6) if (swic(id, "e") && (l(id) == 1 && empty(get(tok, i+3)) && eqGet(tok, i+4, "-") || startsWithInteger(substring(id, 1)))) continue; // skip numbers with underscores like 1_000 if (startsWith(id, "_")) continue; replaceTokens_reTokLater(tok, reToks, i, i+3, camelCase(numberToEnglish(parseLong(number))) + firstToUpper(id)); } catch (Throwable __e) { pcallFail(__e); }} } reTok_multi(tok, reToks); } // e.g. cast req to Req; // (converts req to (Req) req for the rest of the block) static void tok_castToStatements(List tok) { int i; while ((i = jfind(tok, "cast to")) >= 0) { String id = tok.get(i+2); int iTypeStart = i+6; int semicolon = findEndOfStatement(tok, iTypeStart)-1; int endOfOuterBlock = findEndOfBracketPart(tok, semicolon)-1; String type = joinSubList(tok, iTypeStart, semicolon-1); tok_insertCasts_noReTok(tok, semicolon+2, endOfOuterBlock, id, type); clearTokens(tok, i, semicolon+1); reTok(tok, i, endOfOuterBlock); } } // optional S bla; // => S bla() { ret getOpt(this, "bla"); } // void bla(S bla) { setOpt(this, "bla", bla); } static void tok_optionalFields(List tok) { for (int i : jfindAll_reverse(tok, "optional ")) { int iSemicolon = tok_endOfStatement(tok, i)-1; String var = tok.get(iSemicolon-2); String type = joinSubList(tok, i+2, iSemicolon-3); tokReplace_reTok(tok, i, iSemicolon+1, ("public " + type + " " + var + "() { ret (" + type + " getOpt(this, " + (quote(var)) + "); }\n") + ("public void var(" + type + " var) { setOpt(this, " + (quote(var)) + ", " + var + "); }")); } } // S name from req; => S name = req?.get("name"); static void tok_getFromMap(List tok) { int i; jreplace_dyn_allowNull(tok, " from ;", (_tok, start, end) -> { String type = tok.get(start); String var = tok.get(start+2); String map = tok.get(start+6); return type + " " + var + " = " + map + "?.get(" + quote(var) + ");"; }); } // "->" short for "() ->" // "Runnable ->" short for "(Runnable) () ->" // "-> .x" short for "__0 -> __0.x" static void tok_shortLambdas(List tok) { jreplace_dyn(tok, "-> .", (_tok, cIdx) -> { var var = makeVar(); return var + " -> " + var + "." + _tok.get(cIdx+6); }); jreplace(tok, "->", "() ->", new TokCondition() { public boolean get(final List tok, final int i) { String prev = _get(tok, i-1); return eqOneOf(prev, null, "=", "(", ",", "return", ":", ">"); }}); jreplace(tok, "Runnable ->", "(Runnable) () ->"); } // e.g.: // sclass Bla extends Stages & Var { static void tok_andVarMixIn(List tok) { for (var i : jfindAll_reversed_any(tok, "& Var<> {", "& Var<<>> {")) { int iOpening = indexOf(tok, i, "{"); String valueType = tok_scanTypeArgWithoutBrackets(tok, indexOf(tok, i, "<")); int iClosing = tok_endOfBracketPart(tok, iOpening)-1; // get Var include List tokVar = javaTok(cacheGet("#1032845")); jreplace(tokVar, "A", valueType); // find code that is to be executed before get() returns a result int iGet = jfind_upTo(tok, iOpening, iClosing, "get :: before {"); if (iGet >= 0) { int iOpening2 = indexOf(tok, iGet, "{"); int iClosing2 = tok_endOfBracketPart(tok, iOpening2)-1; String code = joinSubList(tok, iOpening2+1, iClosing2); jreplace1(tokVar, "get() {", "get() {" + code); clearTokens_reTok(tok, iGet, iClosing2+1); } tokReplace_reTok(tok, iOpening+1, "\n" + join(tokVar) + "\n"); tokReplace_reTok(tok, i, i+3, "implements IVar"); } } static void tok_stages(List tok) { // anonymous stage (name = shortened source code) replaceKeywordBlock(tok, "stage", "{ stage(r {", "}); }"); // named stage replaceKeywordPlusQuotedBlock_dyn(tok, "stage", (_tok, iKeyword) -> stringArray("{ stage(" + tok.get(iKeyword+2) + ", r {", "}); }")); // stage with name and variable for (var iStage : rjfindAll(tok, "stage ")) { String id = tok.get(iStage+2); String name = tok.get(iStage+4); int iOpening = iStage+6; assertEquals("{", tok.get(iOpening)); int iClosing = tok_findEndOfBlock(tok, iOpening)-1; tokSet_reTok(tok, iClosing, "});"); replaceTokens_reTok(tok, iStage, iOpening, ("Stage " + id + " = stage(") + name + ", r "); } } static void tok_beginPeriod(List tok) { for (var i : jfind_all_reversed(tok, "begin.", (_tok, nIdx) -> startsWithSpaceEtc(_get(tok, nIdx+4)))) { int iClosing = tok_findEndOfBlock(tok, i)-1; tokPrepend_reTok(tok, iClosing, "}\n"); tokReplace_reTok(tok, i, i+3, "public void run aka get() {"); } } static void tok_enterStatement(List tok) { jreplace(tok, "enter;", "temp enter();", (_tok, nIdx) -> tok_isBeginningOfStatement(tok, nIdx+1)); } static void tok_settableFields(List tok) { new Tok_SettableFields().run(tok); new Tok_SettableWithChangeFields().run(tok); new Tok_SettableWithVar().run(tok); tok_gettableFields(tok); } // turns out reMutable and reImmutable are the same thing :) // TODO: handle this.myVar static void tok_reImmutableVars(List tok) { tok_unifyKeywords(tok, remutableKeywords(), "reImmutable"); // without assignment jreplace_dyn(tok, "reImmutable ;", (_tok, i) -> { String var = _get(tok, i+2); String var2 = makeVar(var); return ("var " + var2 + " = " + var + "; replace var " + var + " with " + var2 + ".\n"); }); // with assignment for (int i : jfind_all_reversed(tok, "reImmutable =")) { String var = _get(tok, i+2); String var2 = makeVar(var); int j = tok_endOfStatement(tok, i+6); String expr = joinSubList(tok, i+6, j-1); tokReplace_reTok(tok, i, j, ("var " + var2 + " = " + expr + "; replace var " + var + " with " + var2 + ".\n")); } } // currently only prints method invocation (not result) // because the latter is currently too complicated // (but AI is coming soon!) static void tok_scaffoldedFunctions(List tok) { for (int i : jrfindAll_any(tok, "scaffolded ", "scaffolded <")) { Tok_MethodDecl method = new Tok_MethodDecl(tok, i+2); if (!method.get()) continue; if (method.hasBody()) tokAppend_reTok(tok, method.iBody, "\n" + "if (metaGet(\"scaffolding\") != null) " + formatFunctionCall("scaffoldCalled", commaCombine( "this", quote(method.name()), method.argNames())) + ";"); tokClear_reTok(tok, i, i+2); } } static void tokReplace_reTok(List tok, int i, int j, String s) { replaceTokens_reTok(tok, i, j, s); } static void tokReplace_reTok(List tok, int i, String s) { replaceTokens_reTok(tok, i, i+1, s); } // add {} to a statement if it isn't a block already // i = beginning of statement or block static void tok_statementToBlock(List tok, int i) { if (neqGet(tok, i, "{")) { int iEnd = tok_findEndOfStatement(tok, i)-1; tokAppend_reTok(tok, iEnd, " }"); tokPrepend_reTok(tok, i, "{ "); } } static void tok_whileCast(List tok) { jreplace(tok, "while ( cast ) {", "while ($3 instanceof $5) { cast $3 to $5;"); } // example: // sS loadTextFile(File/S file) { ... } static void tok_multiTypeArguments_v2(List tok) { int i; // File/S while ((i = jfind(tok, "File/ ", (_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, " etc ")) >= 0) { String mainType = tok.get(i); String argName = tok.get(i+4); int iArgEnd = i+6; List> alts = new ArrayList(); // altType, converter boolean v3 = false; if (eq(mainType, "Graphics2D")) alts.add(pair("BufferedImage", "graphics")); else if (eq(mainType, "File")) alts.add(pair("String", "toFile")); else if (eq(mainType, "BWImage")) alts.add(pair("BufferedImage", "toBWImage")); 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, "Runnable")) alts.add(pair("IF0", "if0ToRunnable")); else if (eq(mainType, "Component")) alts.add(pair("Swingable", "toComponent")); else if (eq(mainType, "JComponent")) alts.add(pair("Swingable", "toJComponent")); else if (eq(mainType, "WidthAndHeight")) { alts.add(pair("Dimension", "toWidthAndHeight")); alts.add(pair(("int " + argName + "_w, int " + argName + "_h"), ("widthAndHeight(" + argName + "_w, " + argName + "_h)"))); v3 = true; } else if (eq(mainType, "Pt")) { alts.add(pair(("int " + argName + "_x, int " + argName + "_y"), ("pt(" + argName + "_x, " + argName + "_y)"))); v3 = true; } else if (eqOneOf(mainType, "DoublePt", "IDoublePt")) { alts.add(pair(("double " + argName + "_x, double " + argName + "_y"), ("doublePt(" + argName + "_x, " + argName + "_y)"))); v3 = true; } if (empty(alts)) throw fail("Unknown multi-type: " + joinSubList(tok, i, iArgEnd)); if (v3) tok_expandMultiTypeArgument_v3(tok, i, iArgEnd, argName, mainType, alts); else tok_expandMultiTypeArgument_v2(tok, i, iArgEnd, argName, mainType, alts); } // Iterable or X[], Iterable<> or X... IntRange r; for (String modifier : ll("[]", "...")) while ((r = jfind_range(tok, "Iterable<> or " + modifier + " ")) != 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, " * *" + modifier + " ", new F2, Integer, Object>() { public Object get(List 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); } } static void tok_printIfdef(List tok) { for (String keyword : ll("print", "printVars")) for (int i : jfind_all_reversed(tok, keyword + " ifdef ")) { String flag = tok.get(i+4); int iEnd = tok_findEndOfStatement(tok, i+6); String args = joinSubList(tok, i+6, iEnd); tokReplace_reTok(tok, i, iEnd, ("ifdef " + flag + " " + keyword + " " + args + " endifdef ")); } } static void tok_swingBlocks(List tok) { replaceKeywordBlock_dyn(tok, "swing", (_tok, iOpening, iClosing) -> containsReturnWithArgument(subList(tok, iOpening+1, iClosing)) ? litstringarray("{ ret swing(-> {", "}); }") : litstringarray("{ swing(-> {", "}); }") ); } // for an example see HashedBWImage static void tok_defEquals(List tok) { replaceKeywordBlock(tok, "equals ", "public bool equals(O $3) { if ($3 cast $2) {", "} false; }"); } /* swap method o.add(a, b) to { ret super + " (added)"; } or: swap method o.add(a, b) { ret super + " (added)"; } => var add_old = cc.add; o.add = (a, b) -> { ret o.add_fallback(add_old, a, b) + " (added)"; }; */ static void tok_swapFunctions(List tok) { int i; while ((i = jfind(tok, "swap method .(")) >= 0) { String obj = tok.get(i+4); String methodName = tok.get(i+8); int iOpening = i+10; int iClosing = indexOf(tok, i, ")"); String args = joinSubList(tok, iOpening+2, iClosing-1); int iOpeningCurly = iClosing+2; if (eqGet(tok, iOpeningCurly, "to")) iOpeningCurly += 2; assertEquals(get(tok, iOpeningCurly), "{"); int iClosingCurly = tok_findEndOfBlock(tok, iOpeningCurly)-1; String add_old = makeVar(); List tokBody = cloneList(cncSubList(tok, iOpeningCurly+1, iClosingCurly)); boolean needsSuper = jreplace_dyn(tokBody, "super", (_tok, nIdx) -> !eqGet(_tok, nIdx+3, "."), () -> (obj + "." + methodName + "_fallback(" + add_old + ", " + args + ")")); String assignment = (obj + "." + methodName + " = (" + args + ") -> { ") + join(tokBody) + "};"; String src = needsSuper ? ("{ var " + add_old + " = " + obj + "." + methodName + "; \n") + assignment + "\n}" : assignment; replaceTokens_reTok(tok, i, iClosingCurly+1, src); } } static void tok_dotPlus(List tok) { jreplace(tok, ".+", ".$3($3)"); } static void tok_processMetaBlocks(List tok, boolean metaCodeAllowed) { for (int i = 0; i < 1000; i++) { int idx = findCodeTokens(tok, "meta", "{"); if (idx < 0) break; if (!metaCodeAllowed) throw fail("Meta code not allowed"); int j = findEndOfBracketPart(tok, idx+2); String code = joinSubList(tok, idx+4, j-2); print("Evaluating: " + code); String result = str(javaEval(code)); replaceTokens_reTok(tok, idx, j+1, result); } } static boolean reTok_modify_check = false; static List reTok_modify(IF1, List> f, List tok, int i, int j) { return reTok_modify(tok, i, j, f); } // f: func(L) -> L static List reTok_modify(List tok, int i, int j, Object f) { // extend i to an "N" token // and j to "C" (so j-1 is an "N" token) i = i & ~1; j = j | 1; List t = javaTok(joinSubList(tok, i, j)); if (f != null) { t = (List) callF(f, t); if (reTok_modify_check) assertEquals("Improperly tokenized", javaTok(join(t)), t); } replaceListPart(tok, i, j, t); return tok; } // removes invocations from src static List tok_findTranslators(List tok, List libsOut) { int i; while ((i = jfind(tok, "!")) >= 0) { setAdd(libsOut, tok.get(i+2)); clearTokens(tok, i, i+3); reTok(tok, i, i+3); } return tok; } static boolean structure_showTiming, structure_checkTokenCount; static String structure(Object o) { return structure(o, new structure_Data()); } static String structure(Object o, structure_Data d) { StringWriter sw = new StringWriter(); d.out = new PrintWriter(sw); structure_go(o, d); String s = str(sw); if (structure_checkTokenCount) { print("token count=" + d.n); assertEquals("token count", l(javaTokC(s)), d.n); } return s; } static void structure_go(Object o, structure_Data d) { structure_1(o, d); while (nempty(d.stack)) popLast(d.stack).run(); } static void structureToPrintWriter(Object o, PrintWriter out) { structureToPrintWriter(o, out, new structure_Data()); } static void structureToPrintWriter(Object o, PrintWriter out, structure_Data d) { d.out = out; structure_go(o, d); } // leave to false, unless unstructure() breaks static boolean structure_allowShortening = false; // info on how to serialize objects of a certain class static class structure_ClassInfo { Class c; String shortName; List fields; Method customSerializer; IVF1 serializeObject; // can be set by caller of structure function boolean special = false; // various special classes boolean nullInstances = false; // serialize all instances as null (e.g. lambdas/anonymous classes) boolean javafy = false; // always convert to "j ..." Object emptyInstance; // to grab default field values from public String toString() { return commaCombine( "Class " + className(c), stringIf("special", special), stringIf("customSerializer", customSerializer != null), stringIf("javafy", javafy), stringIf("nullInstances", nullInstances)); } void nullInstances(boolean b) { this.nullInstances = b; if (b) special = true; } void javafy(boolean b) { this.javafy = b; if (b) special = true; } // overridable - return true if you wrote the object boolean handle(A o) { return false; } } static class structure_Data { PrintWriter out; int stringSizeLimit; int shareStringsLongerThan = 20; boolean noStringSharing = false; boolean storeBaseClasses = false; boolean honorFieldOrder = true; String mcDollar = actualMCDollar(); final public structure_Data setWarnIfUnpersistable(boolean warnIfUnpersistable){ return warnIfUnpersistable(warnIfUnpersistable); } public structure_Data warnIfUnpersistable(boolean warnIfUnpersistable) { this.warnIfUnpersistable = warnIfUnpersistable; return this; } final public boolean getWarnIfUnpersistable(){ return warnIfUnpersistable(); } public boolean warnIfUnpersistable() { return warnIfUnpersistable; } boolean warnIfUnpersistable = true; final public structure_Data setStackTraceIfUnpersistable(boolean stackTraceIfUnpersistable){ return stackTraceIfUnpersistable(stackTraceIfUnpersistable); } public structure_Data stackTraceIfUnpersistable(boolean stackTraceIfUnpersistable) { this.stackTraceIfUnpersistable = stackTraceIfUnpersistable; return this; } final public boolean getStackTraceIfUnpersistable(){ return stackTraceIfUnpersistable(); } public boolean stackTraceIfUnpersistable() { return stackTraceIfUnpersistable; } boolean stackTraceIfUnpersistable = true; // skip a field if it has the default value defined in the class // -slower, and may cause issues with schema evolution // -OTOH, it can serialize null values for a field with default non-null value final public structure_Data setSkipDefaultValues(boolean skipDefaultValues){ return skipDefaultValues(skipDefaultValues); } public structure_Data skipDefaultValues(boolean skipDefaultValues) { this.skipDefaultValues = skipDefaultValues; return this; } final public boolean getSkipDefaultValues(){ return skipDefaultValues(); } public boolean skipDefaultValues() { return skipDefaultValues; } boolean skipDefaultValues = false; structure_Data d() { return this; } transient IF1 shouldIncludeField; boolean shouldIncludeField(Field f) { return shouldIncludeField != null ? shouldIncludeField.get(f) : shouldIncludeField_base(f); } final boolean shouldIncludeField_fallback(IF1 _f, Field f) { return _f != null ? _f.get(f) : shouldIncludeField_base(f); } boolean shouldIncludeField_base(Field f) { return true; } IdentityHashMap seen = new IdentityHashMap(); //new BitSet refd; HashMap strings = new HashMap(); HashSet concepts = new HashSet(); HashMap infoByClass = new HashMap(); // wrapper for _persistenceInfo field or _persistenceInfo method // by class (taking the object instance) HashMap> persistenceInfo = new HashMap(); int n; // token count List stack = new ArrayList(); // append single token structure_Data append(String token) { out.print(token); ++n; return this; } structure_Data append(int i) { out.print(i); ++n; return this; } // append multiple tokens structure_Data append(String token, int tokCount) { out.print(token); n += tokCount; return this; } // extend last token structure_Data app(String token) { out.print(token); return this; } structure_Data app(int i) { out.print(i); return this; } structure_Data app(char c) { out.print(c); return this; } structure_ClassInfo infoForClass(Class c) { structure_ClassInfo info = infoByClass.get(c); if (info == null) info = newClass(c); return info; } transient IF1 realShortName; String realShortName(String name) { return realShortName != null ? realShortName.get(name) : realShortName_base(name); } final String realShortName_fallback(IF1 _f, String name) { return _f != null ? _f.get(name) : realShortName_base(name); } String realShortName_base(String name) { return dropPrefix("main$", dropPrefix("loadableUtils.utils$", dropPrefix(mcDollar, name))); } // called when a new class is detected // can be overridden by clients structure_ClassInfo newClass(Class c) { // special classes here! var d = d(); boolean isJavaXClass = isJavaXClassName(c.getName(), mcDollar); if (c == String.class) return new structure_ClassInfo() { @Override boolean handle(String o) { String s = d.stringSizeLimit != 0 ? shorten((String) o, d.stringSizeLimit) : (String) o; if (!d.noStringSharing) { if (d.shareStringsLongerThan == Integer.MAX_VALUE) d.seen.put(o, d.n); if (l(s) >= d.shareStringsLongerThan) d.strings.put(s, d.n); } quoteToPrintWriter(s, d.out); d.n++; return true; } }; if (c == File.class) return new structure_ClassInfo() { @Override boolean handle(File o) { append("File ").append(quote(o.getPath())); return true; } }; if (!isJavaXClass) { if (isSubClassOf(c, Set.class)) return new structure_ClassInfo() { @Override boolean handle(Set o) { writeSet(o); return true; } }; if (isSubClassOf(c, Collection.class)) return new structure_ClassInfo() { @Override boolean handle(Collection o) { writeCollection(o); return true; } }; if (isSubClassOf(c, Map.class)) return new structure_ClassInfo() { @Override boolean handle(Map o) { writeMap(o); return true; } }; } structure_ClassInfo info = new structure_ClassInfo(); info.c = c; infoByClass.put(c, info); String name = c.getName(); String shortName = realShortName(name); if (startsWithDigit(shortName)) shortName = name; // for anonymous classes info.shortName = shortName; try { if (isSyntheticOrAnonymous(c)) { info.nullInstances(true); return info; } if (c.isEnum()) { info.special = true; return info; } if (c.isArray()) { // info.special? return info; } if ((info.customSerializer = findMethodNamed(c, "_serialize")) != null) info.special = true; if (storeBaseClasses) { Class sup = c.getSuperclass(); if (sup != Object.class) { append("bc "); append(shortDynClassNameForStructure(c)); out.print(" "); append(shortDynClassNameForStructure(sup)); out.print(" "); infoForClass(sup); // transitively write out superclass relations } } if (eqOneOf(name, "java.awt.Color", "java.lang.ThreadLocal")) info.javafy(true); else if (name.startsWith("sun") || !isPersistableClass(c)) { info.javafy(true); if (warnIfUnpersistable) { String msg = "Class not persistable: " + c + " (anonymous or no default constructor), referenced from " + last(stack); if (stackTraceIfUnpersistable) printStackTrace(new Throwable(msg)); else print(msg); } } else if (skipDefaultValues) { var ctor = getDefaultConstructor(c); if (ctor != null) info.emptyInstance = invokeConstructor(ctor); } } catch (Throwable e) { printStackTrace(e); info.nullInstances(true); } return info; } void setFields(structure_ClassInfo info, List fields) { info.fields = fields; } void writeObject(Object o, String shortName, Map fv) { String singleField = fv.size() == 1 ? first(fv.keySet()) : null; append(shortName); n += countDots(shortName)*2; // correct token count int l = n; Iterator it = fv.entrySet().iterator(); class WritingObject implements Runnable { String lastFieldWritten; public void run() { try { if (!it.hasNext()) { if (n != l) append(")"); } else { Map.Entry e = (Map.Entry) (it.next()); append(n == l ? "(" : ", "); append(lastFieldWritten = (String) e.getKey()).append("="); stack.add(this); structure_1(e.getValue(), structure_Data.this); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return shortName + "." + lastFieldWritten; } } stack.add(new WritingObject()); } void writeMap(Map o) { var d = this; String name = o.getClass().getName(); if (o instanceof LinkedHashMap) d.append("lhm"); else if (o instanceof HashMap) d.append("hm"); else if (o instanceof TreeMap) d.append(isCIMap_gen((TreeMap) o) ? "cimap" : "tm"); else if (name.equals("java.util.Collections$SynchronizedMap") || name.equals("java.util.Collections$SynchronizedSortedMap") || name.equals("java.util.Collections$SynchronizedNavigableMap")) { d.append("sync "); { structure_1(unwrapSynchronizedMap(((Map) o)), d); return; } } d.append("{"); final int l = d.n; final Iterator it = cloneMap((Map) o).entrySet().iterator(); class WritingMap implements Runnable { boolean v = false; Map.Entry e; public String toString() { return renderVars("WritingMap", "e" , mapEntryToPair(e), "v" , !v); } public void run() { try { if (v) { d.append("="); v = false; d.stack.add(this); structure_1(e.getValue(), d); } else { if (!it.hasNext()) d.append("}"); else { e = (Map.Entry) it.next(); v = true; d.stack.add(this); if (d.n != l) d.append(", "); structure_1(e.getKey(), d); } } } catch (Exception __e) { throw rethrow(__e); } } } d.stack.add(new WritingMap()); } void writeSet(Set o) { var d = this; String name = o.getClass().getName(); /*O set2 = unwrapSynchronizedSet(o); if (set2 != o) { d.append("sync"); o = set2; } TODO */ if (o instanceof TreeSet) { d.append(isCISet_gen(o) ? "ciset" : "treeset"); structure_1(new ArrayList(o), d); return; } // assume it's a HashSet or LinkedHashSet d.append(o instanceof LinkedHashSet ? "lhs" : "hashset"); structure_1(new ArrayList(o), d); } void writeCollection(Collection o) { var d = this; String name = o.getClass().getName(); if (name.equals("java.util.Collections$SynchronizedList") || name.equals("java.util.Collections$SynchronizedRandomAccessList")) { d.append("sync "); { structure_1(unwrapSynchronizedList(((List) o)), d); return; } } else if (name.equals("java.util.LinkedList")) d.append("ll"); d.append("["); int l = d.n; Iterator it = cloneList(o).iterator(); d.stack.add(new Runnable() { public void run() { try { if (!it.hasNext()) d.append("]"); else { d.stack.add(this); if (d.n != l) d.append(", "); structure_1(it.next(), d); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (!it.hasNext())\r\n d.append(\"]\");\r\n else {\r\n d.stack.add..."; }}); } } // end of class structure_Data static void structure_1(Object o, structure_Data d) { try { if (o == null) { d.append("null"); return; } Class c = o.getClass(); boolean concept = false; structure_ClassInfo info = d.infoForClass(c); boolean isJavaXName = isJavaXClassName(c.getName(), d.mcDollar); boolean referencable = isJavaXName && !(o instanceof Number || o instanceof Character || o instanceof Boolean) || o instanceof Collection || o instanceof Map || o instanceof Rectangle; if (referencable) { Integer ref = d.seen.get(o); if (ref != null) { //d.refd.set(ref); d.append("t").app(ref); return; } d.seen.put(o, d.n); // record token number } if (info.handle(o)) { return; } if (info.special) { if (info.javafy) { d.append("j ").append(quote(str(o))); return; // This is not unstructure-able except for java.awt.Color } if (c.isEnum()) { d.append("enum "); d.append(info.shortName); d.out.append(' '); d.append(((Enum) o).ordinal()); return; } if (info.customSerializer != null) { // custom serialization (_serialize method) Object o2 = invokeMethod(info.customSerializer, o); if (o2 == o) {} // bail out to standard serialization else { d.append("cu "); String name = c.getName(); String shortName = d.realShortName(name); d.append(shortName); d.out.append(' '); structure_1(o2, d); return; } } else if (info.nullInstances) { d.append("null"); return; } else if (info.serializeObject != null) { info.serializeObject.get(o); return; } else throw fail("unknown special type"); } List lFields = info.fields; if (lFields == null) { // these are never back-referenced (for readability) if (o instanceof Number) { PrintWriter out = d.out; if (o instanceof Integer) { int i = ((Integer) o).intValue(); out.print(i); d.n += i < 0 ? 2 : 1; return; } if (o instanceof Long) { long l = ((Long) o).longValue(); out.print(l); out.print("L"); d.n += l < 0 ? 2 : 1; return; } if (o instanceof Short) { short s = ((Short) o).shortValue(); d.append("sh "); out.print(s); d.n += s < 0 ? 2 : 1; return; } if (o instanceof Float) { d.append("fl ", 2); quoteToPrintWriter(str(o), out); return; } if (o instanceof Double) { d.append("d(", 3); quoteToPrintWriter(str(o), out); d.append(")"); return; } if (o instanceof BigInteger) { out.print("bigint("); out.print(o); out.print(")"); d.n += ((BigInteger) o).signum() < 0 ? 5 : 4; return; } } if (o instanceof Boolean) { d.append(((Boolean) o).booleanValue() ? "t" : "f"); return; } if (o instanceof Character) { d.append(quoteCharacter((Character) o)); return; } String name = c.getName(); if (!isJavaXName) { if (o instanceof Set) { d.writeSet((Set) o); return; } if (o instanceof Collection /* && neq(name, "main$Concept$RefL") */) { { d.writeCollection((Collection) o); return; } } if (o instanceof Map) { d.writeMap((Map) o); return; } } if (c.isArray()) { if (o instanceof byte[]) { d.append("ba ").append(quote(bytesToHex((byte[]) o))); return; } final int n = Array.getLength(o); if (o instanceof boolean[]) { String hex = boolArrayToHex((boolean[]) o); int i = l(hex); while (i > 0 && hex.charAt(i-1) == '0' && hex.charAt(i-2) == '0') i -= 2; d.append("boolarray ").append(n).app(" ").append(quote(substring(hex, 0, i))); return; } if (o instanceof short[]) { String hex = shortArrayToHex_bigEndian((short[]) o); d.append("shortarray \"").append(hex).app('\"'); return; } if (o instanceof long[]) { String hex = longArrayToHex_bigEndian((long[]) o); d.append("longarray \"").append(hex).app('\"'); return; } String atype = "array"/*, sep = ", "*/; // sep is not used yet if (o instanceof int[]) { //ret "intarray " + quote(intArrayToHex((int[]) o)); atype = "intarray"; //sep = " "; } else if (o instanceof double[]) { atype = "dblarray"; //sep = " "; } else if (o instanceof float[]) { atype = "floatarray"; } else { // 2-dimensional and deeper arrays Pair p = arrayTypeAndDimensions(c); if (p.a == int.class) atype = "intarray"; else if (p.a == byte.class) atype = "bytearray"; else if (p.a == boolean.class) atype = "boolarray"; else if (p.a == double.class) atype = "dblarray"; else if (p.a == float.class) atype = "floatarray"; else if (p.a == String.class) { atype = "array S"; d.n++; } else atype = "array"; // fail("Unsupported array type: " + p.a); if (p.b > 1) { atype += "/" + p.b; // add number of dimensions d.n += 2; // 2 additional tokens will be written } } d.append(atype).append("{"); d.stack.add(new Runnable() { int i; public void run() { if (i >= n) d.append("}"); else { d.stack.add(this); if (i > 0) d.append(", "); structure_1(Array.get(o, i++), d); } } }); return; } if (o instanceof Class) { d.append("class(", 2).append(quote(((Class) o).getName())).append(")"); return; } if (o instanceof Throwable) { d.append("exception(", 2).append(quote(((Throwable) o).getMessage())).append(")"); return; } if (o instanceof BitSet) { BitSet bs = (BitSet) o; d.append("bitset{", 2); int l = d.n; for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) { if (d.n != l) d.append(", "); d.append(i); } d.append("}"); return; } /*if (name.equals("main$Lisp")) { fail("lisp not supported right now"); }*/ String dynName = shortDynClassNameForStructure(o); if (concept && !d.concepts.contains(dynName)) { d.concepts.add(dynName); d.append("c "); } // serialize an object with fields. // first, collect all fields and values in fv. TreeSet fields = new TreeSet(new Comparator() { public int compare(Field a, Field b) { return stdcompare(a.getName(), b.getName()); } }); Class cc = c; while (cc != Object.class) { for (Field field : getDeclaredFields_cached(cc)) { if (!d.shouldIncludeField(field)) continue; String fieldName = field.getName(); if (fieldName.equals("_persistenceInfo")) d.persistenceInfo.put(c, obj -> (Map) fieldGet(field, obj)); if ((field.getModifiers() & (java.lang.reflect.Modifier.STATIC | java.lang.reflect.Modifier.TRANSIENT)) != 0) continue; fields.add(field); // put special cases here...? } cc = cc.getSuperclass(); } Method persistenceInfoMethod = findInstanceMethod(c, "_persistenceInfo"); if (persistenceInfoMethod != null) d.persistenceInfo.put(c, obj -> (Map) invokeMethod(persistenceInfoMethod, obj)); lFields = asList(d.honorFieldOrder ? fieldObjectsInFieldOrder(c, fields) : fields); // Render this$0/this$1 first because unstructure needs it for constructor call. int n = l(lFields); for (int i = 0; i < n; i++) { Field f = lFields.get(i); if (f.getName().startsWith("this$")) { lFields.remove(i); lFields.add(0, f); break; } } d.setFields(info, lFields); } // << if (lFields == null) // get _persistenceInfo from field and/or dynamic field IF1 piGetter = d.persistenceInfo.get(c); Map persistenceInfo = piGetter == null ? null : piGetter.get(o); if (piGetter == null && o instanceof DynamicObject) persistenceInfo = (Map) getOptDynOnly(((DynamicObject) o), "_persistenceInfo"); LinkedHashMap fv = new LinkedHashMap(); Object defaultInstance = info.emptyInstance; if (!referencable) throw fail("Not referencable: " + className(o)); for (Field f : lFields) { Object value, defaultValue = null; try { value = f.get(o); defaultValue = defaultInstance == null ? null : f.get(defaultInstance); } catch (Exception e) { value = "?"; } if (!eq(defaultValue, value) && (persistenceInfo == null || !Boolean.FALSE.equals(persistenceInfo.get(f.getName())))) fv.put(f.getName(), value); } String shortName = info.shortName; // Now we have fields & values. Process fieldValues if it's a DynamicObject. Object classNameFromFV = fv.get("className"); // omit field "className" if equal to class's name if (concept && eq(classNameFromFV, shortName)) fv.remove("className"); if (o instanceof DynamicObject) { putAll(fv, (Map) fv.get("fieldValues")); fv.remove("fieldValues"); if (((DynamicObject) o).className != null) { // TODO: this probably doesn't work with inner classes shortName = shortDynClassNameForStructure((DynamicObject) o); fv.remove("className"); // special handling for missing Class objects encoded as DynamicObject if (eq(shortName, "java.lang.Class")) { d.append("class("); d.append(quoted(fv.get("name"))); d.append(")"); return; } } } d.writeObject(o, shortName, fv); } catch (Exception __e) { throw rethrow(__e); } } // TODO: optimize // also doesn't seem to work yet static List tok_processDontImports(List tok, NavigableSet defs) { print("tok_processDontImports"); String prefix = "dontImport_"; List names = new ArrayList(); for (String def : startingWithIC_navigableSubSet(prefix, defs)) { def = dropPrefixIC(prefix, def); String cl = replace(def, "$$", "."); names.add(cl); boolean change = jreplace(tok, "import " + cl + ";", "") | jreplace(tok, "import static " + cl + ";", ""); printVars("tok_processDontImports", "def", def, "cl", cl, "change", change); } return names; } static String afterLastDot(String s) { return s == null ? null : substring(s, s.lastIndexOf('.')+1); } static String unquote_relaxedMLS(String s) { if (s == null) return null; if (startsWith(s, '[')) { int i = 1; while (i < s.length() && s.charAt(i) == '=') ++i; if (i < s.length() && s.charAt(i) == '[') { String m = s.substring(1, i); int n = s.length(); if (s.endsWith("]" + m + "]")) n -= i+1; return s.substring(i+1, n); } } return unquoteSingleOrDoubleQuotes(s); } static void tokSet_reTok(List tok, int i, String t) { tokSet_withReTok(tok, i, t); } static int getAndInc(AtomicInteger i) { return i.getAndIncrement(); } static Map runTranslatorQuick_cache = new HashMap(); static synchronized String runTranslatorQuick(String text, String translatorID) { translatorID = formatSnippetID(translatorID); Class c = runTranslatorQuick_cache.get(translatorID); print("runTranslatorQuick " + programID() + " " + identityHashCode(main.class) + " CACHE " + identityHashCode(runTranslatorQuick_cache) + " " + structure(runTranslatorQuick_cache.keySet()) + " " + (c != null ? "CACHED" : "LOAD") + ": " + translatorID); if (c == null) { //printStackTrace(); c = hotwire(translatorID); print("runTranslatorQuick " + programID() + " " + identityHashCode(main.class) + " CACHE " + identityHashCode(runTranslatorQuick_cache) + " " + structure(runTranslatorQuick_cache.keySet()) + " STORE: " + translatorID + " " + identityHashCode(c)); runTranslatorQuick_cache.put(translatorID, c); } set(c, "mainJava", text); callMain(c); return (String) get(c, "mainJava"); } static List runTranslatorQuick(List tok, String translatorID) { return javaTok(runTranslatorQuick(join(tok), translatorID)); } static ArrayList litlist(A... a) { ArrayList l = new ArrayList(a.length); for (A x : a) l.add(x); return l; } static Set> _entrySet(Map map) { return map == null ? Collections.EMPTY_SET : map.entrySet(); } static Map javaxClassShortcuts_cache; static Map javaxClassShortcuts() { if (javaxClassShortcuts_cache == null) javaxClassShortcuts_cache = javaxClassShortcuts_load(); return javaxClassShortcuts_cache;} static Map javaxClassShortcuts_load() { return litmap( "O", "Object", "S", "String", "L", "List", "Cl", "Collection", "Int", "Integer"); } static boolean neqGetOneOf(List l, int i, A... options) { return !eqGetOneOf(l, i, options); } static void tok_selfNestedType(List tok, String nestedName, String simpleName, boolean legacy) { jreplace(tok, nestedName + "< >", (simpleName + "<" + simpleName + "<$3>>")); jreplace(tok, nestedName + "< <> >", (simpleName + "<" + simpleName + "<$3<$5>>>")); jreplace(tok, nestedName + "", (simpleName + "<" + simpleName + ">")); jreplace(tok, nestedName, legacy ? (simpleName + "<" + simpleName + ">") : (simpleName + "<" + simpleName + ">")); } // finds static imports too static List tok_findImports(List tok) { List imports = new ArrayList(); int n = l(tok); for (int i = 1; i < n; i += 2) if (eq(tok.get(i), "import")) { int j = indexOf(tok, ";", i+2); if (j < 0) break; imports.add(joinCodeTokens(subList(tok, i-1, j))); i = j; } return imports; } static List standardImports_cache; static List standardImports() { if (standardImports_cache == null) standardImports_cache = standardImports_load(); return standardImports_cache;} static List standardImports_load() { return ll( "java.util.*", "java.util.zip.*", "java.util.List", "java.util.regex.*", "java.util.concurrent.*", "java.util.concurrent.atomic.*", "java.util.concurrent.locks.*", "java.util.function.*", "javax.swing.*", "javax.swing.event.*", "javax.swing.text.*", "javax.swing.table.*", "java.io.*", "java.net.*", "java.lang.reflect.*", "java.lang.ref.*", "java.lang.management.*", "java.security.*", "java.security.spec.*", "java.awt.*", "java.awt.event.*", "java.awt.image.*", "java.awt.geom.*", "javax.imageio.*", "java.math.*", "java.time.Duration", "java.lang.invoke.VarHandle", "java.lang.invoke.MethodHandles" ); } static Class include(String progID) { Class c = hotwire(progID); setOpt(c, "programID", getProgramID()); return c; } static long parseLong(String s) { if (empty(s)) return 0; return Long.parseLong(dropSuffix("L", s)); } static long parseLong(Object s) { return Long.parseLong((String) s); } static List findInnerClassOfMain(List tok, String className) { for (List c : innerClassesOfMain(tok)) { String name = getClassDeclarationName(c); if (eq(name, className)) return c; } return null; } static int indexOfSubList(List x, List y) { return indexOfSubList(x, y, 0); } static int indexOfSubList(List x, List y, int i) { outer: for (; i+l(y) <= l(x); i++) { for (int j = 0; j < l(y); j++) if (neq(x.get(i+j), y.get(j))) continue outer; return i; } return -1; } static int indexOfSubList(List x, A[] y, int i) { outer: for (; i+l(y) <= l(x); i++) { for (int j = 0; j < l(y); j++) if (neq(x.get(i+j), y[j])) continue outer; return i; } return -1; } static void doubleReTok(List tok, int i1, int j1, int i2, int j2) { if (i1 > i2) { int i = i1, j = j1; i1 = i2; j1 = j2; i2 = i; j2 = j; } if (j1 > i2) { reTok(tok); return; } reTok(tok, i2, j2); reTok(tok, i1, j1); } static String dropPrefixTrim(String prefix, String s) { return trim(dropPrefix(prefix, s)); } static void clearAllTokens(List tok) { for (int i = 0; i < tok.size(); i++) tok.set(i, ""); } static void clearAllTokens(List tok, int i, int j) { for (; i < j; i++) tok.set(i, ""); } static int countChar(String s, char c) { int n = 0, l = l(s), i = 0; while (true) { int j = s.indexOf(c, i); if (j < 0) break; ++n; i = j+1; } return n; } static void tok_autosemi(List tok) { int i; while ( (i = jfind(tok, "autosemi {")) >= 0 || (i = jfind(tok, "semiauto {")) >= 0) { int closing = findEndOfBlock(tok, i+2)-1; tok.set(i, ""); // remove autosemi keyword tok.set(i+1, ""); for (int j = i+5; j < closing; j += 2) if (containsNewLine(tok.get(j)) && neqOneOf(tok.get(j-1), "{", "}", ";")) tok.set(j-1, tok.get(j-1) + ";"); reTok(tok, i, closing); } } static String tok_autoCloseBrackets(String s) { return join(tok_autoCloseBrackets(javaTok(s))); } // modifies tok static List tok_autoCloseBrackets(List tok) { bigloop: for (int i = 1; i < l(tok); i += 2) { if (eq(tok.get(i), ";")) { int j, level = 0; for (j = i-2; j >= 0; j -= 2) { String t = tok.get(j); if (eqOneOf(t, ";", "{")) break; if (eq(t, "}")) break; // TODO: skip over until other end of bracket else if (eq(t, ")")) --level; else if (eq(t, "(")) { if (eq(get(tok, j-2), "for")) break; if (eq(get(tok, j-4), "for")) break; // for ping ++level; } } while (level-- > 0) { tok.add(i++, ")"); tok.add(i++, ""); } } } return tok; } static boolean jreplace_check(String checkToken, List tok, String in, String out) { if (isIndexedList(tok) && !tok.contains(checkToken)) return false; return jreplace(tok, in, out); } static void tok_mutatorMethods(List tok) { replaceKeywordBlock(tok, "mutator", "{ try { ", "} finally { _change(); } }"); } static Map tok_toNonPrimitiveTypes_map = mapFromTokens("\r\n int Int\r\n byte Byte\r\n float Float\r\n short Short\r\n double Double\r\n long Long\r\n char Character\r\n bool Bool\r\n boolean Bool\r\n"); static String tok_toNonPrimitiveTypes(String s) { return join(tok_toNonPrimitiveTypes(javaTok(s))); } static List tok_toNonPrimitiveTypes(List tok) { for (int i = 1; i < l(tok); i += 2) { String t = tok.get(i); t = tok_toNonPrimitiveTypes_map.get(t); if (t != null && neq(get(tok, i+2), "[")) tok.set(i, t); } return tok; } static List cloneSubList(List l, int startIndex, int endIndex) { return newSubList(l, startIndex, endIndex); } static List cloneSubList(List l, int startIndex) { return newSubList(l, startIndex); } static List tok_typesOfParams(List tok) { try { List types = new ArrayList(); for (int i = 1; i < l(tok); ) { String t = tok.get(i); if (eqOneOf(t, "final")) t = get(tok, i += 2); assertTrue(isIdentifier(t)); i += 2; String type = t; if (eq(t, "virtual")) { type += " " + tok.get(i); i += 2; } while (eq(get(tok, i), ".") && isIdentifier(get(tok, i+2))) { type += "." + get(tok, i+2); i += 4; } // ... if (eqGet(tok, i, ".") && eqGet(tok, i+2, ".") && eqGet(tok, i+2, ".")) { type += "[]"; i += 6; } // just a parameter name, no type if (eqOneOf(get(tok, i), null, ",")) t = null; else { if (eq(tok.get(i), "<")) { int j = findEndOfTypeArgs(tok, i)-1; while (eq(get(tok, j), "[") && eq(get(tok, j+2), "]")) j += 4; type += trimJoinSubList(tok, i, j+1); String id = assertIdentifier(tok.get(j+2)); i = j+2; } while (eq(get(tok, i), "[") && eq(get(tok, i+2), "]")) { i += 4; type += "[]"; } String id = assertIdentifier(tok.get(i)); i += 2; while (eq(get(tok, i), "[") && eq(get(tok, i+2), "]")) { i += 4; type += "[]"; } if (i < l(tok)) { assertEquals(get(tok, i), ","); i += 2; } } types.add(type); } return types; } catch (Throwable e) { print("Bad parameter declaration: " + join(tok)); throw rethrow(e); } } static List tok_typesOfParams(String s) { return tok_typesOfParams(javaTok(s)); } static String joinWithComma(Iterable c) { return join(", ", c); } static String joinWithComma(Object... c) { return join(", ", c); } static String joinWithComma(String... c) { return join(", ", c); } static String joinWithComma(Pair p) { return p == null ? "" : joinWithComma(str(p.a), str(p.b)); } // optionally convert expression to return statement static String tok_addReturn(List tok) { if (tok_shouldAddReturn(tok)) { tokPrepend(tok, 1, "return "); tokAppend(tok, l(tok)-2, ";"); } return join(tok); } static String tok_addReturn(String s) { return tok_addReturn(javaTok(s)); } static boolean jcontains(String s, String pat) { return jfind(s, pat) >= 0; } static boolean jcontains(List tok, String pat) { return jfind(tok, pat) >= 0; } static boolean jcontains(List tok, String pat, Object condition) { return jfind(tok, pat, condition) >= 0; } static String trim(String s) { return s == null ? null : s.trim(); } static String trim(StringBuilder buf) { return buf.toString().trim(); } static String trim(StringBuffer buf) { return buf.toString().trim(); } static void tok_qFunctions(List tok) { tok_qFunctions(tok, "q", "dm_q"); tok_qFunctions(tok, "runInQAndWait", "dm_runInQAndWait"); } static void tok_qFunctions(List tok, String keyword, String function) { int i; while ((i = jfind_check(keyword, tok, "void " + keyword + " {")) >= 0) { int bracket = findCodeTokens(tok, i, false, "{"); int j = findEndOfBracketPart(tok, bracket); clearTokens(tok, i+4, i+6); tok.set(bracket, "{ " + function + "(module(), r {"); tok.set(j-1, "}); }"); reTok(tok, i+4, j); } while ((i = jfind_check(keyword, tok, ") " + keyword + " {")) >= 0) { int opening = findBeginningOfBracketPart(tok, i); String fname = assertIdentifier(get(tok, opening-2)); int bracket = findCodeTokens(tok, i, false, "{"); int j = findEndOfBracketPart(tok, bracket); clearTokens(tok, i+2, i+4); tok.set(bracket, "{ " + function + "(module(), r {"); tok.set(j-1, "}); }"); reTok(tok, i+4, j); tok_makeArgumentsFinal(tok, opening, i); } } static String lastJavaToken(String s) { return last(javaTokC(s)); } static String dropLastJavaTokenAndSpacing(String s) { return join(dropLast(3, javaTok(s))); } // i must point at the (possibly imaginary) opening bracket ("{") // index returned is index of closing bracket + 1 (or l(tok)) static int findEndOfBlock(List tok, int i) { return tok_findEndOfBlock(tok, i); } static boolean tok_tokenLeftOfExpression(List tok, int i) { return eqGetOneOf(tok, i, "(", "=", ",") || isIdentifier(get(tok, i)); } static boolean isBracketHygienic(String s) { return testBracketHygiene(s); } static boolean isBracketHygienic(String s, String op, String close, Var msg) { return testBracketHygiene(s, op, close, msg); } static boolean isBracketHygienic(String s, String op, String close) { return testBracketHygiene(s, op, close, null); } static void assertTrue(Object o) { if (!(eq(o, true) /*|| isTrue(pcallF(o))*/)) throw fail(str(o)); } static boolean assertTrue(String msg, boolean b) { if (!b) throw fail(msg); return b; } static boolean assertTrue(boolean b) { if (!b) throw fail("oops"); return b; } static boolean assertTrue(Scorer scorer, boolean b) { scorer.add(b); return b; } static List concatLists(Iterable... lists) { List l = new ArrayList(); if (lists != null) for (Iterable list : lists) addAll(l, list); return l; } static List concatLists(Collection> lists) { List l = new ArrayList(); if (lists != null) for (Iterable list : lists) addAll(l, list); return l; } static Object loadVariableDefinition(String varName) { return loadVariableDefinition(getProgramID(), varName); } // currently works with string lists ("= litlist(...)"), // strings, longs and ints. static Object loadVariableDefinition(String progIDOrSrc, String varName) { if (isSnippetID(progIDOrSrc)) progIDOrSrc = loadSnippet(progIDOrSrc); return loadVariableDefinition(progIDOrSrc, javaTok(progIDOrSrc), varName); } static Object loadVariableDefinition(String src, List tok, String varName) { int i = findCodeTokens(tok, varName, "="); if (i < 0) return null; i += 4; String t = tok.get(i); if (isQuoted(t)) return unquote(t); if (isLongConstant(t)) return parseLong(t); if (isInteger(t)) return parseInt(t); if (eqOneOf(t, "litlist", "ll") && eq(get(tok, i+2), "(")) { int opening = i+2; int closing = findEndOfBracketPart(tok, opening)-1; List l = new ArrayList(); for (i = opening+2; i < closing; i += 4) l.add(unquote(tok.get(i))); return l; } throw fail("Unknown variable type or no definition in source: " + shorten(src, 100) + "/" + varName); } static Map combinedMap(Map... maps) { return new CombinedMap(wrapAsList(maps)); } static > Map combinedMap(Collection maps) { return l(maps) == 1 ? first(maps) : new CombinedMap(maps); } static void clearTokens_reTok(List tok, int i, int j) { clearTokens(tok, i, j); reTok(tok, i, j); } static boolean findFunctionInvocations_v2_debug = false; // tok: the code // sf: map of functions (keys) to look for - null to record every function call // hardReferences (out parameter): records every "please include" statement if not null // haveFunctions: functions to skip (or null) // includePossiblyMapLikes: include calls with pre-brackets argument (e.g. map l(...)) // mainClassName: name of program's main class (calls to this class will be skipped) static Set findFunctionInvocations_v2(List tok, Map sf, Collection hardReferences, Set haveFunctions, boolean includePossiblyMapLikes, String mainClassName, IF1 isKnownClassName) { LinkedHashSet l = new LinkedHashSet(); for (int i : jfindAll(tok, "please include functions")) { int j = i + 6; while (licensed()) { String fname = tok.get(j); assertIdentifier("in please include functions section", get(tok, j)); l.add(fname); add(hardReferences, fname); j += 2; if (eqGet(tok, j, ".")) break; while (eqGetOneOf(tok, j, ",", "and")) j += 2; } clearAllTokens(tok.subList(i, j+2)); } for (int i : jfindAll(tok, "please include function *.")) { String fname = tok.get(i+6); l.add(fname); add(hardReferences, fname); clearAllTokens(tok.subList(i, i+10)); } int i, n = tok.size(); boolean result = false; for (i = 1; i+2 < n; i += 2) { String f = tok.get(i); if (!isIdentifier_quick(f)) continue; // main.bla() if (eq(mainClassName, f) && eq(tok.get(i+2), ".") && eqGet(tok, i+4, "<")) { i = findEndOfTypeArgs(tok, i+4)+1; f = tok.get(i); if (!isIdentifier(f)) continue; } // e.g. ... html_findLIs(LS [auto htmlTok] tok) { ... } if (eqGet(tok, i-4, "[") && eqGet(tok, i-2, "auto")) { // ok } else if (eqGet(tok, i-2, ":") && eqGet(tok, i-4, ":") && eqGet(tok, i-6, mainClassName)) { // ok, function reference (main::bla) } else if (eqGet(tok, i+2, "(")) { // ok, normal function invocation } else if (includePossiblyMapLikes && eqGet(tok, i+4, "(") && isIdentifier(get(tok, i+2))) { // ok, mapLike invocation (bla blubb(...)) } else // not an invocation continue; if (!tok_isMethodDeclarationNotSFInvocation(tok, i, mainClassName, isKnownClassName)) { boolean inSF = sf == null || sf.containsKey(f); if (findFunctionInvocations_v2_debug) print("Possible invocation: " + f + ", inSF: " + inSF); if (inSF && !contains(haveFunctions, f) && l.add(f)) if (findFunctionInvocations_v2_debug) print("Found reference to standard function " + f + ": " + lineAroundToken(tok, i)); } } return l; } static IF1 containsKeyPredicate(Map map) { return map == null ? a -> false : a -> map.containsKey(a); } static boolean cic(Collection l, String s) { return containsIgnoreCase(l, s); } static boolean cic(Collection l, Symbol s) { return contains(l, s); } static boolean cic(String[] l, String s) { return containsIgnoreCase(l, s); } static boolean cic(String s, char c) { return containsIgnoreCase(s, c); } static boolean cic(String a, String b) { return containsIgnoreCase(a, b); } static Set setMinusSet(Set l, Collection stuff) { if (empty(stuff)) return l; Set set = asSet(stuff); Set l2 = similarEmptySet(l); for (A a : l) if (!set.contains(a)) l2.add(a); return l2; } static Set setMinusSet(Collection l, Collection stuff) { return setMinusSet(asSet(l), stuff); } static Set setIntersection(Collection a, Collection b) { Set set = similarEmptySet(a); if (nempty(a) && nempty(b)) { Set bSet = asSet(b); for (A x : a) if (bSet.contains(x)) set.add(x); } return set; } static long psI(String snippetID) { return parseSnippetID(snippetID); } static List findFunctionDefsAtCurlyLevel(int curlyLevel, String s) { return findFunctionDefsAtCurlyLevel(curlyLevel, javaTok(s)); } static List findFunctionDefsAtCurlyLevel(int targetCurlyLevel, List tok) { if (tok instanceof IContentsIndexedList2) return findFunctionDefsAtCurlyLevel_indexed(targetCurlyLevel, ((IContentsIndexedList2) tok)); List functions = new ArrayList(); var keywords = findFunctionDefs_keywords(); int n = l(tok); int curlyLevel = 0; BitSet ignore = new BitSet(); for (int i = 1; i < n; i += 2) { if (ignore.get(i)) continue; String t = tok.get(i); // Account for meta-for (don't change curly level) if (eqSubList(tok, i, "meta", "", "-", "", "for")) { var r = tok_findFirstBlock(tok, i); ignore.set(r.start); ignore.set(r.end-1); } curlyLevel += curlyLevel(t); if (curlyLevel == targetCurlyLevel) if (keywords.contains(t)) findFunctionDefs_step(tok, i, functions); } return functions; } static String nParts(long n) { return n2(n, "part"); } static String nParts(Collection l) { return nParts(l(l)); } static String lines(Iterable lines) { return fromLines(lines); } static String lines(Object[] lines) { return fromLines(asList(lines)); } static List lines(String s) { return toLines(s); } // convenience map call static String lines(Iterable l, IF1 f) { return mapToLines(l, f); } static List getAllFutures(Collection> l) { List out = new ArrayList(l(l)); for (Future f : unnull(l)) out.add(getFuture(f)); return out; } static String includeInMainLoaded_magicComment; static List includeInMainLoaded(List tok, String text) { if (includeInMainLoaded_magicComment == null) includeInMainLoaded_magicComment = "/*" + randomID() + "*/"; int i = lastIndexOfStartingWith(tok, includeInMainLoaded_magicComment); if (i > 0) --i; else { print("Finding main class"); List main = findMainClass(tok); if (main == null) { print(join(tok)); throw fail("no main class"); } i = main.lastIndexOf("}"); i += magicIndexOfSubList(tok, main); tok.set(i, "}" + includeInMainLoaded_magicComment); } tok.set(i, "\n" + text + "\n" + tok.get(i)); return includeInMainLoaded_reTok(tok, i, i+1); } static void dontPrint() {} static A dontPrint(String s, A o) { return o; } static A dontPrint(A o) { return o; } // assumes main class is last declared class // returns actual CNC static List findMainClass(List tok) { for (List c : reversedList(allClasses(tok))) { String name = getClassDeclarationName(c); if (eq(name, "main") || name.startsWith("x")) return c; } return findBlock("m {", tok); } static String formatSnippetID(String id) { return "#" + parseSnippetID(id); } static String formatSnippetID(long id) { return "#" + id; } static boolean preferCached = false; static boolean loadSnippet_debug = false; static ThreadLocal loadSnippet_silent = new ThreadLocal(); static ThreadLocal loadSnippet_publicOnly = new ThreadLocal(); static int loadSnippet_timeout = 30000; static String loadSnippet(String snippetID) { try { if (snippetID == null) return null; return loadSnippet(parseSnippetID(snippetID), preferCached); } catch (Exception __e) { throw rethrow(__e); } } static String loadSnippet(String snippetID, boolean preferCached) throws IOException { return loadSnippet(parseSnippetID(snippetID), preferCached); } static IF1 loadSnippet; static String loadSnippet(long snippetID) { return loadSnippet != null ? loadSnippet.get(snippetID) : loadSnippet_base(snippetID); } final static String loadSnippet_fallback(IF1 _f, long snippetID) { return _f != null ? _f.get(snippetID) : loadSnippet_base(snippetID); } static String loadSnippet_base(long snippetID) { try { return loadSnippet(snippetID, preferCached); } catch (Exception __e) { throw rethrow(__e); } } static String loadSnippet(long snippetID, boolean preferCached) throws IOException { if (isLocalSnippetID(snippetID)) return loadLocalSnippet(snippetID); IResourceLoader rl = vm_getResourceLoader(); if (rl != null) return rl.loadSnippet(fsI(snippetID)); return loadSnippet_noResourceLoader(snippetID, preferCached); } static String loadSnippet_noResourceLoader(long snippetID, boolean preferCached) throws IOException { String text; // boss bot (old concept) /*text = getSnippetFromBossBot(snippetID); if (text != null) return text;*/ initSnippetCache(); text = DiskSnippetCache_get(snippetID); if (preferCached && text != null) return text; try { if (loadSnippet_debug && text != null) System.err.println("md5: " + md5(text)); String url = tb_mainServer() + "/getraw.php?id=" + snippetID + "&utf8=1"; if (nempty(text)) url += "&md5=" + md5(text); if (!isTrue(loadSnippet_publicOnly.get())) url += standardCredentials(); String text2 = loadSnippet_loadFromServer(url); boolean same = eq(text2, "==*#*=="); if (loadSnippet_debug) print("loadSnippet: same=" + same); if (!same) text = text2; } catch (RuntimeException e) { e.printStackTrace(); throw new IOException("Snippet #" + snippetID + " not found or not public"); } try { initSnippetCache(); DiskSnippetCache_put(snippetID, text); } catch (IOException e) { System.err.println("Minor warning: Couldn't save snippet to cache (" + DiskSnippetCache_getDir() + ")"); } return text; } static File DiskSnippetCache_dir; public static void initDiskSnippetCache(File dir) { DiskSnippetCache_dir = dir; dir.mkdirs(); } public static synchronized String DiskSnippetCache_get(long snippetID) throws IOException { return loadTextFile(DiskSnippetCache_getFile(snippetID).getPath(), null); } private static File DiskSnippetCache_getFile(long snippetID) { return new File(DiskSnippetCache_dir, "" + snippetID); } public static synchronized void DiskSnippetCache_put(long snippetID, String snippet) throws IOException { saveTextFile(DiskSnippetCache_getFile(snippetID).getPath(), snippet); } public static File DiskSnippetCache_getDir() { return DiskSnippetCache_dir; } public static void initSnippetCache() { if (DiskSnippetCache_dir == null) initDiskSnippetCache(getGlobalCache()); } static String loadSnippet_loadFromServer(String url) { Integer oldTimeout = setThreadLocal(loadPage_forcedTimeout_byThread, loadSnippet_timeout); try { return isTrue(loadSnippet_silent.get()) ? loadPageSilently(url) : loadPage(url); } finally { loadPage_forcedTimeout_byThread.set(oldTimeout); } } static boolean hasUnclosedStringLiterals(String s) { for (String t : javaTokC(s)) if (isUnproperlyQuoted(t)) return true; return false; } static boolean regexpContains(String pat, String s) { return regexpFinds(pat, s); } static boolean regexpContains(Pattern pat, String s) { return regexpFinds(pat, s); } static String unnullForIteration(String s) { return s == null ? "" : s; } static Collection unnullForIteration(Collection l) { return l == null ? immutableEmptyList() : l; } static List unnullForIteration(List l) { return l == null ? immutableEmptyList() : l; } static byte[] unnullForIteration(byte[] l) { return l == null ? emptyByteArray() : l; } static int[] unnullForIteration(int[] l) { return l == null ? emptyIntArray() : l; } static char[] unnullForIteration(char[] l) { return l == null ? emptyCharArray() : l; } static double[] unnullForIteration(double[] l) { return l == null ? emptyDoubleArray() : l; } static short[] unnullForIteration(short[] l) { return l == null ? emptyShortArray() : l; } static Map unnullForIteration(Map l) { return l == null ? immutableEmptyMap() : l; } static Iterable unnullForIteration(Iterable i) { return i == null ? immutableEmptyList() : i; } static A[] unnullForIteration(A[] a) { return a == null ? (A[]) emptyObjectArray() : a; } static BitSet unnullForIteration(BitSet b) { return b == null ? new BitSet() : b; } static Pt unnullForIteration(Pt p) { return p == null ? new Pt() : p; } //ifclass Symbol static Symbol unnullForIteration(Symbol s) { return s == null ? emptySymbol() : s; } //endif static Pair unnullForIteration(Pair p) { return p != null ? p : new Pair(null, null); } static long unnullForIteration(Long l) { return l == null ? 0L : l; } static boolean loadSnippets_verbose = false; static List loadSnippets(String... ids) { return loadSnippets(asList(ids)); } static List loadSnippets(List ids) { try { List texts = new ArrayList(); StringBuilder buf = new StringBuilder(); Map cached = new HashMap(); initSnippetCache(); for (String id : ids) { long snippetID = psI(id); String text = DiskSnippetCache_get(snippetID); String md5 = text != null ? md5(text) : "."; if (loadSnippets_verbose) print(id + " => " + md5 + " - " + quote(shorten(text, 20))); mapPut(cached, snippetID, text); buf.append(snippetID).append(" ").append(md5).append(" "); } if (loadSnippets_verbose) print("loadSnippets post data: " + buf); Map map = jsonDecodeMap(doPost( "ids=" + urlencode(trim(str(buf))) + standardCredentials(), tb_mainServer() + "/get-multi2.php")); for (String id : ids) { long snippetID = psI(id); Object result = map.get(str(snippetID)); if (loadSnippets_verbose) print(id + " => " + className(result)); if (result instanceof String) { texts.add((String) result); DiskSnippetCache_put(snippetID, (String) result); } else texts.add(cached.get(snippetID)); } return texts; } catch (Exception __e) { throw rethrow(__e); } } static List> innerClassesOfMain(List tok) { return innerClasses(findMainClass(tok)); } static List> innerClassesOfMain(String src) { return innerClassesOfMain(javaTok(src)); } static String getClassDeclarationName(List tok) { if (tok != null) for (int i = 1; i+2 < tok.size(); i += 2) if (allClasses_keywords.contains(tok.get(i)) && isIdentifier(tok.get(i+2))) { while (contains(getClassDeclarationName_skippables(), get(tok, i+2))) i += 2; return tok.get(i+2); } return null; } // names that don't fit the uppercase-is-class mantra static Map tok_importedClassNames_specialNames = litmap( "_MethodCache" , true, "DynamicObject_loading" , false ); static List tok_importedClassNames(List tok) { return tok_importedClassNames(tok, null); } static List tok_importedClassNames(List tok, IVF2, IntRange> importFound) { List names = new ArrayList(); int n = l(tok); for (int i = 1; i < n; i += 2) if (eq(tok.get(i), "import") /*&& neq(get(tok, i+2), "static")*/) { // static may be OK, e.g. import static x30_pkg.x30_util.VF1; int j = findEndOfStatement(tok, i); // index of ;+1 String s = get(tok, j-3); // This is to distinguish from imported functions; // yes it's rough. if (or(tok_importedClassNames_specialNames.get(s), isIdentifier(s) && startsWithUpperCase(s))) names.add(s); if (importFound != null) { // We assume importFound can change the import statement and also reTok it importFound.get(tok, intRange(i, j)); n = l(tok); } else i = j-1; } return names; } static Set usualJavaClassNames_set = asHashSet(javaTokC("\r\n String Object Map List Integer Long Collection File Component JComponent JButton\r\n JCheckBox Float JTextArea JTextComponent JFrame JPanel JInternalFrame\r\n Number BigInteger Boolean Double Float\r\n")); static Set usualJavaClassNames() { return usualJavaClassNames_set; } static List standardClassesSnippetIDs() { return ll("#1003674", "#1034167"); } static List tlft_j(String text) { return toLinesFullTrim_java(text); } static Set keys(Map map) { return map == null ? new HashSet() : map.keySet(); } // convenience shortcut for keys_gen static Set keys(Object map) { return keys((Map) map); } static Set keys(IMultiMap mm) { return mm.keySet(); } static Set tokenIndexWithoutIfclass_forStdClasses(List tok) { HashSet set = new HashSet(); int n = l(tok); int level = 0; for (int i = 1; i < n; i += 2) { String t = tok.get(i); if (eqOneOf_twoNonNullStrings(t, "ifclass", "ifndef")) ++level; else if (eqOneOf_twoNonNullStrings(t, "endif", "endifndef")) --level; else if (level <= 0 && startsWithJavaIdentifierStart(t) && !eqOneOf_twoNonNullStrings(get(tok, i-2), ".", "virtual")) set.add(t); } return set; } static boolean removeAll(Collection a, Collection b) { return a != null && b != null && a.removeAll(b); } static void removeAll(Map a, Collection b) { if (a != null && b != null) for (A x : b) a.remove(x); } static boolean removeAll(Collection c, B... b) { return c != null && b != null && c.removeAll(Arrays.asList(b)); } static void removeAll(Map a, A... b) { if (a != null && b != null) for (A x : b) a.remove(x); } static Collection values(Map map) { return map == null ? emptyList() : map.values(); } // convenience shortcut for values_gen static Collection values(Object map) { return values((Map) map); } static Collection values(MultiMap mm) { return mm == null ? emptyList() : concatLists(values(mm.data)); } static String joinWithSpace(Iterable c) { return join(" ", c); } static String joinWithSpace(Object... c) { return join(" ", c); } static String md5(String text) { try { if (text == null) return "-"; return bytesToHex(md5AsByteArray(toUtf8(text))); // maybe different than the way PHP does it... } catch (Exception __e) { throw rethrow(__e); } } static String md5(byte[] data) { if (data == null) return "-"; return bytesToHex(md5AsByteArray(data)); } static String md5(File file) { return md5OfFile(file); } static Pair pair(A a, B b) { return new Pair(a, b); } static Pair pair(A a) { return new Pair(a, a); } static HashSet allClasses_keywords = lithashset("class", "interface", "enum", "sclass", "sinterface", "record", "srecord", "strecord", "asclass", "concept"); // lists returned are actual CNC (N/C/N/.../C/N) - and connected to // original list // only returns the top level classes static List> allClasses(List tok) { List> l = new ArrayList(); int n = tok.size(); HashSet _allClasses_keywords = allClasses_keywords; for (int i = 1; i < n; i += 2) { String t = tok.get(i); if ("{".equals(t)) // skip functions i = findEndOfBlock(tok, i)-1; else if (_allClasses_keywords.contains(t) && (tok_isJavaxMetaCommandLeftOf(tok, i) || !(eqGetOneOf(tok, i-2, ".", "include") && !containsNewLine(tok.get(i-1))))) { int j = i; while (j < n && !tok.get(j).equals("{")) j += 2; j = findEndOfBlock(tok, j)+1; i = leftScanModifiers(tok, i); l.add(subList(tok, i-1, Math.min(n, j))); i = j-2; } } return l; } static List> allClasses(String text) { return allClasses(javaTok(text)); } // i = index of "implements"/"extends" static int tok_endOfImplementsList(List tok, int i) { int level = 0; while (i < l(tok)) { String t = tok.get(i); if (eq(t, "<")) ++level; else if (eq(t, ">")) { if (level == 0) return i; else --level; } else if (eq(t, "{")) return i; i += 2; } return i; } static IntRange intRange(int start, int end) { return new IntRange(start, end); } static List reTok_multi(List tok, List places) { if (empty(places)) return tok; if (l(places) == 1) return reTok(tok, first(places)); List orig = cloneList(tok); // copy to orig // sort, extend & merge ranges sortIntRangesInPlace(places); List places2 = new ArrayList(); for (IntRange p : places) { p = intRange(p.start & ~1, p.end | 1); // extend to N-to-N if (nempty(places2) && p.start <= last(places2).end) last(places2).end = p.end; // merge if overlapping else places2.add(p); } int iPlace = 0, n = l(orig); IntRange p = get(places2, iPlace); int next = p.start, i = next; tok.subList(next, tok.size()).clear(); while (i < n) if (i < next) tok.add(orig.get(i++)); else { int j = p.end; String s = joinSubList(orig, i, j); tok.addAll(javaTok(s)); i = j; p = get(places2, ++iPlace); if (p == null) break; next = p.start; } while (i < n) tok.add(orig.get(i++)); return tok; } static List jfindAll(List tok, String pat) { return jfindAll(tok, pat, null); } static List jfindAll(List tok, String pat, ITokCondition condition) { return jfindAll(tok, jfind_preprocess(javaTok(pat)), condition); } // tokPat must be jfind_preprocess'd static List jfindAll(List tok, List tokPat) { return jfindAll(tok, tokPat, null); } static List jfindAll(List tok, List tokPat, ITokCondition condition) { TokCondition cond = toTokCondition(condition); String[] toks = toStringArray(codeTokensOnly(tokPat)); int i = -1; List l = new ArrayList(); while ((i = findCodeTokens(tok, i+1, false, toks, cond)) >= 0) l.add(i); return l; } static boolean contains(Collection c, Object o) { return c != null && c.contains(o); } static boolean contains(Iterable it, Object a) { if (it != null) for (Object o : it) if (eq(a, o)) return true; return false; } static boolean contains(Object[] x, Object o) { if (x != null) for (Object a : x) if (eq(a, o)) return true; return false; } static boolean contains(String s, char c) { return s != null && s.indexOf(c) >= 0; } static boolean contains(String s, String b) { return s != null && s.indexOf(b) >= 0; } static boolean contains(BitSet bs, int i) { return bs != null && bs.get(i); } static boolean contains(Producer p, A a) { if (p != null && a != null) while (true) { A x = p.next(); if (x == null) break; if (eq(x, a)) return true; } return false; } static boolean contains(Rect r, Pt p) { return rectContains(r, p); } static A last(List l) { return empty(l) ? null : l.get(l.size()-1); } static char last(String s) { return empty(s) ? '#' : s.charAt(l(s)-1); } static byte last(byte[] a) { return l(a) != 0 ? a[l(a)-1] : 0; } static int last(int[] a) { return l(a) != 0 ? a[l(a)-1] : 0; } static long last(long[] a) { return l(a) != 0 ? a[l(a)-1] : 0; } static double last(double[] a) { return l(a) != 0 ? a[l(a)-1] : 0; } static A last(A[] a) { return l(a) != 0 ? a[l(a)-1] : null; } static A last(Iterator it) { A a = null; while (it.hasNext()) { ping(); a = it.next(); } return a; } static A last(Collection l) { if (l == null) return null; if (l instanceof List) return (A) last((List) l); if (l instanceof SortedSet) return (A) last((SortedSet) l); Iterator it = iterator(l); A a = null; while (it.hasNext()) { ping(); a = it.next(); } return a; } static A last(SortedSet l) { return l == null ? null : l.last(); } static A last(ReverseChain l) { return l == null ? null : l.element; } static A last(CompactLinkedHashSet set) { return set == null ? null : set.last(); } static int jfindOneOf_cond(List tok, Object condition, String... patterns) { for (String in : patterns) { int i = jfind(tok, in, condition); if (i >= 0) return i; } return -1; } static String joinQuoted(String sep, Collection c) { List l = new ArrayList(); for (String s : c) l.add(quote(s)); return join(sep, l); } // returns number of changes static int tok_conditionals(List tok, String keyword, String keywordEnd, IF1 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))) { tok_conditionals_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 + " ")) >= 0) { ++changes; tok_conditionals_processConditional(tok, i, keyword, keywordEnd, pred, reTokImmediately && !noReTok); } } if (changes != 0 && !reTokImmediately && !noReTok) reTok(tok); //print(keyword + ": " + nChanges(changes)); return changes; } static void tok_conditionals_processConditional(List tok, int i, String keyword, String keywordEnd, IF1 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 } // returns l(s) if not found static int smartIndexOf(String s, String sub, int i) { if (s == null) return 0; i = s.indexOf(sub, min(i, l(s))); return i >= 0 ? i : l(s); } static int smartIndexOf(String s, int i, char c) { return smartIndexOf(s, c, i); } static int smartIndexOf(String s, char c, int i) { if (s == null) return 0; i = s.indexOf(c, min(i, l(s))); return i >= 0 ? i : l(s); } static int smartIndexOf(String s, String sub) { return smartIndexOf(s, sub, 0); } static int smartIndexOf(String s, char c) { return smartIndexOf(s, c, 0); } static int smartIndexOf(List l, A sub) { return smartIndexOf(l, sub, 0); } static int smartIndexOf(List l, int start, A sub) { return smartIndexOf(l, sub, start); } static int smartIndexOf(List l, A sub, int start) { int i = indexOf(l, sub, start); return i < 0 ? l(l) : i; } static void mapPut(Map map, A key, B value) { if (map != null && key != null && value != null) map.put(key, value); } static void mapPut(Map map, Pair p) { if (map != null && p != null) map.put(p.a, p.b); } static boolean mapPut_trueIfChanged(Map map, A key, B value) { if (map != null && key != null && value != null) if (eq(map.get(key), value)) return false; else { map.put(key, value); return true; } return false; } static String quoted(Object o) { return quote(o); } static String quoted(String s) { return quote(s); } static void tok_addFieldOrder(List tok, int i) { int idx = findCodeTokens(tok, i, false, "{"); if (idx < 0) return; int j = findEndOfBracketPart(tok, idx); List vars = allVarNames(subList(tok, idx+1, j-1)); //print("addFieldOrder " + struct(vars)); if (nempty(vars) && !vars.contains("_fieldOrder") && !isSortedList(vars)) { //print("Adding field order"); tok.set(idx+2, "static final String _fieldOrder = " + quote(join(" ", vars)) + ";\n " + tok.get(idx+2)); // reTok has to be done by caller } } static int smartIndexOfOneOf(List l, int i, A... x) { return smartIndexOfAny(l, i, x); } static int smartIndexOfOneOf(List l, A... x) { return smartIndexOfAny(l, x); } static void vmKeepWithProgramMD5_save(String varName) { if (vmExiting()) return; String struct = struct(getOpt(mc(), varName)); callOpt(javax(), "vmKeep_store", programID(), md5OfMyJavaSource(), varName, struct(getOpt(mc(), varName))); } static Pair testBracketHygiene2(String s) { return testBracketHygiene2(s, testBracketHygiene_op, testBracketHygiene_close); } static Pair testBracketHygiene2(String s, String op, String close) { List tok = javaTok(s); Map map = new HashMap(); List stack = getBracketMap2(tok, map, op, close); for (int i = 1; i < l(tok); i += 2) if (isUnproperlyQuoted(tok.get(i))) { int lineNr = tokenIndexToUserLandLineNr(tok, i); return pair(tokenToCharIndex(tok, i), "Unclosed string literal at line " + lineNr); } for (int i : keys(map)) { int j = map.get(i); String a = tok.get(i), b = tok.get(j); int ai = op.indexOf(a), bi = close.indexOf(b); if (ai != bi) { int lineNr1 = tokenIndexToUserLandLineNr(tok, i); int lineNr2 = tokenIndexToUserLandLineNr(tok, j); String msg; if (empty(a)) msg = "superfluous closing bracket (" + quote(b) + ") at line " + lineNr2; else msg = "brackets don't match (" + quote(a) + " vs " + quote(b) + ") at lines " + lineNr1 + " and " + lineNr2; return pair(tokenToCharIndex(tok, /*tossCoin() ?*/ i /*: j*/), "Bad hygiene - " + msg); } } if (nempty(stack)) { int lineNr = tokenIndexToUserLandLineNr(tok, last(stack)); return pair(tokenIndexToCharIndex(tok, last(stack)), "Line " + lineNr + ": " + "Bad hygiene - " + n(l(stack), "bracket") + " not closed"); } if (map.containsKey(0)) { int lineNr = tokenIndexToUserLandLineNr(tok, map.get(0)); return pair(tokenToCharIndex(tok, map.get(0)), "Bad hygiene - bracket not opened (" + quote(tok.get(map.get(0))) + ") at line " + lineNr); } return null; } static void clearTokensAndReTok(List tok, int i, int j) { clearTokens_reTok(tok, i, j); } static boolean subListEquals(List l, List pat, int i) { if (i < 0) return false; int j = i+l(pat); if (j > l(l)) return false; for (int k = i; k < j; k++) if (!eq(l.get(k), pat.get(k-i))) return false; return true; } static boolean subListEquals(List l, int i, A... pat) { return subListEquals(l, asVirtualList(pat), i); } static A printIf(boolean b, A a) { if (b) print(a); return a; } static A printIf(boolean b, String s, A a) { if (b) print(s, a); return a; } static String unquote(String s) { if (s == null) return null; if (startsWith(s, '[')) { int i = 1; while (i < s.length() && s.charAt(i) == '=') ++i; if (i < s.length() && s.charAt(i) == '[') { String m = s.substring(1, i); if (s.endsWith("]" + m + "]")) return s.substring(i+1, s.length()-i-1); } } return unquoteSingleOrDoubleQuotes(s); } static IntRange combineIntRanges(IntRange a, IntRange b) { if (a == null) return b; if (b == null) return a; return intRange(min(a.start, b.start), max(a.end, b.end)); } static void replaceTokens_reTokLater(List tok, List reToks, int i, int j, String text) { if (j <= i) return; replaceTokens(tok, i, j, text); reToks.add(intRange(i, j)); } static String standardFunctionSnippet(String sfName) { return lookupStandardFunction(sfName); } static String assertIdentifier(String s) { return assertIsIdentifier(s); } static String assertIdentifier(String msg, String s) { return assertIsIdentifier(msg, s); } static Object call(Object o) { return callF(o); } // varargs assignment fixer for a single string array argument static Object call(Object o, String method, String[] arg) { return call(o, method, new Object[] {arg}); } static Object call(Object o, String method, Object... args) { //ret call_cached(o, method, args); return call_withVarargs(o, method, args); } static TreeMap hotwireCached_cache = new TreeMap(); static Lock hotwireCached_lock = lock(); static Class hotwireCached(String programID) { return hotwireCached(programID, true); } static Class hotwireCached(String programID, boolean runMain) { return hotwireCached(programID, runMain, false); } static Class hotwireCached(String programID, boolean runMain, boolean dependent) { Lock __0 = hotwireCached_lock; lock(__0); try { programID = formatSnippetID(programID); Class c = hotwireCached_cache.get(programID); if (c == null) { c = hotwire(programID); if (dependent) makeDependent(c); if (runMain) callMain(c); hotwireCached_cache.put(programID, c); } return c; } finally { unlock(__0); } } static void tok_runMetaTransformer(List tok, String transformer) { print("META-TRANSFORM " + transformer); call(hotwireCached(standardFunctionSnippet(assertIdentifier(transformer))), transformer, tok); } static TokenIndexedList3 tokenIndexedList3(List l) { return l instanceof TokenIndexedList3 ? ((TokenIndexedList3) l) : new TokenIndexedList3(l); } static void tok_standardBot1(List tok) { int i; while ((i = jfind(tok, "standardBot1 {")) >= 0) { print("Processing standardBot1"); int iOpening = indexOf(tok, i, "{"); String name = tok.get(iOpening-2); int iClosing = findEndOfBracketPart(tok, iOpening)-1; List contents = subList(tok, iOpening+1, iClosing); String allServers = ""; int j = jfind(contents, "allServers {"); if (j >= 0) { int k = findEndOfBracketPart(contents, j+2); allServers = joinSubList(contents, j+4, k-2); clearTokens(contents, j, k); } String init = ""; j = jfind(contents, "init {"); if (j >= 0) { int k = findEndOfBracketPart(contents, j+2); init = joinSubList(contents, j+4, k-2); clearTokens(contents, j, k); } replaceTokens_reTok(tok, i, iClosing+1, " cmodule2 " + name + " extends DynTalkBot2<" + name + ".ByServer> {\r\n void init {\r\n super.init();\r\n makeByServer = () -> new ByServer;\r\n useAGIBlueForDropPunctuation = false;\r\n preprocessAtSelfToMyName = false;\r\n " + init + "\r\n }\r\n \r\n " + allServers + "\r\n\r\n class ByServer extends DynTalkBot2.ByServer { " + join(contents) + "} }"); } } static void tok_processSimplified(List tok) { replaceKeywordBlock(tok, "processSimplified", "\r\n S processSimplifiedLine(S s, O... _) {\r\n try answer super.processSimplifiedLine(s, _);\r\n new Matches m;\r\n ", " null;\r\n } "); } static void tok_compactModules(List tok) { String latestID = "#1031187"; // cm means "latest version of compact module" jreplace(tok, "cm *", "cmodule2 $2", (_tok, nIdx) -> { String t = _tok.get(nIdx+3); return eqOneOf(t, ">", "{") || isIdentifier(t); }); for (String kw : ll("cprint", "cprint2")) { jreplace(tok, kw + " {", kw + " " + stefansOS_defaultModuleClassName() + " {"); jreplace(tok, kw + " {", "cmodule2 $2 > DynPrintLog {"); } if (jreplace_multi(tok, ll("cmodule", "compact module"), "module")) { print("compact modules"); includeInMainLoaded(tok, "!include once " + latestID + "\n"); } if (jreplace_multi(tok, ll("cmodule2 ", "cmodule2 >", "cmodule2 {"), "module $2")) includeInMainLoaded(tok, "!include once " + latestID + "\n"); } static void tok_metaFor(List tok) { int i; jreplace(tok, "meta-for also as", "meta-for $4 in $4,"); while ((i = jfind_any(tok, "meta-for in", "meta-for as")) >= 0) { int iOpening = indexOf(tok, i, "{"); int iClosing = tok_findEndOfBracketPart(tok, iOpening)-1; int iVar = i+6, iFirstValue = iVar+4; String var = tok.get(iVar); List values = identifiersOnly(subList(tok, iFirstValue, iOpening-1)); List body = subList(tok, iOpening+1, iClosing); tokReplace_reTok(tok, i, iClosing+1, mapToLines(values, value -> join(replaceInClonedList(body, var, value)))); } } static String roundBracket(String s) { return "(" + s + ")"; } static String roundBracket(Object s) { return roundBracket(str(s)); } static Class mc() { return main.class; } static List tok_importedStaticFunctionNamesWithPackages_v2(List tok) { List names = new ArrayList(); for (HasIndex idx : unnullForIteration(indicesOf_collectionOfHasIndex(tok, "import"))) { int i = idx.idx; if (eq(get(tok, i+2), "static")) { int j = findEndOfStatement(tok, i); // index of ;+1 String s = get(tok, j-3); if (isIdentifier(s)) names.add(join(codeTokens(subList(tok, i+3, j-1)))); i = j-1; } } return names; } static int lastIndexOf(String a, String b) { return a == null || b == null ? -1 : a.lastIndexOf(b); } static int lastIndexOf(String a, char b) { return a == null ? -1 : a.lastIndexOf(b); } // starts searching from i-1 static int lastIndexOf(List l, int i, A a) { if (l == null) return -1; for (i = min(l(l), i)-1; i >= 0; i--) if (eq(l.get(i), a)) return i; return -1; } static int lastIndexOf(List l, A a) { if (l == null) return -1; for (int i = l(l)-1; i >= 0; i--) if (eq(l.get(i), a)) return i; return -1; } static List takeFirst(List l, int n) { return l(l) <= n ? l : newSubListOrSame(l, 0, n); } static List takeFirst(int n, List l) { return takeFirst(l, n); } static String takeFirst(int n, String s) { return substring(s, 0, n); } static String takeFirst(String s, int n) { return substring(s, 0, n); } static CharSequence takeFirst(int n, CharSequence s) { return subCharSequence(s, 0, n); } static List takeFirst(int n, Iterator it) { if (it == null) return null; List l = new ArrayList(); for (int _repeat_0 = 0; _repeat_0 < n; _repeat_0++) { if (it.hasNext()) l.add(it.next()); else break; } return l; } static List takeFirst(int n, Iterable i) { if (i == null) return null; return i == null ? null : takeFirst(n, i.iterator()); } static List takeFirst(int n, IterableIterator i) { return takeFirst(n, (Iterator) i); } static int[] takeFirst(int n, int[] a) { return takeFirstOfIntArray(n, a); } static short[] takeFirst(int n, short[] a) { return takeFirstOfShortArray(n, a); } static byte[] takeFirst(int n, byte[] a) { return takeFirstOfByteArray(n, a); } static byte[] takeFirst(byte[] a, int n) { return takeFirstOfByteArray(n, a); } static double[] takeFirst(int n, double[] a) { return takeFirstOfDoubleArray(n, a); } static double[] takeFirst(double[] a, int n) { return takeFirstOfDoubleArray(n, a); } static Map takeFirst(int n, Map map) { return takeFirstFromMap(n, map); } static AutoCloseable tempInterceptPrintIfNotIntercepted(F1 f) { return print_byThread().get() == null ? tempInterceptPrint(f) : null; } // not including <> as they are ambiguous (< is also a comparison operator) static String testBracketHygiene_op = "([{"; static String testBracketHygiene_close = ")]}"; static boolean testBracketHygiene(String s) { return testBracketHygiene(s, testBracketHygiene_op, testBracketHygiene_close, null); } static boolean testBracketHygiene(String s, Var msg) { return testBracketHygiene(s, testBracketHygiene_op, testBracketHygiene_close, msg); } static boolean testBracketHygiene(String s, String op, String close, Var msg) { Pair p = testBracketHygiene2(s, op, close); if (p == null) { if (msg != null) msg.set("Hygiene OK!"); return true; } if (msg != null) msg.set(p.b); return false; } static RuntimeException asRuntimeException(Throwable t) { if (t instanceof Error) _handleError((Error) t); return t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t); } static boolean boolOptParam(ThreadLocal tl) { return isTrue(optPar(tl)); } // defaults to false static boolean boolOptParam(Object[] __, String name) { return isTrue(optParam(__, name)); } static boolean boolOptParam(String name, Object[] __) { return boolOptParam(__, name); } static boolean boolOptParam(String name, Map __) { return isTrue(optPar(name, __)); } static boolean isNormalQuoted_dirty(String s) { return startsWith(s, "\"") && endsWith(s, "\"") && l(s) >= 2; } static boolean isMultilineQuoted(String s) { if (!startsWith(s, "[")) return false; int i = 1, n = s.length(); while (i < n && s.charAt(i) == '=') ++i; return i < n && s.charAt(i) == '['; } static boolean isJavaIdentifier(String s) { if (empty(s) || !Character.isJavaIdentifierStart(s.charAt(0))) return false; for (int i = 1; i < s.length(); i++) if (!Character.isJavaIdentifierPart(s.charAt(i))) return false; return true; } static String asString(Object o) { return o == null ? null : o.toString(); } static String combinePrintParameters(String s, Object o) { return (endsWithLetterOrDigit(s) ? s + ": " : s) + o; } static void ping_okInCleanUp() { if (ping_pauseAll || ping_anyActions) ping_impl(true); } static ThreadLocal print_byThread_dontCreate() { return print_byThread; } static boolean isFalse(Object o) { return eq(false, o); } static String getStackTrace(Throwable throwable) { lastException(throwable); return getStackTrace_noRecord(throwable); } static String getStackTrace_noRecord(Throwable throwable) { StringWriter writer = new StringWriter(); throwable.printStackTrace(new PrintWriter(writer)); return hideCredentials(writer.toString()); } static String getStackTrace() { return getStackTrace_noRecord(new Throwable()); } static String getStackTrace(String msg) { return getStackTrace_noRecord(new Throwable(msg)); } static String fixNewLines(String s) { int i = indexOf(s, '\r'); if (i < 0) return s; int l = s.length(); StringBuilder out = new StringBuilder(l); out.append(s, 0, i); for (; i < l; i++) { char c = s.charAt(i); if (c != '\r') out.append(c); else { out.append('\n'); if (i+1 < l && s.charAt(i+1) == '\n') ++i; } } return out.toString(); } static void print_append(Appendable buf, String s, int max) { try { synchronized(buf) { buf.append(s); if (buf instanceof StringBuffer) rotateStringBuffer(((StringBuffer) buf), max); else if (buf instanceof StringBuilder) rotateStringBuilder(((StringBuilder) buf), max); } } catch (Exception __e) { throw rethrow(__e); } } static void vmBus_send(String msg, Object... args) { Object arg = vmBus_wrapArgs(args); pcallFAll_minimalExceptionHandling(vm_busListeners_live(), msg, arg); pcallFAll_minimalExceptionHandling(vm_busListenersByMessage_live().get(msg), msg, arg); } static void vmBus_send(String msg) { vmBus_send(msg, (Object) null); } static boolean checkCondition(Object condition, Object... args) { return isTrue(callF(condition, args)); } static boolean checkCondition(IF1 condition, A arg) { return isTrue(callF(condition, arg)); } static List map(Iterable l, Object f) { return map(f, l); } static List map(Object f, Iterable l) { List x = emptyList(l); if (l != null) for (Object o : l) { ping(); x.add(callF(f, o)); } return x; } // map: func(key, value) -> list element static List map(Map map, Object f) { List x = new ArrayList(); if (map != null) for (Object _e : map.entrySet()) { ping(); Map.Entry e = (Map.Entry) _e; x.add(callF(f, e.getKey(), e.getValue())); } return x; } static List map(Object f, Object[] l) { return map(f, asList(l)); } static List map(Object[] l, Object f) { return map(f, l); } static List map(Object f, Map map) { return map(map, f); } static List map(Iterable l, F1 f) { return map(f, l); } static List map(F1 f, Iterable l) { List x = emptyList(l); if (l != null) for (A o : l) { ping(); x.add(callF(f, o)); } return x; } static List map(IF1 f, Iterable l) { return map(l, f); } static List map(Iterable l, IF1 f) { List x = emptyList(l); if (l != null) { var it = l.iterator(); if (it.hasNext()) { var pingSource = pingSource(); do { ping(pingSource); x.add(f.get(it.next())); } while (it.hasNext()); } } return x; } static List map(IF1 f, A[] l) { return map(l, f); } static List map(A[] l, IF1 f) { List x = emptyList(l); if (l != null) for (A o : l) { ping(); x.add(f.get(o)); } return x; } static List map(Map map, IF2 f) { List x = new ArrayList(); if (map != null) for (Map.Entry e : map.entrySet()) { ping(); x.add(f.get(e.getKey(), e.getValue())); } return x; } // new magic alias for mapLL - does it conflict? static List map(IF1 f, A data1, A... moreData) { List x = emptyList(l(moreData)+1); x.add(f.get(data1)); if (moreData != null) for (A o : moreData) { ping(); x.add(f.get(o)); } return x; } static LinkedHashMap cloneLinkedHashMap(Map map) { return map == null ? new LinkedHashMap() : new LinkedHashMap(map); } static Map synchroHashMap() { return synchronizedMap(new HashMap()); } static Map synchronizedMap() { return synchroMap(); } static Map synchronizedMap(Map map) { return synchroMap(map); } static Map synchronizedMRUCache(int maxSize) { return synchroMap(new MRUCache(maxSize)); } static TreeSet caseInsensitiveSet() { return caseInsensitiveSet_treeSet(); } static TreeSet caseInsensitiveSet(Collection c) { return caseInsensitiveSet_treeSet(c); } static Object callOpt(Object o) { return callF(o); } static Object callOpt(Object o, String method, Object... args) { return callOpt_withVarargs(o, method, args); } static AutoInitVar < String > md5OfMyJavaSource_cache = new AutoInitVar<>(new F0() { public String get() { try { return md5(myJavaSource()); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "return md5(myJavaSource());"; }}); static String md5OfMyJavaSource() { return md5OfMyJavaSource_cache.get(); } static Field setOpt_findField(Class c, String field) { HashMap map; synchronized(getOpt_cache) { map = getOpt_cache.get(c); if (map == null) map = getOpt_makeCache(c); } return map.get(field); } static void setOpt(Object o, String field, Object value) { try { if (o == null) return; Class c = o.getClass(); HashMap map; if (getOpt_cache == null) map = getOpt_makeCache(c); // in class init else synchronized(getOpt_cache) { map = getOpt_cache.get(c); if (map == null) map = getOpt_makeCache(c); } if (map == getOpt_special) { if (o instanceof Class) { setOpt((Class) o, field, value); return; } // It's probably a subclass of Map. Use raw method. TODO: huh? setOpt_raw(o, field, value); return; } Field f = map.get(field); if (f != null) { smartSet(f, o, value); return; } // possible improvement: skip setAccessible if (o instanceof DynamicObject) { setDyn(((DynamicObject) o), field, value); return; } if (o instanceof IMeta) setDyn(((IMeta) o), field, value); } catch (Exception __e) { throw rethrow(__e); } } static void setOpt(Class c, String field, Object value) { if (c == null) return; try { Field f = setOpt_findStaticField(c, field); // TODO: optimize if (f != null) smartSet(f, null, value); } catch (Exception e) { throw new RuntimeException(e); } } static Field setOpt_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) { makeAccessible(f); return f; } _c = _c.getSuperclass(); } while (_c != null); return null; } // TODO: cyclic structures involving certain lists & sets static Object unstructure(String text) { return unstructure(text, false); } static Object unstructure(String text, boolean allDynamic) { return unstructure(text, allDynamic, null); } static Object unstructure(String text, IF1 classFinder) { return unstructure(text, false, classFinder); } static int structure_internStringsLongerThan = 50; static int unstructure_unquoteBufSize = 100; static int unstructure_tokrefs; // stats abstract static class unstructure_Receiver { abstract void set(Object o); } // classFinder: func(name) -> class (optional) static Object unstructure(String text, boolean allDynamic, Object classFinder) { if (text == null) return null; return unstructure_tok(javaTokC_noMLS_iterator(text), allDynamic, classFinder); } static Object unstructure_reader(BufferedReader reader) { return unstructure_tok(javaTokC_noMLS_onReader(reader), false, null); } interface unstructure_Handler { void parse(int refID, int tokIndex, unstructure_Receiver out); } static class Unstructurer { final public Unstructurer setTok(Producer tok){ return tok(tok); } public Unstructurer tok(Producer tok) { this.tok = tok; return this; } final public Producer getTok(){ return tok(); } public Producer tok() { return tok; } Producer tok; final public Unstructurer setAllDynamic(boolean allDynamic){ return allDynamic(allDynamic); } public Unstructurer allDynamic(boolean allDynamic) { this.allDynamic = allDynamic; return this; } final public boolean getAllDynamic(){ return allDynamic(); } public boolean allDynamic() { return allDynamic; } boolean allDynamic = false; int i = -1; Object classFinder; String mcDollar = actualMCDollar(); Unstructurer classFinder(Object _classFinder) { classFinder = _classFinder != null ? _classFinder : _defaultClassFinder(); return this; } // use Eclipse primitive collection if possible (smaller & hopefully faster?) HashMap refs = new HashMap(); HashMap tokrefs = new HashMap(); HashSet concepts = new HashSet(); List stack = new ArrayList(); Map baseClassMap = new HashMap(); HashMap innerClassConstructors = new HashMap(); String curT; char[] unquoteBuf = new char[unstructure_unquoteBufSize]; // value is a class or a Handler final HashMap handlers = new HashMap(); Unstructurer() { try { Class mc = (Class) (callF(classFinder, "
")); if (mc != null) mcDollar = mc.getName() + "$"; } catch (Throwable __e) { pcallFail(__e); } makeHandlers(); } void makeHandlers() { unstructure_Handler h; handlers.put("bigint", (unstructure_Handler) (refID, tokIndex, out) -> out.set(parseBigInt())); handlers.put("d", (unstructure_Handler) (refID, tokIndex, out) -> out.set(parseDouble())); handlers.put("fl", (unstructure_Handler) (refID, tokIndex, out) -> out.set(parseFloat())); handlers.put("sh", (unstructure_Handler) (refID, tokIndex, out) -> { consume(); String t = tpp(); if (t.equals("-")) { t = tpp(); out.set((short) (-parseInt(t))); return; } out.set((short) parseInt(t)); }); handlers.put("enum", (unstructure_Handler) (refID, tokIndex, out) -> { consume(); String t = tpp(); assertTrue(isJavaIdentifier(t)); String fullClassName = mcDollar + t; Class _c = findAClass(fullClassName); if (_c == null) throw fail("Enum class not found: " + fullClassName); int ordinal = parseInt(tpp()); out.set(_c.getEnumConstants()[ordinal]); }); handlers.put("false", h = (unstructure_Handler) (refID, tokIndex, out) -> { consume(); out.set(false); }); handlers.put("f", h); handlers.put("true", h = (unstructure_Handler) (refID, tokIndex, out) -> { consume(); out.set(true); }); handlers.put("t", h); handlers.put("{", (unstructure_Handler) (refID, tokIndex, out) -> parseMap(out)); handlers.put("[", (unstructure_Handler) (refID, tokIndex, out) -> { ArrayList l = new ArrayList(); if (refID >= 0) refs.put(refID, l); this.parseList(l, out); }); handlers.put("bitset", (unstructure_Handler) (refID, tokIndex, out) -> parseBitSet(out)); handlers.put("array", h = (unstructure_Handler) (refID, tokIndex, out) -> parseArray(out)); handlers.put("intarray", h); handlers.put("dblarray", h); handlers.put("floatarray", h); handlers.put("shortarray", (unstructure_Handler) (refID, tokIndex, out) -> { consume(); String hex = trivialUnquote(tpp()); out.set(shortArrayFromBytes(hexToBytes(hex))); }); handlers.put("longarray", (unstructure_Handler) (refID, tokIndex, out) -> { consume(); String hex = trivialUnquote(tpp()); out.set(longArrayFromBytes(hexToBytes(hex))); }); } // end of makeHandlers - add more handlers here Class findAClass(String fullClassName) { try { return classFinder != null ? (Class) callF(classFinder, fullClassName) : findClass_fullName(fullClassName); } catch (Throwable __e) { return null; } } String unquote(String s) { return unquoteUsingCharArray(s, unquoteBuf); } // look at current token String t() { return curT; } // get current token, move to next String tpp() { String t = curT; consume(); return t; } void parse(final unstructure_Receiver out) { String t = t(); int refID; if (structure_isMarker(t, 0, l(t))) { refID = parseInt(t.substring(1)); consume(); } else refID = -1; // if (debug) print("parse: " + quote(t)); final int tokIndex = i; parse_inner(refID, tokIndex, new unstructure_Receiver() { void set(Object o) { if (refID >= 0) refs.put(refID, o); if (o != null) tokrefs.put(tokIndex, o); out.set(o); } }); } void parse_inner(int refID, int tokIndex, unstructure_Receiver out) { String t = t(); // if (debug) print("parse_inner: " + quote(t)); Object handler = handlers.get(t); if (handler instanceof unstructure_Handler) { ((unstructure_Handler) handler).parse(refID, tokIndex, out); return; } Class c = (Class) handler; if (c == null) { if (t.startsWith("\"")) { String s = internIfLongerThan(unquote(tpp()), structure_internStringsLongerThan); out.set(s); return; } if (t.startsWith("'")) { out.set(unquoteCharacter(tpp())); return; } if (t.equals("-")) { consume(); t = tpp(); out.set(isLongConstant(t) ? (Object) (-parseLong(t)) : (Object) (-parseInt(t))); return; } if (isInteger(t) || isLongConstant(t)) { consume(); //if (debug) print("isLongConstant " + quote(t) + " => " + isLongConstant(t)); if (isLongConstant(t)) { out.set(parseLong(t)); return; } long l = parseLong(t); boolean isInt = l == (int) l; out.set(isInt ? (Object) Integer.valueOf((int) l) : (Object) Long.valueOf(l)); return; } if (t.equals("-")) { consume(); t = tpp(); out.set(isLongConstant(t) ? (Object) (-parseLong(t)) : (Object) (-parseInt(t))); return; } if (isInteger(t) || isLongConstant(t)) { consume(); //if (debug) print("isLongConstant " + quote(t) + " => " + isLongConstant(t)); if (isLongConstant(t)) { out.set(parseLong(t)); return; } long l = parseLong(t); boolean isInt = l == (int) l; out.set(isInt ? (Object) Integer.valueOf((int) l) : (Object) Long.valueOf(l)); return; } if (t.equals("File")) { consume(); File f = new File(unquote(tpp())); out.set(f); return; } if (t.startsWith("r") && isInteger(t.substring(1))) { consume(); int ref = Integer.parseInt(t.substring(1)); Object o = refs.get(ref); if (o == null) warn("unsatisfied back reference " + ref); out.set(o); return; } if (t.startsWith("t") && isInteger(t.substring(1))) { consume(); int ref = Integer.parseInt(t.substring(1)); Object o = tokrefs.get(ref); if (o == null) warn("unsatisfied token reference " + ref + " at " + tokIndex); out.set(o); return; } if (t.equals("hashset")) { parseHashSet(out); return; } if (t.equals("lhs")) { parseLinkedHashSet(out); return; } if (t.equals("treeset")) { parseTreeSet(out); return; } if (t.equals("ciset")) { parseCISet(out); return; } if (eqOneOf(t, "hashmap", "hm")) { consume(); parseMap(new HashMap(), out); return; } if (t.equals("lhm")) { consume(); parseMap(new LinkedHashMap(), out); return; } if (t.equals("tm")) { consume(); parseMap(new TreeMap(), out); return; } if (t.equals("cimap")) { consume(); parseMap(ciMap(), out); return; } if (t.equals("ll")) { consume(); LinkedList l = new LinkedList(); if (refID >= 0) refs.put(refID, l); { parseList(l, out); return; } } if (t.equals("syncLL")) { // legacy consume(); { parseList(synchroLinkedList(), out); return; } } if (t.equals("sync")) { consume(); { parse(new unstructure_Receiver() { void set(Object value) { if (value instanceof Map) { // Java 7 if (value instanceof NavigableMap) { out.set(synchroNavigableMap((NavigableMap) value)); return; } if (value instanceof SortedMap) { out.set(synchroSortedMap((SortedMap) value)); return; } { out.set(synchroMap((Map) value)); return; } } else { out.set(synchroList((List) value)); return; } } }); return; } } if (t.equals("ba")) { consume(); String hex = trivialUnquote(tpp()); out.set(hexToBytes(hex)); return; } if (t.equals("boolarray")) { consume(); int n = parseInt(tpp()); String hex = trivialUnquote(tpp()); out.set(boolArrayFromBytes(hexToBytes(hex), n)); return; } if (t.equals("class")) { out.set(parseClass()); return; } if (t.equals("l")) { parseLisp(out); return; } if (t.equals("null")) { consume(); out.set(null); return; } if (eq(t, "c")) { consume(); t = t(); assertTrue(isJavaIdentifier(t)); concepts.add(t); } // custom deserialization (new static method method) if (eq(t, "cu")) { consume(); t = tpp(); assertTrue(isJavaIdentifier(t)); String fullClassName = mcDollar + t; Class _c = findAClass(fullClassName); if (_c == null) throw fail("Class not found: " + fullClassName); parse(new unstructure_Receiver() { void set(Object value) { out.set(call(_c, "_deserialize", value)); } }); return; } } if (eq(t, "j")) { consume(); out.set(parseJava()); return; } if (eq(t, "bc")) { consume(); String c1 = tpp(); String c2 = tpp(); baseClassMap.put(c1, c2); { parse_inner(refID, i, out); return; } } // add more tokens here // Now we want to find our target class c // Have we failed to look up the class before? //bool seenBefore = handlers.containsKey(cname); // If we have seen the class before, we skip all of this // and simply leave c as null // TODO - how do we fill className? //if (!seenBefore) { if (c == null && !isJavaIdentifier(t)) throw new RuntimeException("Unknown token " + (i+1) + ": " + quote(t)); // any other class name (or package name) consume(); String className, fullClassName; // Is it a package name? if (eq(t(), ".")) { className = t; do { consume(); className += "." + assertIdentifier(tpp()); } while (eq(t(), ".")); fullClassName = className; } else { className = t; fullClassName = mcDollar + t; } if (c == null && !allDynamic) { // First, find class c = findAClass(fullClassName); handlers.put(className, c); } // check for existing base class if (c == null && !allDynamic) { Set seen = new HashSet(); String parent = className; while (true) { String baseName = baseClassMap.get(parent); if (baseName == null) break; if (!seen.add(baseName)) throw fail("Cyclic superclass info: " + baseName); c = findAClass(mcDollar + baseName); if (c == null) print("Base class " + baseName + " of " + parent + " doesn't exist either"); else if (isAbstract(c)) print("Can't instantiate abstract base class: " + c); else { printVars_str("Reverting to base class", "className", className, "baseName", baseName, "c", c); handlers.put(className, c); break; } parent = baseName; } } //} // Check if it has an outer reference boolean hasBracket = eq(t(), "("); if (hasBracket) consume(); boolean hasOuter = hasBracket && startsWith(t(), "this$"); DynamicObject dO = null; Object o = null; final String thingName = t; try { if (c != null) { if (hasOuter) try { Constructor ctor = innerClassConstructors.get(c); if (ctor == null) innerClassConstructors.put(c, ctor = nuStubInnerObject_findConstructor(c, classFinder)); o = ctor.newInstance(new Object[] {null}); } catch (Exception e) { print("Error deserializing " + c + ": " + e); o = nuEmptyObject(c); } else o = nuEmptyObject(c); if (o instanceof DynamicObject) dO = (DynamicObject) o; } else { if (concepts.contains(t) && (c = findAClass(mcDollar + "Concept")) != null) o = dO = (DynamicObject) nuEmptyObject(c); else dO = new DynamicObject(); dO.className = className; } } catch (Throwable __e) { pcallFail(__e); } // end of pcall // Creating instance failed? Use DynamicObject if (o == null && dO == null) dO = new DynamicObject(); // Save in references list early because contents of object // might link back to main object if (refID >= 0) refs.put(refID, o != null ? o : dO); tokrefs.put(tokIndex, o != null ? o : dO); // NOW parse the fields! HashMap fields = new HashMap(); // no longer preserving order (why did we do this?) Object _o = o; DynamicObject _dO = dO; if (hasBracket) { stack.add(new Runnable() { public void run() { try { if (eq(t(), ",")) consume(); if (eq(t(), ")")) { consume(")"); objRead(_o, _dO, fields, hasOuter); out.set(_o != null ? _o : _dO); } else { final String key = unquote(tpp()); String t = tpp(); if (!eq(t, "=")) throw fail("= expected, got " + t + " after " + quote(key) + " in object " + thingName /*+ " " + sfu(fields)*/); stack.add(this); parse(new unstructure_Receiver() { void set(Object value) { fields.put(key, value); /*ifdef unstructure_debug print("Got field value " + value + ", next token: " + t()); endifdef*/ //if (eq(t(), ",")) consume(); } }); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "ifdef unstructure_debug\r\n print(\"in object values, token: \" + t());\r..."; }}); } else { objRead(o, dO, fields, hasOuter); out.set(o != null ? o : dO); } } void objRead(Object o, DynamicObject dO, Map fields, boolean hasOuter) { // translate between diferent compilers (this$0 vs this$1) Object outer = fields.get("this$0"); if (outer != null) fields.put("this$1", outer); else { outer = fields.get("this$1"); if (outer != null) fields.put("this$0", outer); } if (o != null) { if (dO != null) { setOptAllDyn_pcall(dO, fields); } else { setOptAll_pcall(o, fields); } if (hasOuter) fixOuterRefs(o); } else for (Map.Entry e : fields.entrySet()) setDynObjectValue(dO, intern(e.getKey()), e.getValue()); if (o != null) pcallOpt_noArgs(o, "_doneLoading"); } void parseSet(final Set set, final unstructure_Receiver out) { this.parseList(new ArrayList(), new unstructure_Receiver() { void set(Object o) { set.addAll((List) o); out.set(set); } }); } void parseLisp(final unstructure_Receiver out) { throw fail("class Lisp not included"); } void parseBitSet(final unstructure_Receiver out) { consume("bitset"); consume("{"); final BitSet bs = new BitSet(); stack.add(new Runnable() { public void run() { try { if (eq(t(), "}")) { consume("}"); out.set(bs); } else { stack.add(this); parse(new unstructure_Receiver() { void set(Object o) { bs.set((Integer) o); if (eq(t(), ",")) consume(); } }); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (eq(t(), \"}\")) {\r\n consume(\"}\");\r\n out.set(bs);\r\n } els..."; }}); } void parseList(final List list, final unstructure_Receiver out) { tokrefs.put(i, list); consume("["); stack.add(new Runnable() { public void run() { try { if (eq(t(), "]")) { consume(); out.set(list); } else { stack.add(this); parse(new unstructure_Receiver() { void set(Object o) { //if (debug) print("List element type: " + getClassName(o)); list.add(o); if (eq(t(), ",")) consume(); } }); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (eq(t(), \"]\")) {\r\n consume();\r\n ifdef unstructure_debug\r\n ..."; }}); } void parseArray(unstructure_Receiver out) { String _type = tpp(); int dims; if (eq(t(), "S")) { // string array _type = "S"; consume(); } if (eq(t(), "/")) { // multi-dimensional array consume(); dims = parseInt(tpp()); } else dims = 1; consume("{"); List list = new ArrayList(); String type = _type; stack.add(new Runnable() { public void run() { try { if (eq(t(), "}")) { consume("}"); if (dims > 1) { Class atype; if (type.equals("intarray")) atype = int.class; else if (type.equals("S")) atype = String.class; else throw todo("multi-dimensional arrays of other types"); out.set(list.toArray((Object[]) newMultiDimensionalOuterArray(atype, dims, l(list)))); } else out.set( type.equals("intarray") ? toIntArray(list) : type.equals("dblarray") ? toDoubleArray(list) : type.equals("floatarray") ? toFloatArray(list) : type.equals("S") ? toStringArray(list) : list.toArray()); } else { stack.add(this); parse(new unstructure_Receiver() { void set(Object o) { list.add(o); if (eq(t(), ",")) consume(); } }); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (eq(t(), \"}\")) {\r\n consume(\"}\");\r\n if (dims > 1) {\r\n ..."; }}); } Object parseClass() { consume("class"); consume("("); String name = unquote(tpp()); consume(")"); Class c = allDynamic ? null : findAClass(name); if (c != null) return c; DynamicObject dO = new DynamicObject(); dO.className = "java.lang.Class"; name = dropPrefix(mcDollar, name); dynamicObject_setRawFieldValue(dO, "name", name); return dO; } Object parseBigInt() { consume("bigint"); consume("("); String val = tpp(); if (eq(val, "-")) val = "-" + tpp(); consume(")"); return new BigInteger(val); } Object parseDouble() { consume("d"); consume("("); String val = unquote(tpp()); consume(")"); return Double.parseDouble(val); } Object parseFloat() { consume("fl"); String val; if (eq(t(), "(")) { consume("("); val = unquote(tpp()); consume(")"); } else { val = unquote(tpp()); } return Float.parseFloat(val); } void parseHashSet(unstructure_Receiver out) { consume("hashset"); parseSet(new HashSet(), out); } void parseLinkedHashSet(unstructure_Receiver out) { consume("lhs"); parseSet(new LinkedHashSet(), out); } void parseTreeSet(unstructure_Receiver out) { consume("treeset"); parseSet(new TreeSet(), out); } void parseCISet(unstructure_Receiver out) { consume("ciset"); parseSet(ciSet(), out); } void parseMap(unstructure_Receiver out) { parseMap(new TreeMap(), out); } Object parseJava() { String j = unquote(tpp()); Matches m = new Matches(); if (jmatch("java.awt.Color[r=*,g=*,b=*]", j, m)) return nuObject("java.awt.Color", parseInt(m.unq(0)), parseInt(m.unq(1)), parseInt(m.unq(2))); else { warn("Unknown Java object: " + j); return null; } } void parseMap(final Map map, final unstructure_Receiver out) { consume("{"); stack.add(new Runnable() { boolean v = false; Object key; public void run() { if (v) { v = false; stack.add(this); if (!eq(tpp(), "=")) throw fail("= expected, got " + t() + " in map of size " + l(map)); parse(new unstructure_Receiver() { void set(Object value) { map.put(key, value); if (eq(t(), ",")) consume(); } }); } else { if (eq(t(), "}")) { consume("}"); out.set(map); } else { v = true; stack.add(this); parse(new unstructure_Receiver() { void set(Object o) { key = o; } }); } } // if v else } // run() }); } /*void parseSub(unstructure_Receiver out) { int n = l(stack); parse(out); while (l(stack) > n) stack }*/ void consume() { curT = tok.next(); ++i; } void consume(String s) { if (!eq(t(), s)) { /*S prevToken = i-1 >= 0 ? tok.get(i-1) : ""; S nextTokens = join(tok.subList(i, Math.min(i+2, tok.size()))); fail(quote(s) + " expected: " + prevToken + " " + nextTokens + " (" + i + "/" + tok.size() + ")");*/ throw fail(quote(s) + " expected, got " + quote(t())); } consume(); } // outer wrapper function getting first token and unwinding the stack void parse_initial(unstructure_Receiver out) { consume(); // get first token parse(out); while (nempty(stack)) popLast(stack).run(); } } static Object unstructure_tok(Producer tok, boolean allDynamic, Object classFinder) { boolean debug = unstructure_debug; AutoCloseable __1 = tempSetTL(dynamicObjectIsLoading_threadLocal(), true); try { Var v = new Var(); var unstructurer = new Unstructurer() .tok(tok) .allDynamic(allDynamic) .classFinder(classFinder); unstructurer.parse_initial(new unstructure_Receiver() { void set(Object o) { v.set(o); } }); unstructure_tokrefs = unstructurer.tokrefs.size(); return v.get(); } finally { _close(__1); }} static boolean unstructure_debug = false; static PCallPolicy pcallPolicyForThread() { var policy = pcallPolicyForThread_tl().get(); if (policy != null) return policy; return defaultPCallPolicy(); } //static final Map> getOpt_cache = newDangerousWeakHashMap(f getOpt_special_init); static class getOpt_Map extends WeakHashMap { getOpt_Map() { if (getOpt_special == null) getOpt_special = new HashMap(); clear(); } public void clear() { super.clear(); //print("getOpt clear"); put(Class.class, getOpt_special); put(String.class, getOpt_special); } } static final Map> getOpt_cache = _registerDangerousWeakMap(synchroMap(new getOpt_Map())); static HashMap getOpt_special; // just a marker /*static void getOpt_special_init(Map map) { map.put(Class.class, getOpt_special); map.put(S.class, getOpt_special); }*/ static Map getOpt_getFieldMap(Object o) { Class c = _getClass(o); HashMap map = getOpt_cache.get(c); if (map == null) map = getOpt_makeCache(c); return map; } static Object getOpt_cached(Object o, String field) { try { if (o == null) return null; Map map = getOpt_getFieldMap(o); if (map == getOpt_special) { if (o instanceof Class) return getOpt((Class) o, field); /*if (o instanceof S) ret getOpt(getBot((S) o), field);*/ if (o instanceof Map) return ((Map) o).get(field); } Field f = map.get(field); if (f != null) return f.get(o); if (o instanceof DynamicObject) return syncMapGet2(((DynamicObject) o).fieldValues, field); return null; } catch (Exception __e) { throw rethrow(__e); } } // used internally - we are in synchronized block static HashMap getOpt_makeCache(Class c) { HashMap map; if (isSubtypeOf(c, Map.class)) map = getOpt_special; else { map = new HashMap(); if (!reflection_classesNotToScan().contains(c.getName())) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) { makeAccessible(f); String name = f.getName(); if (!map.containsKey(name)) map.put(name, f); } _c = _c.getSuperclass(); } while (_c != null); } } if (getOpt_cache != null) getOpt_cache.put(c, map); return map; } static Field getOpt_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); return null; } static Field makeAccessible(Field f) { try { f.setAccessible(true); } catch (Throwable e) { // Note: The error reporting only works with Java VM option --illegal-access=deny vmBus_send("makeAccessible_error", e, f); } return f; } static Method makeAccessible(Method m) { try { m.setAccessible(true); } catch (Throwable e) { vmBus_send("makeAccessible_error", e, m); } return m; } static Constructor makeAccessible(Constructor c) { try { c.setAccessible(true); } catch (Throwable e) { vmBus_send("makeAccessible_error", e, c); } return c; } static Class __javax; static Class getJavaX() { try { return __javax; } catch (Exception __e) { throw rethrow(__e); } } static void __setJavaX(Class j) { __javax = j; _onJavaXSet(); } static AutoCloseable tempSetThreadLocal(final ThreadLocal tl, A a) { if (tl == null) return null; final A prev = setThreadLocal(tl, a); return new AutoCloseable() { public String toString() { return "tl.set(prev);"; } public void close() throws Exception { tl.set(prev); }}; } static Object getOptDynOnly(DynamicObject o, String field) { if (o == null || o.fieldValues == null) return null; return o.fieldValues.get(field); } static Map newDangerousWeakHashMap() { return _registerDangerousWeakMap(synchroMap(new WeakHashMap())); } // initFunction: voidfunc(Map) - is called initially, and after clearing the map static Map newDangerousWeakHashMap(Object initFunction) { return _registerDangerousWeakMap(synchroMap(new WeakHashMap()), initFunction); } static Object callMCWithVarArgs(String method, Object... args) { return call_withVarargs(mc(), method, args); } static String getClassName(Object o) { return o == null ? "null" : o instanceof Class ? ((Class) o).getName() : o.getClass().getName(); } static Object invokeMethod(Method m, Object o, Object... args) { try { try { return m.invoke(o, args); } catch (InvocationTargetException e) { throw rethrow(getExceptionCause(e)); } catch (IllegalArgumentException e) { throw new IllegalArgumentException(e.getMessage() + " - was calling: " + m + ", args: " + joinWithSpace(classNames(args))); } } catch (Exception __e) { throw rethrow(__e); } } static boolean call_checkArgs(Method m, Object[] args, boolean debug) { Class[] types = m.getParameterTypes(); if (types.length != l(args)) { if (debug) print("Bad parameter length: " + args.length + " vs " + types.length); return false; } for (int i = 0; i < types.length; i++) { Object arg = args[i]; if (!(arg == null ? !types[i].isPrimitive() : isInstanceX(types[i], arg))) { if (debug) print("Bad parameter " + i + ": " + arg + " vs " + types[i]); return false; } } return true; } static String padLeft(String s, char c, int n) { return rep(c, n-l(s)) + s; } // default to space static String padLeft(String s, int n) { return padLeft(s, ' ', n); } public static boolean isSnippetID(String s) { try { parseSnippetID(s); return true; } catch (RuntimeException e) { return false; } } public static long parseSnippetID(String snippetID) { long id = Long.parseLong(shortenSnippetID(snippetID)); if (id == 0) throw fail("0 is not a snippet ID"); return id; } static String programID; static String getProgramID() { return nempty(programID) ? formatSnippetIDOpt(programID) : "?"; } // TODO: ask JavaX instead static String getProgramID(Class c) { String id = (String) getOpt(c, "programID"); if (nempty(id)) return formatSnippetID(id); return "?"; } static String getProgramID(Object o) { return getProgramID(getMainClass(o)); } static String loadTextFile(String fileName) { return loadTextFile(fileName, null); } static String loadTextFile(File f, String defaultContents) { return loadTextFile(f, defaultContents, "UTF-8"); } static String loadTextFile(File f, String defaultContents, String encoding) { try { checkFileNotTooBigToRead(f); if (f == null || !f.exists()) return defaultContents; FileInputStream fileInputStream = new FileInputStream(f); InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, encoding); return loadTextFile(inputStreamReader); } catch (Exception __e) { throw rethrow(__e); } } public static String loadTextFile(File fileName) { return loadTextFile(fileName, null); } static String loadTextFile(String fileName, String defaultContents) { return fileName == null ? defaultContents : loadTextFile(newFile(fileName), defaultContents); } static String loadTextFile(Reader reader) throws IOException { StringBuilder builder = new StringBuilder(); try { char[] buffer = new char[1024]; int n; while (-1 != (n = reader.read(buffer))) builder.append(buffer, 0, n); } finally { reader.close(); } return str(builder); } static String n2(long l) { return formatWithThousands(l); } static String n2(AtomicLong l) { return n2(l.get()); } static String n2(Collection l) { return n2(l(l)); } static String n2(Map map) { return n2(l(map)); } static String n2_getPlural(String singular) { //ret singular + "s"; return plural(singular); } static String n2(double l, String singular) { return empty(singular) ? str(l) : n2(l, singular, n2_getPlural(singular)); } static String n2(double l, String singular, String plural) { if (fraction(l) == 0) return n2((long) l, singular, plural); else return l + " " + plural; } static String n2(long l, String singular, String plural) { return n_fancy2(l, singular, plural); } static String n2(long l, String singular) { return empty(singular) ? n2(l) : n_fancy2(l, singular, n2_getPlural(singular)); } static String n2(Collection l, String singular) { return n2(l(l), singular); } static String n2(Collection l, String singular, String plural) { return n_fancy2(l, singular, plural); } static String n2(Map m, String singular, String plural) { return n_fancy2(m, singular, plural); } static String n2(Map m, String singular) { return n2(l(m), singular); } static String n2(long[] a, String singular) { return n2(l(a), singular); } static String n2(Object[] a, String singular) { return n2(l(a), singular); } static String n2(Object[] a, String singular, String plural) { return n_fancy2(a, singular, plural); } static String n2(IMultiMap mm, String singular) { return n2(mm, singular, n2_getPlural(singular)); } static String n2(IMultiMap mm, String singular, String plural) { return n_fancy2(l(mm), singular, plural); } static Set synchroHashSet() { return synchronizedSet(new HashSet()); } static > B addAllAndReturnCollection(B c, Collection b) { if (c != null && b != null) c.addAll(b); return c; } static > B addAllAndReturnCollection(B c, A... b) { addAll(c, b); return c; } // TODO: JDK 17!! ?? No! Yes? Yes!! static Object collectionMutex(List l) { return l; } static Object collectionMutex(Object o) { if (o instanceof List) return o; // TODO: actually use our own maps so we can get the mutex properly String c = className(o); return o; } static Set emptySet() { return new HashSet(); } static HashSet asHashSet(Collection c) { synchronized(collectionMutex(c)) { return new HashSet(c); } } static HashSet asHashSet(A[] a) { return a == null ? null : new HashSet(Arrays.asList(a)); } static List splitAtSpace(String s) { return empty(s) ? emptyList() : asList(s.split("\\s+")); } static int iteratorCount_int_close(Iterator i) { try { int n = 0; if (i != null) while (i.hasNext()) { i.next(); ++n; } if (i instanceof AutoCloseable) ((AutoCloseable) i).close(); return n; } catch (Exception __e) { throw rethrow(__e); } } static List itemPlusList(A a, Collection l) { return concatLists(ll(a), l); } static Pair mapEntryToPair(Map.Entry e) { return e == null ? null : pair(e.getKey(), e.getValue()); } static Set> entrySet(Map map) { return _entrySet(map); } static A firstThat(Iterable l, IF1 pred) { for (A a : unnullForIteration(l)) if (pred.get(a)) return a; return null; } static A firstThat(A[] l, IF1 pred) { for (A a : unnullForIteration(l)) if (pred.get(a)) return a; return null; } static A firstThat(IF1 pred, Iterable l) { return firstThat(l, pred); } static A firstThat(IF1 pred, A[] l) { return firstThat(l, pred); } static String[] drop(int n, String[] a) { n = Math.min(n, a.length); String[] b = new String[a.length-n]; System.arraycopy(a, n, b, 0, b.length); return b; } static Object[] drop(int n, Object[] a) { n = Math.min(n, a.length); Object[] b = new Object[a.length-n]; System.arraycopy(a, n, b, 0, b.length); return b; } static List drop(Iterable c, Object pred) { return antiFilter(c, pred); } static List drop(Object pred, Iterable c) { return antiFilter(pred, c); } static List drop(Object pred, Object[] c) { return antiFilter(pred, c); } static List drop(Iterable c, F1 pred) { return antiFilter(c, pred); } static List drop(F1 pred, Iterable c) { return antiFilter(pred, c); } static List drop(Iterable c, IF1 pred) { return antiFilter(c, pred); } static List drop(IF1 pred, Iterable c) { return antiFilter(pred, c); } static ArrayList toList(A[] a) { return asList(a); } static ArrayList toList(int[] a) { return asList(a); } static ArrayList toList(short[] a) { return asList(a); } static ArrayList toList(long[] a) { return asList(a); } static ArrayList toList(double[] a) { return asList(a); } static ArrayList toList(float[] a) { return asList(a); } static ArrayList toList(Set s) { return asList(s); } static ArrayList toList(Iterable s) { return asList(s); } static boolean regionMatches(String a, int offsetA, String b, int offsetB, int len) { return a != null && b != null && a.regionMatches(offsetA, b, offsetB, len); } static boolean regionMatches(String a, int offsetA, String b) { return regionMatches(a, offsetA, b, 0, l(b)); } static String javaTok_substringN(String s, int i, int j) { if (i == j) return ""; if (j == i+1 && s.charAt(i) == ' ') return " "; return s.substring(i, j); } static String javaTok_substringC(String s, int i, int j) { return s.substring(i, j); } static List javaTokWithExisting(String s, List existing) { ++javaTok_n; int nExisting = javaTok_opt && existing != null ? existing.size() : 0; ArrayList tok = existing != null ? new ArrayList(nExisting) : new ArrayList(); int l = s.length(); int i = 0, n = 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 && !s.substring(j, Math.min(j+2, l)).equals("*/")); j = Math.min(j+2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } if (n < nExisting && javaTokWithExisting_isCopyable(existing.get(n), s, i, j)) tok.add(existing.get(n)); else tok.add(javaTok_substringN(s, i, j)); ++n; 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) { if (s.charAt(j) == opener /*|| s.charAt(j) == '\n'*/) { // allow multi-line strings ++j; break; } else if (s.charAt(j) == '\\' && j+1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || "'".indexOf(s.charAt(j)) >= 0)); // 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+1 < l && !s.substring(j, j+2).equals("]]")); j = Math.min(j+2, l); } else if (c == '[' && d == '=' && i+2 < l && s.charAt(i+2) == '[') { do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]")); j = Math.min(j+3, l); } else ++j; if (n < nExisting && javaTokWithExisting_isCopyable(existing.get(n), s, i, j)) tok.add(existing.get(n)); else tok.add(javaTok_substringC(s, i, j)); ++n; i = j; } if ((tok.size() % 2) == 0) tok.add(""); javaTok_elements += tok.size(); return tok; } static boolean javaTokWithExisting_isCopyable(String t, String s, int i, int j) { return t.length() == j-i && s.regionMatches(i, t, 0, j-i); // << could be left out, but that's brave } static ArrayList emptyList() { return new ArrayList(); //ret Collections.emptyList(); } static ArrayList emptyList(int capacity) { return new ArrayList(max(0, capacity)); } // Try to match capacity static ArrayList emptyList(Iterable l) { return l instanceof Collection ? emptyList(((Collection) l).size()) : emptyList(); } static ArrayList emptyList(Object[] l) { return emptyList(l(l)); } // get correct type at once static ArrayList emptyList(Class c) { return new ArrayList(); } static int[] emptyIntArray_a = new int[0]; static int[] emptyIntArray() { return emptyIntArray_a; } static char[] emptyCharArray = new char[0]; static char[] emptyCharArray() { return emptyCharArray; } static double[] emptyDoubleArray = new double[0]; static double[] emptyDoubleArray() { return emptyDoubleArray; } static float[] emptyFloatArray = new float[0]; static float[] emptyFloatArray() { return emptyFloatArray; } static Map emptyMap() { return new HashMap(); } static Object[] emptyObjectArray_a = new Object[0]; static Object[] emptyObjectArray() { return emptyObjectArray_a; } static Symbol emptySymbol_value; static Symbol emptySymbol() { if (emptySymbol_value == null) emptySymbol_value = symbol(""); return emptySymbol_value; } static int indexOf(List l, A a, int startIndex) { if (l == null) return -1; int n = l(l); for (int i = startIndex; i < n; i++) if (eq(l.get(i), a)) return i; return -1; } static int indexOf(List l, int startIndex, A a) { return indexOf(l, a, startIndex); } static int indexOf(List l, A a) { if (l == null) return -1; return l.indexOf(a); } static int indexOf(String a, String b) { return a == null || b == null ? -1 : a.indexOf(b); } static int indexOf(String a, String b, int i) { return a == null || b == null ? -1 : a.indexOf(b, i); } static int indexOf(String a, char b) { return a == null ? -1 : a.indexOf(b); } static int indexOf(String a, int i, char b) { return indexOf(a, b, i); } static int indexOf(String a, char b, int i) { return a == null ? -1 : a.indexOf(b, i); } static int indexOf(String a, int i, String b) { return a == null || b == null ? -1 : a.indexOf(b, i); } static int indexOf(A[] x, A a) { int n = l(x); for (int i = 0; i < n; i++) if (eq(x[i], a)) return i; return -1; } static int indexOf(Iterable l, A a) { if (l == null) return -1; int i = 0; for (A x : l) { if (eq(x, a)) return i; i++; } return -1; } static void addAll(Collection c, Iterable b) { if (c != null && b != null) for (A a : b) c.add(a); } static boolean addAll(Collection c, Collection b) { return c != null && b != null && c.addAll(b); } static boolean addAll(Collection c, B... b) { return c != null && b != null && c.addAll(Arrays.asList(b)); } static Map addAll(Map a, Map b) { if (a != null && b != null) a.putAll(b); return a; } static A addAll(A c, Collection components) { return addComponents(c, components); } static A addAll(A c, Component... components) { return addComponents(c, components); } static File makeTempDir() { return (File) call(getJavaX(), "TempDirMaker_make"); } /** writes safely (to temp file, then rename) */ static File saveTextFile(String fileName, String contents) throws IOException { /*ifdef CriticalActions temp beginCriticalAction("Saving file " + fileName + " (" + l(contents) + " chars)"); endifdef*/ File file = new File(fileName); mkdirsForFile(file); String tempFileName = fileName + "_temp"; File tempFile = new File(tempFileName); if (contents != null) { if (tempFile.exists()) try { String saveName = tempFileName + ".saved." + now(); copyFile(tempFile, new File(saveName)); } catch (Throwable e) { printStackTrace(e); } FileOutputStream fileOutputStream = newFileOutputStream(tempFile.getPath()); try { OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "UTF-8"); PrintWriter printWriter = new PrintWriter(outputStreamWriter); printWriter.print(contents); printWriter.close(); } finally { _close(fileOutputStream); }} if (file.exists() && !file.delete()) throw new IOException("Can't delete " + fileName); if (contents != null) if (!tempFile.renameTo(file)) throw new IOException("Can't rename " + tempFile + " to " + file); vmBus_send("wroteFile", file); return file; } static File saveTextFile(File fileName, String contents) { try { saveTextFile(fileName.getPath(), contents); return fileName; } catch (Exception __e) { throw rethrow(__e); } } static String strOrEmpty(Object o) { return o == null ? "" : str(o); } static Map newWeakHashMap() { return _registerWeakMap(synchroMap(new WeakHashMap())); } static void newPing() { var tl = newPing_actionTL(); Runnable action = tl == null ? null : tl.get(); { if (action != null) action.run(); } } // TODO: test if android complains about this static boolean isAWTThread() { if (isAndroid()) return false; if (isHeadless()) return false; return isAWTThread_awt(); } static boolean isAWTThread_awt() { return SwingUtilities.isEventDispatchThread(); } static boolean isTrue(Object o) { if (o instanceof Boolean) return ((Boolean) o).booleanValue(); if (o == null) return false; if (o instanceof ThreadLocal) // TODO: remove this return isTrue(((ThreadLocal) o).get()); throw fail(getClassName(o)); } static boolean isTrue(Boolean b) { return b != null && b.booleanValue(); } static void failIfUnlicensed() { assertTrue("license off", licensed()); } static Thread currentThread() { return Thread.currentThread(); } // unclear semantics as to whether return null on null static ArrayList asList(A[] a) { return a == null ? new ArrayList() : new ArrayList(Arrays.asList(a)); } static ArrayList asList(char[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (var i : a) l.add(i); return l; } static ArrayList asList(byte[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (var i : a) l.add(i); return l; } static ArrayList asList(int[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (int i : a) l.add(i); return l; } static ArrayList asList(long[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (long i : a) l.add(i); return l; } static ArrayList asList(float[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (float i : a) l.add(i); return l; } static ArrayList asList(double[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (double i : a) l.add(i); return l; } static ArrayList asList(short[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (short i : a) l.add(i); return l; } static ArrayList asList(Iterator it) { ArrayList l = new ArrayList(); if (it != null) while (it.hasNext()) l.add(it.next()); return l; } // disambiguation static ArrayList asList(IterableIterator s) { return asList((Iterator) s); } static ArrayList asList(Iterable s) { if (s instanceof ArrayList) return (ArrayList) s; ArrayList l = new ArrayList(); if (s != null) for (A a : s) l.add(a); return l; } static ArrayList asList(Producer p) { ArrayList l = new ArrayList(); A a; if (p != null) while ((a = p.next()) != null) l.add(a); return l; } static ArrayList asList(Enumeration e) { ArrayList l = new ArrayList(); if (e != null) while (e.hasMoreElements()) l.add(e.nextElement()); return l; } static ArrayList asList(ReverseChain c) { return c == null ? emptyList() : c.toList(); } static List asList(Pair p) { return p == null ? null : ll(p.a, p.b); } static HashMap javaTokForJFind_array_cache = new HashMap(); static String[] javaTokForJFind_array(String s) { String[] tok = javaTokForJFind_array_cache.get(s); if (tok == null) javaTokForJFind_array_cache.put(s, tok = codeTokensAsStringArray(jfind_preprocess(javaTok(s)))); return tok; } // "$1" is first code token, "$2" second code token etc. static String jreplaceExpandRefs(String s, List tokref) { if (!contains(s, '$')) return s; List tok = javaTok(s); for (int i = 1; i < l(tok); i += 2) { String t = tok.get(i); if (t.startsWith("$") && isInteger(t.substring(1))) { String x = tokref.get(-1+parseInt(t.substring(1))*2); tok.set(i, x); } else if (t.equals("\\")) { tok.set(i, ""); i += 2; } } return join(tok); } // TODO: more cases static String tok_typeArgs_declToInvocation(String typeArgs) { List tok = javaTok(typeArgs); int i; while ((i = jfind(tok, "extends ")) >= 0) { int j = tok_endOfType(tok, i+2); clearTokens(tok, i, j); } return join(tok); } static String tok_scanType(List tok, int iTypeStart) { int iEndOfType = tok_endOfType(tok, iTypeStart); return joinSubList_cToC(tok, iTypeStart, iEndOfType); } static String tok_dropTypeParameters(String type) { return join(dropAfter("<", javaTok(type))); } static String[] toStringArray(Collection c) { String[] a = new String[l(c)]; Iterator it = c.iterator(); for (int i = 0; i < l(a); i++) a[i] = it.next(); return a; } static String[] toStringArray(Object o) { if (o instanceof String[]) return (String[]) o; else if (o instanceof Collection) return toStringArray((Collection) o); else throw fail("Not a collection or array: " + getClassName(o)); } static List codeTokensOnly(List tok) { int n = l(tok); List l = emptyList(n/2); for (int i = 1; i < n; i += 2) l.add(tok.get(i)); return l; } static B mapGet(Map map, A a) { return map == null || a == null ? null : map.get(a); } static B mapGet(A a, Map map) { return map == null || a == null ? null : map.get(a); } static void _handleError(Error e) { //call(javax(), '_handleError, e); } static void add(BitSet bs, int i) { bs.set(i); } static boolean add(Collection c, A a) { return c != null && c.add(a); } static void add(Container c, Component x) { addToContainer(c, x); } static long add(AtomicLong l, long b) { return l.addAndGet(b); } // auto-magic type parameter might be a bad idea. supply explicitly if // in doubt. static IF2 if0ToIF2(IF0 f) { return f == null ? null : (a, b) -> f.get(); } static String dropTrailingSquareBracketStuff(String s) { if (!endsWith(s, "]")) return s; return trimSubstring(s, 0, smartLastIndexOf(s, '[')); } static IResourceLoader vm_getResourceLoader() { return proxy(IResourceLoader.class, vm_generalMap_get("_officialResourceLoader")); } static boolean isLocalSnippetID(String snippetID) { return isSnippetID(snippetID) && isLocalSnippetID(psI(snippetID)); } static boolean isLocalSnippetID(long snippetID) { return snippetID >= 1000 && snippetID <= 9999; } static String localSnippetTitle(String snippetID) { if (!isLocalSnippetID(snippetID)) return null; File f = localSnippetFile(snippetID); if (!f.exists()) return null; return or2(getFileInfoField(dropExtension(f), "Title"), "Unnamed"); } static boolean isImageServerSnippet(long id) { return id >= 1100000 && id < 1200000; } static String imageServerURL() { return or2(trim(loadTextFile(javaxDataDir("image-server-url.txt"))), "http://botcompany.de/images/raw/"); } static String muricaCredentialsQuery() { return htmlQuery(muricaCredentials()); } static boolean isGeneralFileServerSnippet(long id) { return id >= 1400000 && id < 1500000; } static String tb_mainServer_default = "https://code.botcompany.de:9898"; static Object tb_mainServer_override; // func -> S static String tb_mainServer() { if (tb_mainServer_override != null) return (String) callF(tb_mainServer_override); return trim(loadTextFile(tb_mainServer_file(), tb_mainServer_default)); } static File tb_mainServer_file() { return getProgramFile("#1001638", "mainserver.txt"); } static boolean tb_mainServer_isDefault() { return eq(tb_mainServer(), tb_mainServer_default); } static String standardCredentials_noCookies() { return standardCredentials() + "&noCookies=1"; } static int loadPage_defaultTimeout = 60000; static ThreadLocal loadPage_charset = new ThreadLocal(); static boolean loadPage_allowGzip = true, loadPage_debug; static boolean loadPage_anonymous = false; // don't send computer ID static int loadPage_verboseness = 100000; static int loadPage_retries = 1; //60; // seconds static ThreadLocal loadPage_silent = new ThreadLocal(); static volatile int loadPage_forcedTimeout; // ms static ThreadLocal loadPage_forcedTimeout_byThread = new ThreadLocal(); // ms static ThreadLocal>> loadPage_responseHeaders = new ThreadLocal(); static ThreadLocal> loadPage_extraHeaders = new ThreadLocal(); static ThreadLocal loadPage_sizeLimit = new ThreadLocal(); public static String loadPageSilently(String url) { try { return loadPageSilently(new URL(loadPage_preprocess(url))); } catch (Exception __e) { throw rethrow(__e); } } public static String loadPageSilently(URL url) { try { if (!networkAllowanceTest(str(url))) throw fail("Not allowed: " + url); IOException e = null; for (int tries = 0; tries < loadPage_retries; tries++) try { URLConnection con = loadPage_openConnection(url); return loadPage(con, url); } catch (IOException _e) { e = _e; if (loadPage_debug) print(exceptionToStringShort(e)); if (tries < loadPage_retries-1) sleepSeconds(1); } throw e; } catch (Exception __e) { throw rethrow(__e); } } static String loadPage_preprocess(String url) { if (url.startsWith("tb/")) // don't think we use this anymore url = tb_mainServer() + "/" + url; if (url.indexOf("://") < 0) url = "http://" + url; return url; } static String loadPage(String url) { try { url = loadPage_preprocess(url); if (!isTrue(loadPage_silent.get())) printWithTime("Loading: " + hideCredentials(url)); return loadPageSilently(new URL(url)); } catch (Exception __e) { throw rethrow(__e); } } static String loadPage(URL url) { return loadPage(url.toExternalForm()); } static String loadPage(URLConnection con, URL url) throws IOException { return loadPage(con, url, true); } static String loadPage(URLConnection con, URL url, boolean addHeaders) { try { Map extraHeaders = getAndClearThreadLocal(loadPage_extraHeaders); if (addHeaders) try { if (!loadPage_anonymous) setHeaders(con); if (loadPage_allowGzip) con.setRequestProperty("Accept-Encoding", "gzip"); con.setRequestProperty("X-No-Cookies", "1"); for (String key : keys(extraHeaders)) con.setRequestProperty(key, extraHeaders.get(key)); } catch (Throwable e) {} // fails if within doPost return loadPage(con); } catch (Exception __e) { throw rethrow(__e); } } // just download as string, no shenanigans or extra headers or ANYTHING static String loadPage(URLConnection con) { try { Long limit = optPar(loadPage_sizeLimit); URL url = con.getURL(); vm_generalSubMap("URLConnection per thread").put(currentThread(), con); loadPage_responseHeaders.set(con.getHeaderFields()); InputStream in = null; try { in = urlConnection_getInputStream(con); //vm_generalSubMap("InputStream per thread").put(currentThread(), in); if (loadPage_debug) print("Put stream in map: " + currentThread()); String contentType = con.getContentType(); if (contentType == null) { //printStruct("Headers: ", con.getHeaderFields()); throw new IOException("Page could not be read: " + hideCredentials(url)); } //print("Content-Type: " + contentType); String charset = loadPage_charset == null ? null : loadPage_charset.get(); if (charset == null) charset = loadPage_guessCharset(contentType); if ("gzip".equals(con.getContentEncoding())) { if (loadPage_debug) print("loadPage: Using gzip."); in = newGZIPInputStream(in); } Reader r; try { r = new InputStreamReader(in, unquote(charset)); } catch (UnsupportedEncodingException e) { print(toHex(utf8(charset))); throw e; } boolean silent = isTrue(loadPage_silent.get()); StringBuilder buf = new StringBuilder(); int n = 0; while (limit == null || n < limit) { ping(); int ch = r.read(); if (ch < 0) break; buf.append((char) ch); ++n; if (!silent && (n % loadPage_verboseness) == 0) print(" " + n + " chars read"); } return buf.toString(); } finally { if (loadPage_debug) print("loadPage done"); //vm_generalSubMap("InputStream per thread").remove(currentThread()); vm_generalSubMap("URLConnection per thread").remove(currentThread()); if (in != null) in.close(); } } catch (Exception __e) { throw rethrow(__e); } } static String loadPage_guessCharset(String contentType) { Matcher m = regexpMatcher("text/[a-z]+;\\s*charset=([^\\s]+)\\s*", contentType); String match = m.matches() ? m.group(1) : null; if (loadPage_debug) print("loadPage: contentType=" + contentType + ", match: " + match); /* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */ //return or(match, "ISO-8859-1"); return or(match, "UTF-8"); } static URLConnection loadPage_openConnection(URL url) { URLConnection con = openConnection(url); int timeout = toInt(loadPage_forcedTimeout_byThread.get()); if (timeout == 0) timeout = loadPage_forcedTimeout; if (timeout != 0) setURLConnectionTimeouts(con, loadPage_forcedTimeout); else setURLConnectionDefaultTimeouts(con, loadPage_defaultTimeout); return con; } static boolean saveTextFileIfChanged(File f, String contents) { return saveTextFileIfDifferent(f, contents); } static File snippetTitle_cacheFile(String snippetID) { return javaxCachesDir("Snippet Titles/" + psI(snippetID)); } static String exceptionToStringShort(Throwable e) { try { lastException(e); e = getInnerException(e); String msg = hideCredentials(unnull(e.getMessage())); if (msg.indexOf("Error") < 0 && msg.indexOf("Exception") < 0) return baseClassName(e) + prependIfNempty(": ", msg); else return msg; } catch (Throwable _e) { printStackTrace(_e); return "Error in exceptionToStringShort"; } } static List rjfindAll(List tok, String pat) { return jfindAll_reversed(tok, pat); } static List rjfindAll(List tok, String pat, ITokCondition condition) { return jfindAll_reversed(tok, pat, condition); } static List rjfindAll(List tok, List tokPat) { return jfindAll_reversed(tok, tokPat); } // i must point at the (possibly imaginary) opening bracket ("{") // index returned is token after closing bracket (or >= l(tok)) static int tok_scanBlock_idx(List tok, int i) { return tok_findEndOfBlock(tok, i)+1; } static String tok_lastIdentifier(String s) { return lastIdentifier(javaTokC(s)); } static List tok_parseArgsDeclList(List tok) { return tok_parseArgsList(tok, getBracketMapIncludingAngleBrackets(tok)); } static void tokAppend(List tok, int i, String s) { tok.set(i, tok.get(i)+s); } static boolean addToCollection(Collection c, A a) { return c != null && c.add(a); } static IContentsIndexedList toContentsIndexedList(Collection l) { if (l == null) return new ContentsIndexedList(); if (l instanceof IContentsIndexedList) return ((IContentsIndexedList) l); return new ContentsIndexedList(l); } // returns actual CNC static List tok_findImports_returnRanges(List tok) { List imports = new ArrayList(); int n = l(tok); for (int i : indicesOf(tok, "import")) { int j = indexOf(tok, ";", i+2); if (j < 0) break; imports.add(intRange(i-1, j+2)); i = j; } return imports; } static A set(A o, String field, Object value) { if (o == null) return null; if (o instanceof Class) set((Class) o, field, value); else try { Field f = set_findField(o.getClass(), field); makeAccessible(f); smartSet(f, o, value); } catch (Exception e) { throw new RuntimeException(e); } return o; } static void set(Class c, String field, Object value) { if (c == null) return; try { Field f = set_findStaticField(c, field); makeAccessible(f); smartSet(f, null, value); } catch (Exception e) { throw new RuntimeException(e); } } static Field set_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 set_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 void set(BitSet bs, int idx) { { if (bs != null) bs.set(idx); } } static List indicesOf(List l, A a) { if (l == null) return null; if (l instanceof IContentsIndexedList) return intArrayToList(((IContentsIndexedList) l).indicesOf(a)); if (l instanceof IContentsIndexedList2) return map(h -> ((HasIndex) h).idx, ((IContentsIndexedList2) l).indicesOf_treeSetOfHasIndex(a)); List x = new ArrayList(); for (int i = 0; i < l(l); i++) if (eq(l.get(i), a)) x.add(i); return x; } static List indicesOf(String s, String x) { int i = -1; List out = new ArrayList(); while ((i = indexOf(s, x, i+1)) >= 0) out.add(i); return out; } static void clearTokens_addToReToks(List tok, int i, int j, List reToks) { if (j <= i) return; clearAllTokens(tok, i, j); reToks.add(intRange(i, j)); } static boolean startsWith(String a, String b) { return a != null && a.startsWith(unnull(b)); } static boolean startsWith(String a, char c) { return nemptyString(a) && a.charAt(0) == c; } static boolean startsWith(String a, String b, Matches m) { if (!startsWith(a, b)) return false; if (m != null) m.m = new String[] {substring(a, strL(b))}; return true; } static boolean startsWith(List a, List b) { if (a == null || listL(b) > listL(a)) return false; for (int i = 0; i < listL(b); i++) if (neq(a.get(i), b.get(i))) return false; return true; } static String structureForUser(Object o) { return structureForUser(o, new structure_Data()); } static String structureForUser(Object o, structure_Data d) { d.noStringSharing = true; d.warnIfUnpersistable(false); return beautifyStructure(structure(o, d)); } static boolean containsIgnoreCase(Collection l, String s) { if (l != null) for (String x : l) if (eqic(x, s)) return true; return false; } static boolean containsIgnoreCase(String[] l, String s) { if (l != null) for (String x : l) if (eqic(x, s)) return true; return false; } static boolean containsIgnoreCase(String s, char c) { return indexOfIgnoreCase(s, String.valueOf(c)) >= 0; } static boolean containsIgnoreCase(String a, String b) { return indexOfIgnoreCase(a, b) >= 0; } static void print_tee(Appendable buf, Object o) { print_tee(buf, "", o); } static void print_tee(Appendable buf, String prefix, Object o) { try { String s = combinePrintParameters(prefix, o); { if (buf != null) buf.append(s + "\n"); } // we prefer this over 2 calls, it's possibly atomic print(s); } catch (Exception __e) { throw rethrow(__e); } } static void print_tee(StringBuilder buf) { print_tee(buf, ""); } static String takeFirstLines(int n, String s) { return lineRange(s, 0, n); } static int parseIntOpt(String s) { return parseIntOpt(s, 0); } static int parseIntOpt(String s, int defValue) { return isInteger(s) ? parseInt(s) : defValue; } static String regexpFirstGroupIC(String pat, String s) { Matcher m = regexpIC(pat, s); if (m.find()) return m.group(1); else return null; } static int max(int a, int b) { return Math.max(a, b); } static int max(int a, int b, int c) { return max(max(a, b), c); } static long max(int a, long b) { return Math.max((long) a, b); } static long max(long a, long b) { return Math.max(a, b); } static double max(int a, double b) { return Math.max((double) a, b); } static float max(float a, float b) { return Math.max(a, b); } static double max(double a, double b) { return Math.max(a, b); } static > A max (Iterable l) { A max = null; var it = iterator(l); if (it.hasNext()) { max = it.next(); while (it.hasNext()) { A a = it.next(); if (cmp(a, max) > 0) max = a; } } return max; } /*Nah. static int max(Collection c) { int x = Integer.MIN_VALUE; for (int i : c) x = max(x, i); ret x; }*/ static double max(double[] c) { if (c.length == 0) return Double.MIN_VALUE; double x = c[0]; for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]); return x; } static float max(float[] c) { if (c.length == 0) return Float.MAX_VALUE; float x = c[0]; for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]); return x; } static byte max(byte[] c) { byte x = -128; for (byte d : c) if (d > x) x = d; return x; } static short max(short[] c) { short x = -0x8000; for (short d : c) if (d > x) x = d; return x; } static int max(int[] c) { int x = Integer.MIN_VALUE; for (int d : c) if (d > x) x = d; return x; } static > A max(A a, A b) { return cmp(a, b) >= 0 ? a : b; } static int min(int a, int b) { return Math.min(a, b); } static long min(long a, long b) { return Math.min(a, b); } static float min(float a, float b) { return Math.min(a, b); } static float min(float a, float b, float c) { return min(min(a, b), c); } static double min(double a, double b) { return Math.min(a, b); } static double min(double[] c) { double x = Double.MAX_VALUE; for (double d : c) x = Math.min(x, d); return x; } static float min(float[] c) { float x = Float.MAX_VALUE; for (float d : c) x = Math.min(x, d); return x; } static byte min(byte[] c) { byte x = 127; for (byte d : c) if (d < x) x = d; return x; } static short min(short[] c) { short x = 0x7FFF; for (short d : c) if (d < x) x = d; return x; } static int min(int[] c) { int x = Integer.MAX_VALUE; for (int d : c) if (d < x) x = d; return x; } static > A min(A a, A b) { return cmp(a, b) <= 0 ? a : b; } static File javaxCachesDir_dir; // can be set to work on different base dir static File javaxCachesDir() { return javaxCachesDir_dir != null ? javaxCachesDir_dir : new File(userHome(), "JavaX-Caches"); } static File javaxCachesDir(String sub) { return newFile(javaxCachesDir(), sub); } static String getInnerMessage(Throwable e) { if (e == null) return null; return getInnerException(e).getMessage(); } static void replaceCollection(Collection dest, Collection src) { if (dest == src) return; dest.clear(); if (src != null) dest.addAll(src); } static void replaceListPart(List l, int i, int j, List l2) { replaceSublist(l, i, j, l2); } static File newFile(File base, String... names) { for (String name : names) base = new File(base, name); return base; } static File newFile(String name) { return name == null ? null : new File(name); } static File newFile(String base, String... names) { return newFile(newFile(base), names); } static File getProgramFile(String progID, String fileName) { if (new File(fileName).isAbsolute()) return new File(fileName); return new File(getProgramDir(progID), fileName); } static File getProgramFile(String fileName) { return getProgramFile(getProgramID(), fileName); } static List cncSubList(List tok, int from, int to) { from &= ~1; to |= 1; return subList(tok, from, to); } static String tok_packageName(List tok) { int i = jfind(tok, "package"); if (i < 0) return ""; i += 2; int j = jfind(tok, i, ";"); if (j < 0) return ""; return join(codeTokensOnly(subList(tok, i-1, j))); } static String tok_packageName(String src) { Producer p = javaTokC_producer(src); String t = p.next(); if (!eq(t, "package")) return ""; StringBuilder buf = new StringBuilder(); while (!eqOneOf(t = p.next(), null, ";")) buf.append(t); return str(buf); } static String getNameOfPublicClass(List tok) { for (List c : allClasses(tok)) if (hasModifier(c, "public")) return getClassDeclarationName(c); return null; } static String getNameOfAnyClass(List tok) { return getClassDeclarationName(first(allClasses(tok))); } static String addSlash(String s) { return empty(s) || s.endsWith("/") ? s : s + "/"; } static boolean boolPar(ThreadLocal tl) { return boolOptParam(tl); } // defaults to false static boolean boolPar(Object[] __, String name) { return boolOptParam(__, name); } static boolean boolPar(String name, Object[] __) { return boolOptParam(__, name); } static boolean boolPar(String name, Map __) { return boolOptParam(name, __); } static boolean boolPar(String name, Object[] params, boolean defaultValue) { return optParam(params, name, defaultValue); } static int rjfind(List tok, String in) { return rjfind(tok, 1, in); } static int rjfind(List tok, int startIdx, String in) { return rjfind(tok, startIdx, in, null); } static int rjfind(List tok, int startIdx, int endIndex, String in) { return rjfind(tok, startIdx, endIndex, in, null); } static int rjfind(List tok, String in, ITokCondition condition) { return rjfind(tok, 1, in, (Object) condition); } static int rjfind(List tok, String in, Object condition) { return rjfind(tok, 1, in, condition); } static int rjfind(List tok, int startIdx, String in, Object condition) { List tokin = javaTok(in); jfind_preprocess(tokin); return rjfind(tok, startIdx, tokin, condition); } static int rjfind(List tok, int startIdx, int endIndex, String in, Object condition) { List tokin = javaTok(in); jfind_preprocess(tokin); return rjfind(tok, startIdx, endIndex, tokin, condition); } // assumes you preprocessed tokin static int rjfind(List tok, List tokin) { return rjfind(tok, 1, tokin); } static int rjfind(List tok, int startIdx, List tokin) { return rjfind(tok, startIdx, tokin, null); } static int rjfind(List tok, int startIdx, List tokin, Object condition) { return rfindCodeTokens(tok, startIdx, false, toStringArray(codeTokensOnly(tokin)), condition); } static int rjfind(List tok, int startIdx, int endIndex, List tokin, Object condition) { return rfindCodeTokens(tok, startIdx, endIndex, false, toStringArray(codeTokensOnly(tokin)), condition); } static boolean subListContains(List l, int startIndex, int endIndex, A a) { if (l == null) return false; int n = l.size(); startIndex = Math.max(0, startIndex); endIndex = Math.min(n, endIndex); for (int i = startIndex; i < endIndex; i++) if (eq(a, l.get(i))) return true; return false; } static int jfind_any(String src, String... patterns) { return jfind_any(javaTok(src), patterns); } static int jfind_any(List tok, String... patterns) { return jfind_any(tok, 1, patterns); } static int jfind_any(List tok, int startIdx, String... patterns) { return jfind_any(tok, startIdx, null, patterns); } static int jfind_any(List tok, TokCondition cond, String... patterns) { return jfind_any(tok, 1, cond, patterns); } static int jfind_any(List tok, int startIdx, TokCondition cond, String... patterns) { int i = -1; for (String pat : patterns) i = minUnlessMinus1(i, jfind(tok, startIdx, pat, cond)); return i; } static int tok_leftScanCustomModifiers(List tok, int i, Collection modifiers) { while (i > 1 && contains(modifiers, tok.get(i-2))) i -= 2; return i; } static List getJavaModifiers_list = litlist("static", "abstract", "public", "private", "protected", "final", "native", "volatile", "synchronized", "transient", "default"); static List getJavaModifiers() { return getJavaModifiers_list; } static Set codeTokensAsSet(List tok) { return asSet(codeTokens_lazy(tok)); } // i must be odd static void clearTokensExceptFromSet(List tok, int i, int j, Collection set) { set = asSet(set); for (; i < j; i += 2) if (!contains(set, tok.get(i))) clearTokens(tok, i, i+2); } static ThreadLocal tok_typesAndNamesOfParams_keepModifiers = new ThreadLocal(); static List> tok_typesAndNamesOfParams(List tok, Object... __) { boolean keepModifiers = boolPar(tok_typesAndNamesOfParams_keepModifiers); boolean typelessMeansObject = boolPar("typelessMeansObject", __); try { List> out = new ArrayList(); for (int i = 1; i < l(tok); ) { i = tok_skipAnnotations(tok, i); String t = get(tok, i); String pre = ""; // yeah, the typeless handling is a mess... if (typelessMeansObject && isIdentifier(t) && eqGetOneOf(tok, i+2, ",", null)) { i += 4; { out.add(pair("Object", t)); continue; } } if (eqOneOf(t, "final", "transient")) { if (keepModifiers) pre += t + " "; t = get(tok, i += 2); } if (eq(t, "virtual")) { pre += "virtual "; t = get(tok, i += 2); } if (eq(t, "new")) { pre += "new "; t = get(tok, i += 2); } assertTrue(isIdentifier(t)); i += 2; String type = t, name = "?"; while (eq(get(tok, i), ".") && !eqGet(tok, i+2, ".")) { type += "." + assertIdentifier(get(tok, i+2)); i += 4; } // just a parameter name, no type if (eqOneOf(get(tok, i), null, ",")) { name = type; type = "?"; } else { if (eq(tok.get(i), "<")) { int j = findEndOfTypeArgs(tok, i)-1; while (eq(get(tok, j), "[") && eq(get(tok, j+2), "]")) j += 4; type += trimJoinSubList(tok, i, j+1); String id = assertIdentifier(tok.get(j+2)); i = j+2; } while (eq(get(tok, i), "[") && eq(get(tok, i+2), "]")) { i += 4; type += "[]"; } if (eqGet(tok, i, "etc")) { i += 2; type += " etc"; } if (eqGet(tok, i, ".") && eqGet(tok, i+2, ".") && eqGet(tok, i+4, ".")) { type += "..."; i += 6; } name = assertIdentifier(tok.get(i)); i += 2; while (eq(get(tok, i), "[") && eq(get(tok, i+2), "]")) { i += 4; type += "[]"; } // skip default value if (eqGet(tok, i, "default")) i = tok_findEndOfExpression(tok, i+2)+1; if (i < l(tok)) { assertEquals(get(tok, i), ","); i += 2; } } out.add(pair(pre + type, name)); } return out; } catch (Throwable e) { print("Bad parameter declaration: " + sfu(tok)); throw rethrow(e); } } static boolean tok_hasDefaultConstructor(List contents, String className) { List contentsWithoutCurly = replaceCurlyBracedWith(tok_combineCurlyBrackets_keep(cloneList(contents)), ""); return jcontains_any(contentsWithoutCurly, "\\*()", className + "()"); } static List trimAll(String... l) { return trimAll(asList(l)); } static List trimAll(Collection l) { List l2 = new ArrayList(); if (l != null) for (String s : l) l2.add(trim(s)); return l2; } static List getJavaLineCommentsWithoutNestedBlocks(List tok) { int curlyLevel = 0; List comments = new ArrayList(); for (int i = 0; i < l(tok); i++) { if (curlyLevel == 0 && even(i)) addAll(comments, getJavaLineComments(tok.get(i))); else curlyLevel += curlyLevel(tok.get(i)); } return comments; } // Use like this: printVars(+x, +y); // Or: printVars("bla", +x); // Or: printVars bla(, +x); static void printVars(Object... params) { printVars_str(params); } static List tok_escapeAsterisk(List tok) { return replace(tok, "*", "\\*"); } static String tok_escapeAsterisk(String s) { return join(tok_escapeAsterisk(javaTok(s))); } static List secondOfPairs(Collection> l) { return lambdaMap(__58 -> secondOfPair(__58), l); } // fields: type + name static String tok_genEqualsAndHashCode(String className, List> fields, Object... __) { String qualifier = optPar("qualifier", __, ""); boolean flexEq = boolPar("flexEq", __); String argName = "o"; while (pairsB(fields).contains(argName)) argName = "_" + argName; StringBuilder buf = new StringBuilder(("\n\npublic bool equals(O " + argName + ") {\n")); String instanceCheck = flexEq ? ("_getClass(" + argName + ") == getClass()") : (argName + " instanceof ") + qualifier + className; if (empty(fields)) buf.append(("ret " + instanceCheck + ";\n")); else { String x = makeVar(); buf.append("if (!(" + instanceCheck + ")) false;\r\n " + className + (" " + x + " = cast ") + argName + ";\r\n ret " + join(" && ", map(fields, new F1, String>() { public String get(Pair p) { try { return tok_isPrimitiveType(p.a) ? p.b + (" == " + x + ".") + p.b : "eq(" + p.b + (", " + x + ".") + p.b + ")"; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "tok_isPrimitiveType(p.a)\r\n ? p.b + \" == \\*x*/.\" + p.b\r\n : \"eq(\"..."; }})) + ";\n"); } buf.append("}\n"); buf.append("\r\n public int hashCode() {\r\n int h = " + hashCode(className) + ";\r\n " + concatMap_strings(fields, new F1, Object>() { public Object get(Pair p) { try { return "h = boostHashCombine(h, _hashCode(" + p.b + "));\r\n "; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "\"h = boostHashCombine(h, _hashCode(\" + p.b + [[));\r\n ]]"; }}) + "ret h;\r\n }\r\n "); return str(buf); } static String tok_genRecordFieldsToList(List> fields) { return "public O[] _fieldsToList() { " + (empty(fields) ? "null;" : "ret new O[] {" + joinWithComma(pairsB(fields)) + "};") + " }\n"; } static String tok_genRecordTransformable(String name, List> fields) { return "public O transformUsing(IF1 f) { " + (empty(fields) ? "this;" : "ret new " + name + "(" + joinWithComma(mapPairs(fields, (type, field) -> (eqOneOf(type, "O", "Object") ? "" : "(" + tok_varArgTypeToArray(type) + ") ") + "f.get(" + field + ")")) + ");") + " }\n" + "public void visitUsing(IVF1 f) {" + joinPrependSpace(map(pairsB(fields), field -> "f.get(" + field + ");")) + " }\n"; } static String joinNemptiesWithComma(Object... strings) { return joinNempties(", ", strings); } static String joinNemptiesWithComma(Iterable strings) { return joinNempties(", ", strings); } static Collection tok_modifiersLeftOf(List tok, int i) { int j = leftScanModifiers(tok, i); List modifiers = new ArrayList(); while (j < i) { modifiers.add(tok.get(j)); j += 2; } return modifiers; } static boolean isSingleQuoteIdentifier(String s) { if (l(s) < 2 || s.charAt(0) != '\'' || !Character.isJavaIdentifierStart(s.charAt(1))) return false; for (int i = 2; i < l(s); i++) if (!Character.isJavaIdentifierPart(s.charAt(i))) return false; return true; } static String transpile_inStringEval(String t) { t = dropPrefix("\"", dropSuffix("\"", t)); List l = new ArrayList(); int idx; while ((idx = t.indexOf("\\*")) >= 0) { int j = indexOf(t, idx, "*/"); if (j < 0) break; if (idx > 0) l.add("\"" + substring(t, 0, idx) + "\""); String code = trim(substring(t, idx+2, j)); l.add(isIdentifier(code) ? code : "(" + code + ")"); t = substring(t, j+2); } if (nempty(t)) l.add("\"" + t + "\""); return "(" + join(" + ", l) + ")"; } static int indexOfAny(List l, int i, A... x) { while (i < l(l)) if (eqOneOf(l.get(i), x)) return i; else ++i; return -1; } static int indexOfAny(List l, Collection x) { return indexOfAny(l, 0, x); } static int indexOfAny(List l, int i, Collection x) { if (nempty(x)) while (i < l(l)) if (x.contains(l.get(i))) return i; else ++i; return -1; } static int indexOfAny(String s, int i, String chars) { for (; i < l(s); i++) if (chars.indexOf(s.charAt(i)) >= 0) return i; return -1; } static int indexOfAny(String s, String chars) { return indexOfAny(s, 0, chars); } static String tok_formatDollarVars(String pat, Map vars) { if (empty(vars)) return pat; Map vars2 = mapKeys(__59 -> addDollarPrefix(__59), vars); List tok = javaTok(pat); for (int i = 1; i < l(tok); i += 2) { String var = tok.get(i); if (!isIdentifier(var)) continue; String value = strOrNull(vars2.get(var)); if (value != null) tok.set(i, value); } String output = join(tok); return output; } static String tok_formatDollarVars(String pat, Object... __) { return tok_formatDollarVars(pat, paramsToMap(__)); } static int tok_leftScanModifiers(List tok, int i) { return leftScanModifiers(tok, i); } // i must point at the (possibly imaginary) opening bracket ("{") // index returned is index of closing bracket + 1 (or l(tok)) static int tok_findEndOfBlock(List tok, int i) { if (tok instanceof IContentsIndexedList2) return tok_findEndOfBlock_IContentsIndexedList2_v2(((IContentsIndexedList2) tok), i); int j = i+2, level = 1, n = l(tok); while (j < n) { String t = tok.get(j); if ("{".equals(t)) ++level; else if ("}".equals(t)) --level; if (level == 0) return j+1; j += 2; } return n; } static boolean startsWithCamelCaseWord(String a, String b) { return startsWith(a, b) && isUpperCase(charAt(a, l(b))); } static String firstToLower(String s) { if (empty(s)) return s; return Character.toLowerCase(s.charAt(0)) + s.substring(1); } static String firstToUpper(String s) { if (empty(s)) return s; return Character.toUpperCase(s.charAt(0)) + s.substring(1); } static List pairsA(Collection> l) { return firstOfPairs(l); } static List dropFirstAndLast(int n, List l) { return cloneSubList(l, n, l(l)-n); } static List dropFirstAndLast(int m, int n, List l) { return cloneSubList(l, m, l(l)-n); } static List dropFirstAndLast(List l) { return dropFirstAndLast(1, l); } static String dropFirstAndLast(String s) { return substring(s, 1, l(s)-1); } static List pairsB(Collection> l) { return secondOfPairs(l); } static List reversed(Iterable l) { return reversedList(l); } static List reversed(A[] l) { return reversedList(asList(l)); } static String reversed(String s) { return reversedString(s); } static List indexesOf(List l, A a) { return indicesOf(l, a); } static A second(List l) { return get(l, 1); } static A second(Iterable l) { if (l == null) return null; Iterator it = iterator(l); if (!it.hasNext()) return null; it.next(); return it.hasNext() ? it.next() : null; } static A second(A[] bla) { return bla == null || bla.length <= 1 ? null : bla[1]; } static B second(Pair p) { return p == null ? null : p.b; } static B second(T3 t) { return t == null ? null : t.b; } static A second(Producer p) { if (p == null) return null; if (p.next() == null) return null; return p.next(); } static char second(String s) { return charAt(s, 1); } // Return value is index of ")" static int tok_findEndOfForExpression(List tok, int i) { int level = 1; while (i < l(tok)) { String t = tok.get(i); if (eq(t, "(")) ++level; else if (eq(t, ")")) if (--level == 0) return i; i += 2; } return i; } static String trimJoinSubList(List l, int i, int j) { return trim(join(subList(l, i, j))); } static String trimJoinSubList(List l, int i) { return trim(join(subList(l, i))); } static String joinPairWithSpace(Pair p) { return str(p.a) + " " + str(p.b); } // returns index of trailing N token static int tok_endOfExpression(List tok, int i) { return tok_findEndOfExpression(tok, i); } static void tok_insertCasts_noReTok(List tok, int start, int end, String var, String type) { end = min(end, l(tok)); for (int j = start; 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); } static List jfind_all_reversed(List tok, String pat) { return jfindAll_reversed(tok, pat); } static List jfind_all_reversed(List tok, String pat, ITokCondition condition) { return jfindAll_reversed(tok, pat, condition); } static List jfind_all_reversed(List tok, List tokPat) { return jfindAll_reversed(tok, tokPat); } static void tok_insertCasts_reTok(List tok, int start, int end, String var, String type) { tok_insertCasts_noReTok(tok, start, end, var, type); reTok(tok, start, end); } static String toUpper(String s) { return s == null ? null : s.toUpperCase(); } static List toUpper(Collection s) { return allToUpper(s); } static ITokCondition tokCondition(IIntPred condition) { return condition == null ? null : (tok, nIdx) -> condition.get(nIdx); } static String[] codeTokensAsStringArray(List tok) { int n = max(0, (l(tok)-1)/2); String[] out = new String[n]; for (int i = 0; i < n; i++) out[i] = tok.get(i*2+1); return out; } // syntax 1: replace all occurrences of x in l with y static List replaceSublist(List l, List x, List y) { if (x == null) return l; int i = 0; while (true) { i = indexOfSubList(l, x, i); if (i < 0) break; replaceSublist(l, i, i+l(x), y); i += l(y); } return l; } // syntax 2: splice l at fromIndex-toIndex and replace middle part with y static List replaceSublist(List l, int fromIndex, int toIndex, List y) { int n = y.size(), toIndex_new = fromIndex+n; if (toIndex_new < toIndex) { removeSubList(l, toIndex_new, toIndex); copyListPart(y, 0, l, fromIndex, n); } else { copyListPart(y, 0, l, fromIndex, toIndex-fromIndex); if (toIndex_new > toIndex) l.addAll(toIndex, subList(y, toIndex-fromIndex)); } return l; } static List replaceSublist(List l, IntRange r, List y) { return replaceSublist(l, r.start, r.end, y); } static String stefansOS_defaultModuleClassName() { return "AModule"; } static String getType(Object o) { return getClassName(o); } static long getFileSize(String path) { return path == null ? 0 : new File(path).length(); } static long getFileSize(File f) { return f == null ? 0 : f.length(); } static A liftLast(List l) { if (empty(l)) return null; int i = l(l)-1; A a = l.get(i); l.remove(i); return a; } static List liftLast(int n, List l) { int i = l(l)-n; List part = cloneSubList(l, i); removeSubList(l, i); return part; } static int tok_findVarDeclarationName(List tok) { int j = 1; List special = litlist("=", "{", ";"); while (j < tok.size() && !special.contains(tok.get(j))) j += 2; j -= 2; while (j > 1 && litlist("[", "]").contains(tok.get(j))) j -= 2; return j; } static List ourSubList_noRangeCheck(List l, int startIndex, int endIndex) { if (l instanceof RandomAccess) return new RandomAccessSubList(l, startIndex, endIndex); else return new SubList(l, startIndex, endIndex); } static List jfindAll_reversed(List tok, String pat) { return reversed(jfindAll(tok, pat)); } static List jfindAll_reversed(List tok, String pat, ITokCondition condition) { return reversed(jfindAll(tok, pat, condition)); } static List jfindAll_reversed(List tok, List tokPat) { return reversed(jfindAll(tok, tokPat)); } static boolean isIndexedList(List l) { if (l instanceof TokenIndexedList3) return true; return false; } static int strL(String s) { return s == null ? 0 : s.length(); } static int lCharSequence(CharSequence s) { return s == null ? 0 : s.length(); } static boolean emptyString(String s) { return s == null || s.length() == 0; } static boolean containsSubList(List x, List y) { return indexOfSubList(x, y) >= 0; } static boolean containsSubList(List x, A... y) { return indexOfSubList(x, y, 0) >= 0; } static void tok_p_repeatWithSleep(List tok) { int i; while ((i = jfind(tok, "p-repeat with sleep * {")) >= 0) { String seconds = tok.get(i+6); // int or id int idx = findCodeTokens(tok, i, false, "{"); int j = findEndOfBracketPart(tok, idx); tok.set(i+2, " { "); tok.set(j-1, "} }"); reTok(tok, j-1); reTok(tok, i+2); } } // out: func(L tok, int cIndex) -> S // condition: func(L tok, int nIndex) -> S [yeah it's inconsistent] static boolean jreplace_dyn_allowDollarRefs(List tok, String in, IF1 out) { return jreplace_dyn(tok, in, (_tok, cIdx) -> { String replacement = out.get(cIdx); List subList = subList(tok, cIdx-1); // N to N return jreplaceExpandRefs(replacement, subList); }); } // i = last C token of type // returns first C token of type static int tok_scanTypeBackwards(List tok, int i) { if (i < 0) return i; int level = 0; while (i > 0) { String t = tok.get(i); if (isIdentifier(t) && level == 0) { while (eqGet(tok, i-2, ".") && isIdentifier(get(tok, i-4))) i -= 4; return i; } if (eq(t, ">")) ++level; else if (eq(t, "<")) --level; i -= 2; } return i; } // returns index of trailing N token static int scanToEndOfInitializer2(List tok, int i) { int level = 0; while (i < l(tok)) { String t = tok.get(i); if (eqOneOf(t, "(", "{")) ++level; else if (level > 0 && eqOneOf(t, ")", "}")) --level; else if (level == 0 && eqOneOf(tok.get(i), ";", ",", ")", "}")) return i-1; i++; } return i; } static boolean tok_typeIsObject(String type) { return eqOneOf(type, "O", "Object"); } static String applyTranspilationFunction(IVF1> f, String s) { if (f == null) return s; List tok = javaTok(s); f.get(tok); return join(tok); } static List splitAtJavaToken(String s, String splitToken) { return splitByJavaToken(s, splitToken); } static List javaTokC(String s) { if (s == null) return null; int l = s.length(); ArrayList tok = new ArrayList(); 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 && !s.substring(j, Math.min(j+2, l)).equals("*/")); j = Math.min(j+2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } i = j; if (i >= l) break; c = s.charAt(i); d = i+1 >= l ? '\0' : s.charAt(i+1); // scan for non-whitespace if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { if (s.charAt(j) == opener || s.charAt(j) == '\n') { // end at \n to not propagate unclosed string literal errors ++j; break; } else if (s.charAt(j) == '\\' && j+1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || "'".indexOf(s.charAt(j)) >= 0)); // 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+1 < l && !s.substring(j, j+2).equals("]]")); j = Math.min(j+2, l); } else if (c == '[' && d == '=' && i+2 < l && s.charAt(i+2) == '[') { do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]")); j = Math.min(j+3, l); } else ++j; tok.add(javaTok_substringC(s, i, j)); i = j; } return tok; } // "i call you $name" static void tok_transpileIfQuoted_dollarVars(List tok) { jreplace_dyn(tok, "if ", new F2, Integer, String>() { public String get(List tok, Integer cIdx) { try { String pat = unquote(tok.get(cIdx+2)); List vars = new ArrayList(); String pat2 = dollarVarsToStars(pat, vars); int iCurly = cIdx+4; tok_statementToBlock(tok, iCurly); tokAppend_reTok(tok, iCurly, joinWithSpace(mapWithIndexStartingAt1(vars, (i, var) -> ("S " + var + " = $" + i + ";")))); return ("if (match(" + (quote(pat2)) + ", s, m))"); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "S pat = unquote(tok.get(cIdx+2));\r\n new LS vars;\r\n S pat2 = dollarVarsT..."; }}, new TokCondition() { public boolean get(final List tok, final int i) { return containsDollarVars(unquote(tok.get(i+3))); }}); } static boolean startsAndEndsWith(String a, char c) { return startsWith(a, c) && endsWith(a, c) && l(a) >= 2; } static boolean startsAndEndsWith(String a, String b) { return startsWith(a, b) && endsWith(a, b) && l(a) >= l(b)*2; } static CharSequence subCharSequence(CharSequence s, int x) { return subCharSequence(s, x, s == null ? 0 : s.length()); } static CharSequence subCharSequence(CharSequence s, int x, int y) { if (s == null) return null; if (x < 0) x = 0; if (x >= s.length()) return ""; if (y < x) y = x; if (y > s.length()) y = s.length(); return s.subSequence(x, y); } static volatile boolean licensed_yes = true; static boolean licensed() { if (!licensed_yes) return false; ping_okInCleanUp(); return true; } static void licensed_off() { licensed_yes = false; } // i must point at the opening bracket ("<") // index returned is index of closing bracket + 1 static int findEndOfTypeArgs(List cnc, int i) { int j = i+2, level = 1; while (j < cnc.size()) { if (cnc.get(j).equals("<")) ++level; else if (cnc.get(j).equals(">")) --level; if (level == 0) return j+1; ++j; } return cnc.size(); } // i must point at the (possibly imaginary) opening bracket (any of the 3 types, not type parameters) // index returned is index of closing bracket + 1 static int findEndOfBracketPart2(List cnc, int i) { int j = i+2, level = 1; while (j < cnc.size()) { if (eqOneOf(cnc.get(j), "{", "(", "[")) ++level; else if (eqOneOf(cnc.get(j), "}", ")", "]")) --level; if (level == 0) return j+1; ++j; } return cnc.size(); } static ThreadLocal assertVerbose_value = new ThreadLocal(); static void assertVerbose(boolean b) { assertVerbose_value.set(b); } static boolean assertVerbose() { return isTrue(assertVerbose_value.get()); } static A assertEqualsVerbose(Object x, A y) { assertEqualsVerbose((String) null, x, y); return y; } // x = expected, y = actual static A assertEqualsVerbose(String msg, Object x, A y) { if (!eq(x, y)) { throw fail((nempty(msg) ? msg + ": " : "") + "expected: "+ x + ", got: " + y); } else print("OK" + (empty(msg) ? "" : " " + msg) + ": " + /*sfu*/(x)); return y; } static void assertEqualsVerbose(Scorer scorer, Object x, Object y) { assertEqualsVerbose(scorer, "", x, y); } static void assertEqualsVerbose(Scorer scorer, String msg, Object x, Object y) { if (scorer == null) { assertEqualsVerbose(x, y); return; } if (!eq(x, y)) { print(appendColonIfNempty(msg) + y + " != " + x); scorer.add(false); } else { print("OK: " + appendColonIfNempty(msg) + x); scorer.add(true); } } static String nullIfEmpty(String s) { return isEmpty(s) ? null : s; } static Map nullIfEmpty(Map map) { return isEmpty(map) ? null : map; } static List nullIfEmpty(List l) { return isEmpty(l) ? null : l; } static T3 t3(A a, B b, C c) { return new T3(a, b, c); } // new Type var; => Type var = new Type; // new Type<...> var; => Type var = new Type; static void tok_quicknew(List tok) { int i = -1; while ((i = jfind(tok, i+1, "new ")) >= 0) { int j = tok_findEndOfType(tok, i+2); if (isIdentifier(get(tok, j)) && eqGetOneOf(tok, j+2, ";", ",")) { List vars = ll(get(tok, j)); int k = j; while (eqGet(tok, k+2, ",") && isIdentifier(get(tok, k+4))) { k += 4; vars.add(tok.get(k)); } String type = joinSubList(tok, i+2, j-1); if (!contains(type, ".")) type = tok.get(i+2); clearTokens(tok, i, i+2); for (int iVar = 0; iVar < l(vars); iVar++) tokAppend(tok, j+iVar*4, " = new " + type + "()"); reTok(tok, i, k+3); } } } static boolean tokCondition_shortNew(List tok, int i) { return eqOneOf(_get(tok, i), "(", ";", ",", ")", "{", "<"); } static int tok_rightScanModifiers(List tok, int i) { return tok_skipModifiers(tok, i); } static List codeTokensFromSubList(List tok, int i, int j) { List out = new ArrayList(); i = max(i, 0); j = min(j, l(tok)); for (int k = i | 1; k < j; k += 2) out.add(tok.get(k)); return out; } static List listMinus(Collection l, Object... stuff) { if (l == null) return null; List l2 = similarEmptyList(l); Set set = lithashset(stuff); for (Object o : l) if (!set.contains(o)) l2.add(o); return l2; } static int indexOf_between(List l, A a, int startIndex, int endIndex) { if (l == null) return -1; for (int i = startIndex; i < endIndex; i++) if (eq(l.get(i), a)) return i; return -1; } static boolean tok_isSingleTypeArg(List tok, int iOpeningBracket) { int j = tok_findEndOfTypeArg(tok, iOpeningBracket); return neqGet(tok, j, ","); } static int jfind_reversed(List tok, String in) { return rjfind(tok, in); } static int jfind_reversed(List tok, int startIdx, String in) { return rjfind(tok, startIdx, in); } static int jfind_reversed(List tok, int startIdx, int endIndex, String in) { return rjfind(tok, startIdx, endIndex, in); } static int jfind_reversed(List tok, String in, Object condition) { return rjfind(tok, in, condition); } static int jfind_reversed(List tok, int startIdx, String in, Object condition) { return rjfind(tok, startIdx, in, condition); } static int jfind_reversed(List tok, int startIdx, int endIndex, String in, Object condition) { return rjfind(tok, startIdx, endIndex, in, condition); } // assumes you preprocessed tokin static int jfind_reversed(List tok, List tokin) { return rjfind(tok, tokin); } static int jfind_reversed(List tok, int startIdx, List tokin) { return rjfind(tok, startIdx, tokin); } static int jfind_reversed(List tok, int startIdx, List tokin, Object condition) { return rjfind(tok, startIdx, tokin, condition); } static int jfind_reversed(List tok, int startIdx, int endIndex, List tokin, Object condition) { return rjfind(tok, startIdx, endIndex, tokin, condition); } static void removeSubList(List l, int from, int to) { if (l != null) subList(l, from, to).clear(); } static void removeSubList(List l, int from) { if (l != null) subList(l, from).clear(); } static boolean longIsInt(long l) { return l == (int) l; } // returns index of "{" or ";" static int tok_findEndOfMethodHeader(List tok, int i) { i |= 1; int level = 0; while (i < l(tok)) { String t = tok.get(i); if (eq(t, "(")) ++level; else if (eq(t, ")")) --level; else if (level == 0 && eqOneOf(t, "{", ";")) return i; i += 2; } return i; } static void tokReplace(List tok, int i, String t) { put(tok, i, t); } static void tokReplace(List tok, int i, int j, String s) { clearAllTokens(tok, i+1, j); tok.set(i, s); } static void tokSet_withReTok(List tok, int i, String t) { put(tok, i, t); reTok(tok, i, i+1); } static void tokPrepend_withReTok(List tok, int i, String s) { tokPrepend_reTok(tok, i, s); } static int leftScanModifiers(List tok, int i) { return leftScanModifiers(tok, i, getJavaModifiers()); } static int leftScanModifiers(List tok, int i, Collection modifiers) { while (i > 1 && contains(modifiers, tok.get(i-2))) i -= 2; return i; } static void tokSet(List tok, int idx, String token) { tok.set(idx, token); } static int tok_findTokenSkippingCurlyBrackets(List tok, int i, String t) { while (i < l(tok)) { if (eqGet(tok, i, t)) return i; if (eqGet(tok, i, "{")) i = findEndOfBracketPart(tok, i)+1; else i += 2; } return -1; } static void tokAppend_reTok(List tok, int i, String s) { tok.set(i, tok.get(i)+s); reTok(tok, i, i+1); } // returns index of trailing N token static int tok_findEndOfExpression(List tok, int i) { return scanToEndOfInitializer2(tok, i); } // index returned is index of closing bracket or semicolon + 1 (or l(cnc)) static int tok_findEndOfMethodDecl(List tok, int i) { i = tok_findEndOfMethodHeader(tok, i); return findEndOfBlock(tok, i); } static String tok_functionName(List tok) { return get(tok, indexOfOneOf(tok, 0, "(", "{")-2); } // i = C token to the right of type // returns start index of type static int tok_leftScanType(List tok, int i) { while (true) { ping(); // first skip ellipsis if (subListEq(tok, i-6, ".", "", ".", "", ".")) i -= 6; // skip array brackets while (eqGet(tok, i-2, "]") && eqGet(tok, i-4, "[")) i -= 4; // skip type args i = tok_leftScanTypeArgsOpt(tok, i); i -= 2; // should be an identifier // package names / outer classes if (!eqGet(tok, i-2, ".")) break; i -= 2; } return i; } static boolean is(String a, String b) { return false; } // returns range(opening bracket, closing bracket+1) static IntRange tok_findFirstBlock(List tok, int i) { i = indexOf(tok, i, "{"); if (i < 0) return null; return intRange(i, findEndOfBlock(tok, i)); } // i is index of last token of expression // return value is C token static int tok_findBeginningOfJavaXTerm(List tok, int i) { i |= 1; int level = 0; while (i > 1) { String t = get(tok, i); if (eqOneOf(t, "}", ")")) level++; else if (eqOneOf(t, "{", "(")) level--; if (level == 0) { String prev = get(tok, i-2); printVars_str("prev", prev, "t", t); if (eqOneOf(prev, "ret", "return") || isIdentifier(t) && !isIdentifier(prev) && !eq(prev, ".")) { return i; } } i -= 2; } return i; } static String tok_varArgTypeToArray(String s) { return replaceSuffix("...", "[]", s); } static boolean containsJavaToken(String s, String t) { return contains(javaTokC_iterator(s), t); } static boolean containsJavaToken(List tok, String t) { return containsToken(tok, t); } static List jfindAll_reverse(List tok, String pat) { return jfindAll_reversed(tok, pat); } static List jfindAll_reverse(List tok, String pat, ITokCondition condition) { return jfindAll_reversed(tok, pat, condition); } static List jfindAll_reverse(List tok, List tokPat) { return jfindAll_reversed(tok, tokPat); } // return index of code token after type static int tok_endOfType(List tok, int iTypeStart) { return tok_findEndOfType(tok, iTypeStart); } static boolean isJavaModifier(String s) { return getJavaModifiers().contains(s); } static boolean tok_hasBody(List tok, int i) { int j = indexOfAny(tok, i, ";", "{"); return eqGet(tok, j, "{"); } static int tok_leftScanAkas(List tok, int i) { while (eqGet(tok, i-2, "aka") && isIdentifier(get(tok, i-4))) i -= 4; return i; } static int tok_leftScanJavaxModifiers(List tok, int i) { return tok_leftScanCustomModifiers(tok, i, javaxModifiers()); } // returns index of opening < static int tok_leftScanTypeArgsOpt(List tok, int i) { if (!eqGet(tok, i-2, ">")) return i; int level = 0; while (i > 1) { String t = tok.get(i-2); if (eq(t, ">")) level++; else if (eq(t, "<")) { level--; if (level == 0) return i-2; } i -= 2; } return i; } static List tok_parseArgsDeclList2(List tok) { return tok_parseArgsDeclList2(tok, getBracketMapIncludingAngleBrackets(tok)); } static List tok_parseArgsDeclList2(List tok, Map bracketMap) { int argStart = 1; if (eqGet(tok, argStart, ",")) argStart += 2; int i = argStart; List args = new ArrayList(); while (i < l(tok) && neq(get(tok, i), ")")) { Integer j = bracketMap.get(i); if (j != null) { i = j+2; continue; } if (eqGetOneOf(tok, i, ",")) { if (i > argStart) args.add(trimJoinSubList(tok, argStart, i)); argStart = i+2; } i += 2; } if (i > argStart) args.add(trimJoinSubList(tok, argStart, i)); return args; } static Pair tok_typeAndNameOfParam(String src) { return first(tok_typesAndNamesOfParams(javaTok(src))); } static List codeTokens(List tok) { return codeTokensOnly(tok); } static Set javaxVoidAliases_cache; static Set javaxVoidAliases() { if (javaxVoidAliases_cache == null) javaxVoidAliases_cache = javaxVoidAliases_load(); return javaxVoidAliases_cache;} static Set javaxVoidAliases_load() { return litset("void", "svoid"); } static String spaceCombine(Object... l) { return joinNemptiesWithSpace(flattenCollections(ll(l))); } static List replaceElementInSubList(List l, int from, int to, A a, A b) { for (int i = from; i < to; i++) if (eq(l.get(i), a)) l.set(i, b); return l; } // f must return a string static String joinMap(Object f, Iterable l) { return join(map(f, l)); } static String joinMap(Iterable l, Object f) { return joinMap(f, l); } static String joinMap(Iterable l, IF1 f) { return joinMap(f, l); } static String joinMap(A[] l, IF1 f) { return joinMap(f, l); } static String joinMap(IF1 f, Iterable l) { return join(map(f, l)); } static String joinMap(IF1 f, A[] l) { return join(map(f, l)); } static String joinMap(String separator, Map map, IF2 f) { return join(separator, map(map, f)); } static String stringIf(boolean b, String s) { return stringIfTrue(b, s); } static String stringIf(String s, boolean b) { return stringIf(b, s); } static List lmap(IF1 f, Iterable l) { return lambdaMap(f, l); } static List lmap(IF1 f, A[] l) { return lambdaMap(f, l); } static void printTokenContext(List tok, int iFirstToken) { printTokenContext(tok, iFirstToken, iFirstToken); } static void printTokenContext(List tok, int iFirstToken, int iLastToken) { print("Context: " + joinSubList(tok, iFirstToken-5, iLastToken+5)); } // Use like this: printVars_str(+x, +y); // Or: printVars("bla", +x); // Or: printVars bla(+x); static void printVars_str(Object... params) { print(renderVars_str(params)); } // opening bracket to closing bracket + 1 static IntRange tok_findCurlyBody(List tok) { return tok_findCurlyBody(tok, 1); } static IntRange tok_findCurlyBody(List tok, int i) { int idx = findCodeTokens(tok, i, false, "{"); if (idx < 0) return null; int j = findEndOfBracketPart(tok, idx); return intRange(idx, j); } static String stringUnless(boolean b, String s) { return b ? "" : s; } // i must point at the (possibly imaginary) opening bracket (any of the 2 types, not type parameters) // index returned is index of closing bracket + 1 static int tok_findEndOfBracketPart(List cnc, int i) { return findEndOfBracketPart(cnc, i); } static String tok_join(List l, int i, int j) { return joinSubList(l, i, j); } static String tok_join(List l, int i) { return joinSubList(l, i); } static String tok_join(List l, IntRange r) { return joinSubList(l, r); } static String replaceDollarVars(String s, Object... params) { if (empty(params)) return s; Map vars = mapKeys(__60 -> dropDollarPrefix(__60), (Map) litcimap(params)); return replaceDollarVars_dyn(s, var -> strOrNull(vars.get(var))); } static String replaceDollarVars(String s, IF1 f) { return replaceDollarVars_dyn(s, f); } static boolean swicOneOf(String s, String... l) { for (String x : l) if (swic(s, x)) return true; return false; } static boolean swicOneOf(String s, Matches m, String... l) { for (String x : l) if (swic(s, x, m)) return true; return false; } static boolean swic(String a, String b) { return startsWithIgnoreCase(a, b); } static boolean swic(String a, String b, Matches m) { if (!swic(a, b)) return false; m.m = new String[] {substring(a, l(b))}; return true; } static boolean startsWithInteger(String s) { if (empty(s)) return false; int start = 0; if (s.charAt(0) == '-') ++start; return l(s) >= start && isDigit(s.charAt(start)); } static String camelCase(List words) { StringBuilder buf = new StringBuilder(); for (int i = 0; i < l(words); i++) { String word = words.get(i); word = toLower(word); buf.append(i == 0 ? word : firstToUpper(word)); } return str(buf); } static String camelCase(String words) { return camelCase(words(words)); } // from https://www.rgagnon.com/javadetails/java-0426.html static String numberToEnglish(long number) { return numberToEnglish_EnglishNumberToWords.convert(number); } static class numberToEnglish_EnglishNumberToWords { private static final String[] tensNames = { "", " ten", " twenty", " thirty", " forty", " fifty", " sixty", " seventy", " eighty", " ninety" }; private static final String[] numNames = { "", " one", " two", " three", " four", " five", " six", " seven", " eight", " nine", " ten", " eleven", " twelve", " thirteen", " fourteen", " fifteen", " sixteen", " seventeen", " eighteen", " nineteen" }; private static String convertLessThanOneThousand(int number) { String soFar; if (number % 100 < 20){ soFar = numNames[number % 100]; number /= 100; } else { soFar = numNames[number % 10]; number /= 10; soFar = tensNames[number % 10] + soFar; number /= 10; } if (number == 0) return soFar; return numNames[number] + " hundred" + soFar; } public static String convert(long number) { // 0 to 999 999 999 999 if (number == 0) { return "zero"; } String snumber = Long.toString(number); // pad with "0" String mask = "000000000000"; DecimalFormat df = new DecimalFormat(mask); snumber = df.format(number); // XXXnnnnnnnnn int billions = Integer.parseInt(snumber.substring(0,3)); // nnnXXXnnnnnn int millions = Integer.parseInt(snumber.substring(3,6)); // nnnnnnXXXnnn int hundredThousands = Integer.parseInt(snumber.substring(6,9)); // nnnnnnnnnXXX int thousands = Integer.parseInt(snumber.substring(9,12)); String tradBillions; switch (billions) { case 0: tradBillions = ""; break; case 1 : tradBillions = convertLessThanOneThousand(billions) + " billion "; break; default : tradBillions = convertLessThanOneThousand(billions) + " billion "; } String result = tradBillions; String tradMillions; switch (millions) { case 0: tradMillions = ""; break; case 1 : tradMillions = convertLessThanOneThousand(millions) + " million "; break; default : tradMillions = convertLessThanOneThousand(millions) + " million "; } result = result + tradMillions; String tradHundredThousands; switch (hundredThousands) { case 0: tradHundredThousands = ""; break; case 1 : tradHundredThousands = "one thousand "; break; default : tradHundredThousands = convertLessThanOneThousand(hundredThousands) + " thousand "; } result = result + tradHundredThousands; String tradThousand; tradThousand = convertLessThanOneThousand(thousands); result = result + tradThousand; // remove extra spaces! return result.replaceAll("^\\s+", "").replaceAll("\\b\\s{2,}\\b", " "); } } // Return value is index of semicolon/curly brace+1 static int tok_endOfStatement(List tok, int i) { return tok_findEndOfStatement(tok, i); } static List jfindAll_reversed_any(List tok, String... patterns) { TreeSet set = new TreeSet(); // startIndex for (String pat : patterns) set.addAll(jfindAll(tok, pat)); return reversedList(set); } // i must point at the opening bracket ("<") static String tok_scanTypeArgWithoutBrackets(List tok, int i) { return joinSubList(tok, i+2, tok_findEndOfAngleBracketPart(tok, i)-1); } // i must point at the (possibly imaginary) opening bracket (any of the 2 types, not type parameters) // index returned is index of closing bracket + 1 static int tok_endOfBracketPart(List cnc, int i) { return findEndOfBracketPart(cnc, i); } static int jfind_upTo(List tok, int startIdx, int endIdx, String in) { List tok2 = subList(tok, 0, endIdx); return jfind(tok2, startIdx, in); } static interface replaceKeywordPlusQuotedBlock_dyn_IReplacer { String[] get(List tok, int iOpening); } // finds " {" // func: tok, iKeyword -> S[] {beg, end} static List replaceKeywordPlusQuotedBlock_dyn(List tok, String keyword, replaceKeywordPlusQuotedBlock_dyn_IReplacer f) { for (int i = 0; i < 1000; i++) { int idx = jfind(tok, keyword + " {"); if (idx < 0) break; int j = findEndOfBracketPart(tok, idx+4); String[] be = f.get(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 String[] stringArray(String... strings) { return strings; } static boolean startsWithSpaceEtc(String s) { return isSpaceEtc(charAt(s, 0)); } static boolean tok_isBeginningOfStatement(List tok, int i) { String prev = get(tok, i-2); return eqOneOf(prev, "{", ";", "}", null); } static void tok_gettableFields(List tok) { Tok_GettableFields t = new Tok_GettableFields(); t.run(tok); } static void tok_unifyKeywords(List tok, Collection keywords, String replacement) { for (var kw : keywords) if (!eq(kw, replacement)) jreplace(tok, kw, replacement); } static List remutableKeywords_cache; static List remutableKeywords() { if (remutableKeywords_cache == null) remutableKeywords_cache = remutableKeywords_load(); return remutableKeywords_cache;} static List remutableKeywords_load() { return ll( "reImmutable", "reimmutable", "remutable", "reMutable" ); } static List jrfindAll_any(List tok, String... patterns) { return jfindAll_reversed_any(tok, patterns); } // binary legacy syntax static String formatFunctionCall(String fname, Object... args) { return formatFunctionCall((Object) fname, args); } static String formatFunctionCall(Object fname, Object... args) { return fname + "(" + joinWithComma(allToString(args)) + ")"; } static String formatFunctionCall(String fname, Iterable args) { return formatFunctionCall((Object) fname, args); } static String formatFunctionCall(Object fname, Iterable args) { return formatFunctionCall(fname, toObjectArray(args)); } static String commaCombine(Object... l) { return joinNemptiesWithComma(flattenCollectionsAndArrays(l)); } static void tokClear_reTok(List tok, int i, int j) { clearTokens_reTok(tok, i, j); } // only one multi-type argument per declaration for now // also allows only one combo right now (File/S with newFile) // example: // sS loadTextFile(File/S file) { ... } static void tok_expandMultiTypeArgument(List tok, int iArgStart, int iArgEnd, // start and end of argument String argName, String mainType, String altType, String conversionExpr) { iArgEnd |= 1; int iOpening = lastIndexOf(tok, iArgStart, "("); // TODO: brackets int iClosing = findEndOfBracketPart2(tok, iOpening)-1; // function name int iName = iOpening-2; String name = assertIdentifier(get(tok, iName)); int iType = tok_leftScanType(tok, iName); int iStart = tok_leftScanTypeArgsOpt(tok, iType); iStart = leftScanModifiers(tok, iStart); //print("Found method head: " + joinSubList(tok, iStart, iClosing+1)); List _args1 = subList(tok, iOpening+1, iArgStart); List _args2 = subList(tok, iArgEnd&~1, iClosing); List args1 = tok_parseArgsDeclList2(_args1); List args2 = tok_parseArgsDeclList2(_args2); List type = subList(tok, iType-1, iName); boolean isVoid = containsOneOf(codeTokens(type), javaxVoidAliases()); //printVars(+expr, +_args1, +_args2, +args1, +args2, +type, +isVoid); String altHead = joinSubList(tok, iStart, iOpening+1) + joinWithComma(concatLists( args1, ll(altType + " " + argName), args2)) + ")"; if (tok_isSingleIdentifier(conversionExpr)) conversionExpr += ("(" + argName + ")"); replaceTokens_reTok(tok, iArgStart|1, iArgEnd, mainType + " " + argName); tokPrepend_reTok(tok, iStart, altHead + " { " + (isVoid ? "" : "return ") + name + "(" + joinWithComma(concatLists( map(__61 -> tok_lastIdentifier(__61), args1), ll(conversionExpr), map(__62 -> tok_lastIdentifier(__62), args2))) + "); }\n"); } static void tok_expandMultiTypeArgument_v3(List tok, int iArgStart, int iArgEnd, // start and end of argument String argName, String mainType, List> alts) { iArgEnd |= 1; int iOpening = lastIndexOf(tok, iArgStart, "("); // TODO: brackets int iClosing = findEndOfBracketPart2(tok, iOpening)-1; // function name int iName = iOpening-2; String name = assertIdentifier(get(tok, iName)); int iType = tok_leftScanType(tok, iName); int iStart = tok_leftScanTypeArgsOpt(tok, iType); iStart = leftScanModifiers(tok, iStart); //print("Found method head: " + joinSubList(tok, iStart, iClosing+1)); List _args1 = subList(tok, iOpening+1, iArgStart); List _args2 = subList(tok, iArgEnd&~1, iClosing); List args1 = tok_parseArgsDeclList2(_args1); List args2 = tok_parseArgsDeclList2(_args2); List type = subList(tok, iType-1, iName); boolean isVoid = containsOneOf(codeTokens(type), javaxVoidAliases()); //printVars(+expr, +_args1, +_args2, +args1, +args2, +type, +isVoid); List altFunctions = new ArrayList(); for (Pair __0 : alts) { String altDecl = pairA(__0); String conversionExpr = pairB(__0); if (tok_isSingleIdentifier(altDecl)) altDecl += (" " + argName); if (tok_isSingleIdentifier(conversionExpr)) conversionExpr += ("(" + argName + ")"); String altHead = joinSubList(tok, iStart, iOpening+1) + joinWithComma(concatLists( args1, ll(altDecl), args2)) + ")"; altFunctions.add(altHead + " { " + (isVoid ? "" : "return ") + name + "(" + joinWithComma(concatLists( map(__63 -> tok_lastIdentifier(__63), args1), ll(conversionExpr), map(__64 -> tok_lastIdentifier(__64), args2))) + "); }\n"); } replaceTokens_reTok(tok, iArgStart|1, iArgEnd, mainType + " " + argName); tokPrepend_reTok(tok, iStart, lines(altFunctions)); } static void tok_expandMultiTypeArgument_v2(List tok, int iArgStart, int iArgEnd, // start and end of argument String argName, String mainType, List> alts) { iArgEnd |= 1; int iOpening = lastIndexOf(tok, iArgStart, "("); // TODO: brackets int iClosing = findEndOfBracketPart2(tok, iOpening)-1; // function name int iName = iOpening-2; String name = assertIdentifier(get(tok, iName)); int iType = tok_leftScanType(tok, iName); int iStart = tok_leftScanTypeArgsOpt(tok, iType); iStart = leftScanModifiers(tok, iStart); //print("Found method head: " + joinSubList(tok, iStart, iClosing+1)); List _args1 = subList(tok, iOpening+1, iArgStart); List _args2 = subList(tok, iArgEnd&~1, iClosing); List args1 = tok_parseArgsDeclList2(_args1); List args2 = tok_parseArgsDeclList2(_args2); List type = subList(tok, iType-1, iName); boolean isVoid = containsOneOf(codeTokens(type), javaxVoidAliases()); //printVars(+expr, +_args1, +_args2, +args1, +args2, +type, +isVoid); List altFunctions = new ArrayList(); for (Pair __0 : alts) { String altType = pairA(__0); String conversionExpr = pairB(__0); if (tok_isSingleIdentifier(conversionExpr)) conversionExpr += ("(" + argName + ")"); String altHead = joinSubList(tok, iStart, iOpening+1) + joinWithComma(concatLists( args1, ll(altType + " " + argName), args2)) + ")"; altFunctions.add(altHead + " { " + (isVoid ? "" : "return ") + name + "(" + joinWithComma(concatLists( map(__65 -> tok_lastIdentifier(__65), args1), ll(conversionExpr), map(__66 -> tok_lastIdentifier(__66), args2))) + "); }\n"); } replaceTokens_reTok(tok, iArgStart|1, iArgEnd, mainType + " " + argName); tokPrepend_reTok(tok, iStart, lines(altFunctions)); } static TokenRange jfind_range(List tok, String in) { return jfind_range(tok, 1, in); } static TokenRange jfind_range(List tok, int startIdx, String in) { return jfind_range(tok, startIdx, in, null); } static TokenRange jfind_range(List tok, String in, Object condition) { return jfind_range(tok, 1, in, condition); } static TokenRange jfind_range(List tok, int startIdx, String in, Object condition) { return jfind_range(tok, startIdx, javaTokForJFind_array(in), condition); } // assumes you preprocessed tokin static TokenRange jfind_range(List tok, List tokin) { return jfind_range(tok, 1, tokin); } static TokenRange jfind_range(List tok, int startIdx, List tokin) { return jfind_range(tok, startIdx, tokin, null); } static TokenRange jfind_range(List tok, int startIdx, List tokin, Object condition) { return jfind_range(tok, startIdx, codeTokensAsStringArray(tokin), condition); } static TokenRange jfind_range(List tok, int startIdx, String[] tokinC, Object condition) { int i = findCodeTokens(tok, startIdx, false, tokinC, condition); return i < 0 ? null : new TokenRange(i-1, i+l(tokinC)*2); } static interface replaceKeywordBlock_dyn_IReplacer { String[] get(List tok, int iOpening, int iClosing); } static List replaceKeywordBlock_dyn(List tok, String keyword, replaceKeywordBlock_dyn_IReplacer func) { return replaceKeywordBlock_dyn("{", tok, keyword, func); } static List replaceKeywordBlock_dyn(String bracket, List tok, String keyword, replaceKeywordBlock_dyn_IReplacer func) { for (int i = 0; i < 1000; i++) { int idx = findCodeTokens(tok, keyword, bracket); if (idx < 0) break; int j = findEndOfBracketPart(tok, idx+2); String[] be = func == null ? null : func.get(tok, idx+2, j-1); tok.set(idx, unnull(first(be))); tok.set(idx+1, " "); tok.set(idx+2, ""); tok.set(j-1, unnull(second(be))); reTok(tok, idx, j); } return tok; } // We'd be really fancy if we filtered out return statements in all // inner blocks. static boolean containsReturnWithArgument(List tok) { for (int i = 1; i+2 < l(tok); i += 2) { String t = tok.get(i); if (eqOneOf(t, "ret", "return") && neqOneOf(tok.get(i+2), ";", "if", "unless", "with")) return true; // skip embedded functions & classes if (eqOneOf(t, "embedded", "class") && isIdentifier(get(tok, i+2)) // skip anonymous classes || eq(t, "(") && eqGet(tok, i+2, ")") && eqGet(tok, i+4, "{")) i = tok_findEndOfMethodDecl(tok, i)-1; // this might just work for classes too // skip runnables / lambdas if (eqOneOf(t, "r", ">") && eqGet(tok, i+2, "{")) i = findEndOfBlock(tok, i+2)-1; } return false; } static boolean containsReturnWithArgument(String code) { return containsReturnWithArgument(javaTok(code)); } // result might not be modifiable static String[] litstringarray(String... data) { return data; } static Object javaEval(String code) { return evalJava(code); } static boolean setAdd(Collection c, A a) { if (c == null || c.contains(a)) return false; c.add(a); return true; } static A popLast(List l) { return liftLast(l); } static List popLast(int n, List l) { return liftLast(n, l); } static String className(Object o) { return getClassName(o); } static String actualMCDollar() { return actualMC().getName() + "$"; } static boolean isJavaXClassName(String s) { return isJavaXClassName(s, "main$"); } static boolean isJavaXClassName(String s, String mcDollar) { return startsWithOneOf(s, mcDollar, "main$", "loadableUtils.", "x30", "userCode."); } static void quoteToPrintWriter(String s, PrintWriter out) { if (s == null) { out.print("null"); return; } out.print('"'); int l = s.length(); for (int i = 0; i < l; i++) { char c = s.charAt(i); if (c == '\\' || c == '"') { out.print('\\'); out.print(c); } else if (c == '\r') out.print("\\r"); else if (c == '\n') out.print("\\n"); else if (c == '\0') out.print("\\0"); else out.print(c); } out.print('"'); } static boolean isSubClassOf(Class a, Class b) { return isSubclass(a, b); } static boolean startsWithDigit(String s) { return nempty(s) && isDigit(s.charAt(0)); } static boolean isSyntheticOrAnonymous(Class c) { return c != null && (c.isSynthetic() || isAnonymousClassName(c.getName())); } // This is a bit rough... finds static and non-static methods. static Method findMethodNamed(Object obj, String method) { if (obj == null) return null; if (obj instanceof Class) return findMethodNamed((Class) obj, method); return findMethodNamed(obj.getClass(), method); } static Method findMethodNamed(Class c, String method) { while (c != null) { for (Method m : c.getDeclaredMethods()) if (m.getName().equals(method)) { makeAccessible(m); return m; } c = c.getSuperclass(); } return null; } // keeps package names for dynamic code (package dyn.*) static String shortDynClassNameForStructure(Object o) { if (o instanceof DynamicObject && ((DynamicObject) o).className != null) return ((DynamicObject) o).className; if (o == null) return null; Class c = o instanceof Class ? (Class) o : o.getClass(); String name = c.getName(); return name.startsWith("dyn.") ? classNameToVM(name) : shortenClassName(name); } static boolean isPersistableClass(Class c) { String name = c.getName(); if (isSubtypeOf(c, TransientObject.class)) return false; if (isAnonymousClassName(name)) return false; if (isBoxedType(c)) return true; if (isArrayType(c)) return true; if (c == Class.class || c == String.class || c == File.class || c == Color.class) return true; if (name.startsWith("java.util.Collections$Synchronized")) return true; if (hasThisDollarFields(c)) return hasSingleArgumentConstructor(c); else return getDefaultConstructor(c) != null; } static A printStackTrace(A e) { // we go to system.out now - system.err is nonsense if (e != null) print(getStackTrace(e)); return e; } static void printStackTrace() { printStackTrace(new Throwable()); } static void printStackTrace(String msg) { printStackTrace(new Throwable(msg)); } static void printStackTrace(String msg, Throwable e) { printStackTrace(new Throwable(msg, e)); } static Constructor getDefaultConstructor(Class c) { if (c != null) for (Constructor m : getDeclaredConstructors_cached(c)) if (empty(m.getParameterTypes())) return m; return null; } static Object invokeConstructor(Constructor m, Object... args) { try { makeAccessible(m); return m.newInstance(args); } catch (Exception __e) { throw rethrow(__e); } } static int countDots(String s) { int n = l(s), count = 0; for (int i = 0; i < n; i++) if (s.charAt(i) == '.') ++count; return count; } static boolean isCIMap_gen(Map map) { return map instanceof TreeMap && className(((TreeMap) map).comparator()).contains("CIComp"); } // works for both java.util-wrapped maps as well as our own static Map unwrapSynchronizedMap(Map map) { if (eqOneOf(shortClassName(map), "SynchronizedMap", "SynchronizedSortedMap", "SynchronizedNavigableMap")) return (Map) get_raw(map, "m"); return map; } static Map cloneMap(Map map) { if (map == null) return new HashMap(); // assume mutex is equal to map synchronized(map) { return map instanceof TreeMap ? new TreeMap((TreeMap) map) // copies comparator : map instanceof LinkedHashMap ? new LinkedHashMap(map) : new HashMap(map); } } static List cloneMap(Iterable l, IF1 f) { List x = emptyList(l); if (l != null) for (A o : cloneList(l)) x.add(f.get(o)); return x; } // Use like this: renderVars(+x, +y) // Or like this: renderVars SomeID(+x, +y) static String renderVars(Object... params) { return renderVars_str(params); } static boolean isCISet_gen(Iterable l) { return l instanceof TreeSet && className(((TreeSet) l).comparator()).contains("CIComp"); } static List unwrapSynchronizedList(List l) { if (eqOneOf(className(l), "java.util.Collections$SynchronizedList", "java.util.Collections$SynchronizedRandomAccessList")) return (List) get_raw(l, "list"); return l; } static String quoteCharacter(char c) { if (c == '\'') return "'\\''"; if (c == '\\') return "'\\\\'"; if (c == '\r') return "'\\r'"; if (c == '\n') return "'\\n'"; if (c == '\t') return "'\\t'"; return "'" + c + "'"; } public static String bytesToHex(byte[] bytes) { return bytesToHex(bytes, 0, bytes.length); } public static String bytesToHex(byte[] bytes, int ofs, int len) { StringBuilder stringBuilder = new StringBuilder(len*2); for (int i = 0; i < len; i++) { String s = "0" + Integer.toHexString(bytes[ofs+i]); stringBuilder.append(s.substring(s.length()-2, s.length())); } return stringBuilder.toString(); } static String boolArrayToHex(boolean[] a) { return bytesToHex(boolArrayToBytes(a)); } static String shortArrayToHex_bigEndian(short[] a) { return bytesToHex(byteArrayFromShorts_bigEndian(a)); } static String longArrayToHex_bigEndian(long[] a) { return bytesToHex(byteArrayFromLongs_bigEndian(a)); } static Pair arrayTypeAndDimensions(Object o) { return arrayTypeAndDimensions(_getClass(o)); } static Pair arrayTypeAndDimensions(Class c) { if (c == null || !c.isArray()) return null; Class elem = c.getComponentType(); if (elem.isArray()) return mapPairB(arrayTypeAndDimensions(elem), dim -> dim+1); return pair(elem, 1); } static Iterator emptyIterator() { return Collections.emptyIterator(); } static int stdcompare(Number a, Number b) { return cmp(a, b); } static int stdcompare(String a, String b) { return cmp(a, b); } static int stdcompare(long a, long b) { return a < b ? -1 : a > b ? 1 : 0; } static int stdcompare(Object a, Object b) { return cmp(a, b); } static Map getDeclaredFields_cache = newDangerousWeakHashMap(); static Field[] getDeclaredFields_cached(Class c) { Field[] fields; synchronized(getDeclaredFields_cache) { fields = getDeclaredFields_cache.get(c); if (fields == null) { getDeclaredFields_cache.put(c, fields = c.getDeclaredFields()); for (Field f : fields) makeAccessible(f); } } return fields; } static Object fieldGet(Field f, Object o) { try { return f == null ? null : f.get(o); } catch (Exception __e) { throw rethrow(__e); } } static Method findInstanceMethod(Class c, String method, Object... args) { while (c != null) { for (Method m : c.getDeclaredMethods()) if (m.getName().equals(method) && findMethod_checkArgs(m, args, false)) return m; c = c.getSuperclass(); } return null; } static Set fieldObjectsInFieldOrder(Class c, Set fields) { try { var byName = mapToKey(f -> f.getName(), fields); LinkedHashSet out = new LinkedHashSet(); for (String name : unnullForIteration(getFieldOrder(c))) { Field f = byName.get(name); if (f != null) { byName.remove(name); out.add(f); } } addAll(out, fields); return out; } catch (Throwable __0) { printStackTrace(__0); return fields; } } static Map putAll(Map a, Map b) { if (a != null && b != null) a.putAll(b); return a; } static MultiMap putAll(MultiMap a, Map b) { if (a != null) a.putAll((Map) b); return a; } static Map putAll(Map a, Object... b) { if (a != null) litmap_impl(a, b); return a; } // set needs to be a ciSet static Set startingWithIC_navigableSubSet(String prefix, NavigableSet set) { if (empty(prefix) || empty(set)) return set; return set.subSet(prefix, true, lexicographicallyNextString(prefix), false); } static String dropPrefixIC(String prefix, String s) { return s == null ? null : swic(s, prefix) ? s.substring(l(prefix)) : s; } static List replace(List l, A a, A b) { for (int i = 0; i < l(l); i++) if (eq(l.get(i), a)) l.set(i, b); return l; } static List replace(A a, A b, List l) { return replace(l, a, b); } // replace all occurrences of a in s with b static String replace(String s, String a, String b) { return s == null ? null : a == null || b == null ? s : s.replace(a, b); } static String replace(String s, char a, char b) { return s == null ? null : s.replace(a, b); } static String unquoteSingleOrDoubleQuotes(String s) { if (s == null) return null; if (s.length() > 1) { char c = s.charAt(0); if (c == '\"' || c == '\'') { int l = endsWith(s, c) ? s.length()-1 : s.length(); StringBuilder sb = new StringBuilder(l-1); for (int i = 1; i < l; i++) { char ch = s.charAt(i); if (ch == '\\') { char nextChar = (i == l - 1) ? '\\' : s.charAt(i + 1); // Octal escape? if (nextChar >= '0' && nextChar <= '7') { String code = "" + nextChar; i++; if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') { code += s.charAt(i + 1); i++; if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') { code += s.charAt(i + 1); i++; } } sb.append((char) Integer.parseInt(code, 8)); continue; } switch (nextChar) { case '\"': ch = '\"'; break; case '\\': ch = '\\'; break; case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case '\'': ch = '\''; break; // Hex Unicode: u???? case 'u': if (i >= l - 5) { ch = 'u'; break; } int code = Integer.parseInt( "" + s.charAt(i + 2) + s.charAt(i + 3) + s.charAt(i + 4) + s.charAt(i + 5), 16); sb.append(Character.toChars(code)); i += 5; continue; default: ch = nextChar; // added by Stefan } i++; } sb.append(ch); } return sb.toString(); } } return s; // not quoted - return original } // custom mainClass only works with hotwire_here static Class hotwire(String src) { return hotwire(src, __1 -> mainClassNameForClassLoader(__1)); } static Class hotwire(String src, IF1 calculateMainClass) { assertFalse(_inCore()); Class j = getJavaX(); if (isAndroid()) { synchronized(j) { // hopefully this goes well... List libraries = new ArrayList(); File srcDir = (File) call(j, "transpileMain", src, libraries); if (srcDir == null) throw fail("transpileMain returned null (src=" + quote(src) + ")"); Object androidContext = get(j, "androidContext"); return (Class) call(j, "loadx2android", srcDir, src); } } else { Class c = (Class) (call(j, "hotwire", src)); hotwire_copyOver(c); return c; } } static A callMain(A c, String... args) { callOpt(c, "main", new Object[] {args}); return c; } static void callMain() { callMain(mc()); } static HashMap litmap(Object... x) { HashMap map = new HashMap(); litmap_impl(map, x); return map; } static void litmap_impl(Map map, Object... x) { if (x != null) for (int i = 0; i < x.length-1; i += 2) if (x[i+1] != null) map.put(x[i], x[i+1]); } static String joinCodeTokens(List tok) { StringBuilder buf = new StringBuilder(); int n = tok.size(); for (int i = 1; i < n; i += 2) buf.append(tok.get(i)); return buf.toString(); } static String dropSuffix(String suffix, String s) { return nempty(suffix) && endsWith(s, suffix) ? s.substring(0, l(s)-l(suffix)) : s; } static boolean containsNewLine(String s) { return contains(s, '\n'); // screw \r, nobody needs it } static HashMap mapFromTokens(String s) { List tok = javaTok(s); HashMap map = new HashMap(); for (int i = 1; i+2 < l(tok); i += 4) map.put(tok.get(i), tok.get(i+2)); return map; } static List newSubList(List l, int startIndex, int endIndex) { return cloneList(subList(l, startIndex, endIndex)); } static List newSubList(List l, int startIndex) { return cloneList(subList(l, startIndex)); } static boolean tok_shouldAddReturn(List tok) { String lastToken = get(tok, l(tok)-2); if (eqOneOf(lastToken, ";", null)) return false; if (eq(lastToken, "}")) { int i = findBeginningOfBlock(tok, l(tok)-2); return eqGet(tok, i-4, "-") && eqGet(tok, i-3, "") && eqGet(tok, i-2, ">"); // it's a lambda definition } return true; } static boolean tok_shouldAddReturn(String s) { return tok_shouldAddReturn(javaTok(s)); } // i must point at the (possibly imaginary) closing bracket (any of the 2 types, not type parameters) // index returned is index of opening bracket static int findBeginningOfBracketPart(List cnc, int i) { int j = i-2, level = 1; while (j > 0) { if (eqOneOf(cnc.get(j), "}", ")")) ++level; else if (eqOneOf(cnc.get(j), "{", "(")) --level; if (level == 0) return j; j -= 2; } return -1; } // iOpening, iClosing = position of () brackets static List tok_makeArgumentsFinal(List tok, int iOpening, int iClosing) { Map bracketMap = getBracketMapIncludingAngleBrackets(tok, iOpening+2, iClosing); boolean change = false; int i = iOpening+2; while (i < iClosing) { if (neqGet(tok, i, "final")) { tokPrepend(tok, i, "final "); change = true; } while (i < iClosing && neqGet(tok, i, ",")) i = or(bracketMap.get(i), i)+2; i += 2; } if (change) reTok(tok, iOpening, iClosing); return tok; } static A[] dropLast(A[] a) { return dropLast(a, 1); } static A[] dropLast(A[] a, int n) { if (a == null) return null; n = Math.min(n, a.length); A[] b = arrayOfSameType(a, a.length-n); System.arraycopy(a, 0, b, 0, b.length); return b; } static List dropLast(List l) { return subList(l, 0, l(l)-1); } static List dropLast(int n, List l) { return subList(l, 0, l(l)-n); } static List dropLast(Iterable l) { return dropLast(asList(l)); } static String dropLast(String s) { return substring(s, 0, l(s)-1); } static String dropLast(String s, int n) { return substring(s, 0, l(s)-n); } static String dropLast(int n, String s) { return dropLast(s, n); } static boolean isLongConstant(String s) { if (!s.endsWith("L")) return false; s = s.substring(0, l(s)-1); return isInteger(s); } static List wrapAsList(A[] a) { return wrapArrayAsList(a); } static boolean isIdentifier_quick(String s) { return startsWithJavaIdentifierStart(s); } // i points at the identifier you think may be a standard function invocation // This function tries to distinguish those invocations from method declarations. // these prefix tokens mark a non-invocation (TODO: expand) static Set tok_isMethodDeclarationNotSFInvocation_pre = lithashset( ".", "void", "S", "String", "int", "bool", "boolean", "A", "Object", "O", "]", "double", "float", "short", "char", "long"); static boolean tok_isMethodDeclarationNotSFInvocation(List tok, int i, String mainClassName, IF1 isKnownClassName) { if (i == 1) return false; String prev = tok.get(i-2); if (eq(prev, ".") && eqGet(tok, i-4, mainClassName)) return false; if (tok_isMethodDeclarationNotSFInvocation_pre.contains(prev)) return true; if (isKnownClassName != null && isKnownClassName.get(prev)) return true; return false; } static String lineAroundToken(List tok, int tokenIndex) { int i = tokenIndex, j = tokenIndex; while (i > 1 && !containsNewLine(get(tok, i-1))) i -= 2; while (j+2 < l(tok) && !containsNewLine(get(tok, j+1))) j += 2; return afterLineBreak(get(tok, i-1)) + joinSubList(tok, i, j+1) + beforeLineBreak(get(tok, j+1)); } static Set asSet(Object[] array) { HashSet set = new HashSet(); for (Object o : array) if (o != null) set.add(o); return set; } static Set asSet(String[] array) { TreeSet set = new TreeSet(); for (String o : array) if (o != null) set.add(o); return set; } static Set asSet(Iterable l) { if (l instanceof Set) return (Set) l; HashSet set = new HashSet(); for (A o : unnull(l)) if (o != null) set.add(o); return set; } static Set similarEmptySet(Iterable m) { if (m instanceof TreeSet) return new TreeSet(((TreeSet) m).comparator()); if (m instanceof LinkedHashSet) return new LinkedHashSet(); return new HashSet(); } static Set similarEmptySet(Map m) { if (m instanceof TreeMap) return new TreeSet(((TreeMap) m).comparator()); if (m instanceof LinkedHashMap) return new LinkedHashSet(); return new HashSet(); } static List findFunctionDefsAtCurlyLevel_indexed(int targetCurlyLevel, IContentsIndexedList2 tok) { List functions = new ArrayList(); OrderedMultiIterator multiIterator = new OrderedMultiIterator(); for (var keyword : findFunctionDefs_keywords()) multiIterator.add(tok.indicesOf_treeSetOfHasIndex(keyword)); multiIterator.add(tok.indicesOf_treeSetOfHasIndex("{")); multiIterator.add(tok.indicesOf_treeSetOfHasIndex("}")); multiIterator.add(tok.indicesOf_treeSetOfHasIndex("meta")); int curlyLevel = 0; BitSet ignore = new BitSet(); while (multiIterator.hasNext()) { HasIndex idx = multiIterator.next(); int i = idx.get(); if (ignore.get(i)) continue; String t = tok.get(i); // Account for meta-for (don't change curly level) if (eq(t, "meta")) { if (eqSubList(tok, i+1, "", "-", "", "for")) { var r = tok_findFirstBlock(tok, i); ignore.set(r.start); ignore.set(r.end-1); } } else if (eq(t, "{")) ++curlyLevel; else if (eq(t, "}")) --curlyLevel; else // it's a function keyword if (curlyLevel == targetCurlyLevel) findFunctionDefs_step(tok, i, functions); } return functions; } static Set findFunctionDefs_keywords_cache; static Set findFunctionDefs_keywords() { if (findFunctionDefs_keywords_cache == null) findFunctionDefs_keywords_cache = findFunctionDefs_keywords_load(); return findFunctionDefs_keywords_cache;} static Set findFunctionDefs_keywords_load() { return new HashSet(splitAtSpace("static svoid ssvoid ssynchronized sbool sS sO sL")); } static boolean eqSubList(List l, List pat, int i) { return subListEquals(l, pat, i); } static boolean eqSubList(List l, int i, A... pat) { return subListEquals(l, i, pat); } static int curlyLevel(String token) { if (eq(token, "{")) return 1; if (eq(token, "}")) return -1; return 0; } static List findFunctionDefs(String s) { return findFunctionDefs(javaTok(s)); } static List findFunctionDefs(List tok) { List functions = new ArrayList(); var keywords = findFunctionDefs_keywords(); if (tok instanceof IContentsIndexedList2) { for (String keyword : keywords) { TreeSet indices = ((IContentsIndexedList2) tok).indicesOf_treeSetOfHasIndex(keyword); if (indices != null) for (HasIndex i : indices) findFunctionDefs_step(tok, i.idx, functions); } } else { int n = l(tok); for (int i = 1; i < n; i += 2) if (keywords.contains(tok.get(i))) findFunctionDefs_step(tok, i, functions); } return functions; } // we found one of the keywords listed above at token i // now scan forward for a function definition static void findFunctionDefs_step(List tok, int i, List functions) { String t = tok.get(i); int j = i+2, n = l(tok); while (j < n && !findFunctionsDefs_checkToken(tok.get(j))) j += 2; if (isIdentifier(tok.get(j-2)) && eqGet(tok, j, "(") || eqGet(tok, j, "{") && eq(t, "svoid")) functions.add(tok.get(j-2)); } static boolean findFunctionsDefs_checkToken(String t) { if (t.length() != 1) return false; char c = t.charAt(0); return c == ';' || c == '=' || c == '(' || c == '{' /*|| c == '#' XXX*/; } // usually L static String fromLines(Iterable lines) { StringBuilder buf = new StringBuilder(); if (lines != null) for (Object line : lines) buf.append(str(line)).append('\n'); return buf.toString(); } static String fromLines(String... lines) { return fromLines(asList(lines)); } static IterableIterator toLines(File f) { return linesFromFile(f); } static List toLines(String s) { List lines = new ArrayList(); if (s == null) return lines; int start = 0; while (true) { int i = toLines_nextLineBreak(s, start); if (i < 0) { if (s.length() > start) lines.add(s.substring(start)); break; } lines.add(s.substring(start, i)); if (s.charAt(i) == '\r' && i+1 < s.length() && s.charAt(i+1) == '\n') i += 2; else ++i; start = i; } return lines; } static int toLines_nextLineBreak(String s, int start) { int n = s.length(); for (int i = start; i < n; i++) { char c = s.charAt(i); if (c == '\r' || c == '\n') return i; } return -1; } static List mapToLines(Map map) { List l = new ArrayList(); for (Object key : keys(map)) l.add(str(key) + " = " + str(map.get(key))); return l; } static String mapToLines(Map map, Object f) { return lines(map(map, f)); } static String mapToLines(Object f, Map map) { return lines(map(map, f)); } static String mapToLines(Object f, Iterable l) { return lines(map(f, l)); } static String mapToLines(Iterable l, IF1 f) { return mapToLines((Object) f, l); } static String mapToLines(IF1 f, Iterable l) { return mapToLines((Object) f, l); } static String mapToLines(Map map, IF2 f) { return lines(map(map, f)); } static String mapToLines(IF1 f, A data1, A... moreData) { return lines(map(f, data1, moreData)); } static int randomID_defaultLength = 12; static String randomID(int length) { return makeRandomID(length); } static String randomID(Random r, int length) { return makeRandomID(r, length); } static String randomID() { return randomID(randomID_defaultLength); } static String randomID(Random r) { return randomID(r, randomID_defaultLength); } // Finds out the index of a sublist in the original list // Works with nested (grand-parent) sublists. // Does not work with lists not made with subList() (returns -1) // If you use NoIllegalAccesses: Make sure not to use subList(...) // instead of .subList(...) in case you ever call magicIndexOfSubList // on the result. static int magicIndexOfSubList(List list, List sublist) { if (sublist == list) return 0; if (sublist instanceof ISubList) { List root = ((ISubList) sublist).rootList(); int o2 = ((ISubList) sublist).subListOffset(); if (list instanceof ISubList) { if (((ISubList) list).rootList() != root) return -1; int o1 = ((ISubList) list).subListOffset(); return o2-o1; } else { if (list != root) return -1; return o2; } } return -1; } static List reversedList(Iterable l) { List x = cloneList(l); Collections.reverse(x); return x; } static List findBlock(String pat, List tok) { List tokpat = javaTok(pat); int i = findCodeTokens(tok, toStringArray(codeTokensOnly(tokpat))); //print("index of block " + quote(pat) + ": " + i); if (i < 0) return null; int bracketIdx = i+tokpat.size()-3; assertEquals("{", tok.get(bracketIdx)); int endIdx = findEndOfBlock(tok, bracketIdx); return subList(tok, i-1, endIdx+1); // make it actual CNC } static String loadLocalSnippet(String snippetID) { return loadLocalSnippet(psI(snippetID)); } static String loadLocalSnippet(long snippetID) { return loadTextFile(localSnippetFile(snippetID)); } static String standardCredentials() { String user = standardCredentialsUser(); String pass = standardCredentialsPass(); if (nempty(user) && nempty(pass)) return "&_user=" + urlencode(user) + "&_pass=" + urlencode(pass); return ""; } static File getGlobalCache() { File file = new File(javaxCachesDir(), "Binary Snippets"); file.mkdirs(); return file; } static A setThreadLocal(ThreadLocal tl, A value) { if (tl == null) return null; A old = tl.get(); tl.set(value); return old; } static boolean isUnproperlyQuoted(String s) { return startsWith(s, '"') && !isProperlyQuoted(s); } static boolean regexpFinds(String pat, String s) { return regexp(pat, s).find(); } static boolean regexpFinds(Pattern pat, String s) { return regexp(pat, s).find(); } static List immutableEmptyList() { return Collections.emptyList(); } static byte[] emptyByteArray_a = new byte[0]; static byte[] emptyByteArray() { return emptyByteArray_a; } static short[] emptyShortArray = new short[0]; static short[] emptyShortArray() { return emptyShortArray; } static Map immutableEmptyMap() { return Collections.emptyMap(); } static Map jsonDecodeMap(String s) { Object o = jsonDecode(s); if (o instanceof List && empty((List) o)) return new HashMap(); if (o instanceof Map) return (Map) o; else throw fail("Not a JSON map: " + s); } static ThreadLocal doPost_silently = new ThreadLocal(); static ThreadLocal doPost_timeout = new ThreadLocal(); static ThreadLocal> doPost_extraHeaders = new ThreadLocal(); static String doPost(String url, Map urlParameters) { return doPost(urlParameters, url); } static String doPost(Map urlParameters, String url) { return doPost(makePostData(urlParameters), url); } static String doPost(String urlParameters, String url) { try { URL _url = new URL(url); ping(); return doPost(urlParameters, _url.openConnection(), _url); } catch (Exception __e) { throw rethrow(__e); } } static String doPost(String urlParameters, URLConnection conn, URL url) { try { boolean silently = isTrue(optParam(doPost_silently)); Long timeout = optParam(doPost_timeout); Map extraHeaders = optPar(doPost_extraHeaders); setHeaders(conn); for (String key : keys(extraHeaders)) { conn.setRequestProperty(key, extraHeaders.get(key)); } int l = lUtf8(urlParameters); if (!silently) print("Sending POST request: " + hideCredentials(url) + " (" + l + " bytes)"); // connect and do POST if (timeout != null) setURLConnectionTimeouts(conn, timeout); ((HttpURLConnection) conn).setRequestMethod("POST"); conn.setDoOutput(true); conn.setRequestProperty("Content-Length", str(l)); OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), "UTF-8"); writer.write(urlParameters); writer.flush(); String contents = loadPage_utf8(conn, url, false); writer.close(); return contents; } catch (Exception __e) { throw rethrow(__e); } } static String urlencode(String x) { try { return URLEncoder.encode(unnull(x), "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } static List> innerClasses(List tok) { if (tok == null) return emptyList(); int i = 1; while (i < tok.size() && !tok.get(i).equals("{")) i += 2; return allClasses(subList(tok, i+1, tok.size())); } static Set getClassDeclarationName_skippables_cache; static Set getClassDeclarationName_skippables() { if (getClassDeclarationName_skippables_cache == null) getClassDeclarationName_skippables_cache = getClassDeclarationName_skippables_load(); return getClassDeclarationName_skippables_cache;} static Set getClassDeclarationName_skippables_load() { return litset("noeq", "mapMethodLike"); } static boolean startsWithUpperCase(String s) { return nempty(s) && Character.isUpperCase(s.charAt(0)); } static List toLinesFullTrim_java(String text) { // TODO: shouldn't it be tlft(javaDropComments(text))? return tlft(joinLines(map(__67 -> javaDropComments(__67), tlft(text)))); } static boolean eqOneOf_twoNonNullStrings(String s, String a, String b) { return a.equals(s) || b.equals(s); } static boolean startsWithJavaIdentifierStart(String s) { return nempty(s) && Character.isJavaIdentifierStart(s.charAt(0)); } static byte[] md5AsByteArray(byte[] data) { try { return MessageDigest.getInstance("MD5").digest(data); } catch (Exception __e) { throw rethrow(__e); } } static byte[] toUtf8(String s) { try { return s.getBytes(utf8charset()); } catch (Exception __e) { throw rethrow(__e); } } static boolean md5OfFile_verbose = false; static String md5OfFile(String path) { return md5OfFile(newFile(path)); } static String md5OfFile(File f) { try { if (!f.exists()) return "-"; if (md5OfFile_verbose) print("Getting MD5 of " + f); MessageDigest md5 = MessageDigest.getInstance("MD5"); FileInputStream in = new FileInputStream(f); try { byte buf[] = new byte[65536]; int l; while (true) { l = in.read(buf); if (l <= 0) break; md5.update(buf, 0, l); } return bytesToHex(md5.digest()); } finally { _close(in); }} catch (Exception __e) { throw rethrow(__e); } } // i points at C token after suspected meta command static boolean tok_isJavaxMetaCommandLeftOf(List tok, int i) { int j = i-2*4-1; if (j >= 0 && jfind(subList(tok, j, i), "set flag .") == 1) return true; return false; } static void sortIntRangesInPlace(List l) { sortInPlaceByCalculatedField(l, r -> r.start); } static TokCondition toTokCondition(ITokCondition condition) { return condition == null ? null : condition instanceof TokCondition ? (TokCondition) condition : new TokCondition() { public boolean get(List tok, int i) { return condition.get(tok, i); } }; } static boolean rectContains(int x1, int y1, int w, int h, Pt p) { return p.x >= x1 && p.y >= y1 && p.x < x1+w && p.y < y1+h; } static boolean rectContains(Rect a, Rect b) { return b.x >= a.x && b.y >= a.y && b.x2() <= a.x2() && b.y2() <= a.y2(); } static boolean rectContains(Rect a, Rectangle b) { return rectContains(a, toRect(b)); } static boolean rectContains(Rect a, int x, int y) { return a != null && a.contains(x, y); } static boolean rectContains(Rect a, Pt p) { return a != null && p != null && a.contains(p); } static Iterator iterator(Iterable c) { return c == null ? emptyIterator() : c.iterator(); } static void clearTokens_maybeReTok(List tok, int i, int j, boolean reTok) { clearTokens(tok, i, j); if (reTok) reTok(tok, i, j); } static boolean allVarNames_debug = false; static List allVarNames(List tok) { boolean debug = allVarNames_debug; Map bracketMap = getBracketMap(tok); List varNames = new ArrayList(); for (int i = 3; i < tok.size(); i += 2) { String t = tok.get(i); if (eqOneOf(t, "=", ";", ",")) { String v = tok.get(i-2); if (isIdentifier(v)) varNames.add(v); if (eq(t, "=")) { i = scanToEndOfInitializer(tok, bracketMap, i)+1; assertTrue(odd(i)); } } else if (eq(t, "<")) { i = findEndOfTypeArgs(tok, i)+1; if (debug) print("Skipped type args: " + struct(subList(tok, i))); } else if (eqOneOf(t, "{", "(")) i = findEndOfBracketPart(tok, i)-1; // skip function/class bodies } return varNames; } static List allVarNames(String text) { return allVarNames(javaTok(text)); } static boolean isSortedList(Collection l) { Iterator it = iterator(l); if (!it.hasNext()) return true; Object a = it.next(); while (it.hasNext()) { Object b = it.next(); if (cmp(a, b) > 0) return false; a = b; } return true; } static int smartIndexOfAny(List l, int i, A... x) { while (i < l(l)) if (eqOneOf(l.get(i), x)) return i; else ++i; return l(l); } static int smartIndexOfAny(List l, A... x) { return smartIndexOfAny(l, 0, x); } static int smartIndexOfAny(List l, int i, Collection x) { int n = l(l); while (i < n) if (contains(x, l.get(i))) return i; else ++i; return n; } static boolean vmExiting() { return isTrue(getOpt(javax(), "killing")); } static String struct(Object o) { return structure(o); } static String struct(Object o, structure_Data data) { return structure(o, data); } static List getBracketMap2(List tok, Map map, String openingBrackets, String closingBrackets) { map.clear(); List stack = new ArrayList(); for (int i = 1; i < l(tok); i+= 2) { String t = tok.get(i); if (l(t) == 1) if (openingBrackets.contains(t)) stack.add(i); else if (closingBrackets.contains(tok.get(i))) map.put(empty(stack) ? 0 : liftLast(stack), i); } return stack; } static int tokenIndexToUserLandLineNr(List tok, int tokenIndex) { return charIndexToUserLandLineNr(join(tok), tokenIndexToCharIndex(tok, tokenIndex)); } static int tokenToCharIndex(List tok, int tokenIndex) { if (tokenIndex < 0) return -1; int idx = 0; tokenIndex = min(tokenIndex, l(tok)); for (int i = 0; i < tokenIndex; i++) idx += l(tok.get(i)); return idx; } static int tokenIndexToCharIndex(List tok, int tokenIndex) { return tokenToCharIndex(tok, tokenIndex); } static String n(long l, String name) { return l + " " + trim(l == 1 ? singular(name) : getPlural(name)); } static String n(Collection l, String name) { return n(l(l), name); } static String n(Map m, String name) { return n(l(m), name); } static String n(Object[] a, String name) { return n(l(a), name); } static List asVirtualList(A[] a) { return wrapArrayAsList(a); } static String lookupStandardFunction(String sfName) { return stdFunctions_cached().get(sfName); } static String assertIsIdentifier(String s) { if (!isIdentifier(s)) throw fail("Not an identifier: " + quote(s)); return s; } static String assertIsIdentifier(String msg, String s) { if (!isIdentifier(s)) throw fail(msg + " - Not an identifier: " + quote(s)); return s; } static Object call_withVarargs(Object o, String methodName, Object... args) { try { if (o == null) return null; if (o instanceof Class) { Class c = (Class) o; _MethodCache cache = callOpt_getCache(c); Method me = cache.findStaticMethod(methodName, args); if (me != null) return invokeMethod(me, null, args); // try varargs List methods = cache.cache.get(methodName); if (methods != null) methodSearch: for (Method m : methods) { { if (!(m.isVarArgs())) continue; } { if (!(isStaticMethod(m))) continue; } Object[] newArgs = massageArgsForVarArgsCall(m, args); if (newArgs != null) return invokeMethod(m, null, newArgs); } throw fail("Method " + c.getName() + "." + methodName + "(" + formatArgumentClasses(args) + ") not found"); } else { Class c = o.getClass(); _MethodCache cache = callOpt_getCache(c); Method me = cache.findMethod(methodName, args); if (me != null) return invokeMethod(me, o, args); // try varargs List methods = cache.cache.get(methodName); if (methods != null) methodSearch: for (Method m : methods) { { if (!(m.isVarArgs())) continue; } Object[] newArgs = massageArgsForVarArgsCall(m, args); if (newArgs != null) return invokeMethod(m, o, newArgs); } throw fail("Method " + c.getName() + "." + methodName + "(" + formatArgumentClasses(args) + ") not found"); } } catch (Exception __e) { throw rethrow(__e); } } static void lock(Lock lock) { try { ping(); if (lock == null) return; try { vmBus_send("locking", lock, "thread" , currentThread()); lock.lockInterruptibly(); vmBus_send("locked", lock, "thread" , currentThread()); } catch (InterruptedException e) { Object reason = vm_threadInterruptionReasonsMap().get(currentThread()); print("Locking interrupted! Reason: " + strOr(reason, "Unknown")); printStackTrace(e); rethrow(e); } // NO call to ping here! Make sure lock is always released. } catch (Exception __e) { throw rethrow(__e); } } static void lock(Lock lock, String msg) { print("Locking: " + msg); lock(lock); } static void lock(Lock lock, String msg, long timeout) { print("Locking: " + msg); lockOrFail(lock, timeout); } static ReentrantLock lock() { return fairLock(); } static Object makeDependent_postProcess; static void makeDependent(Object c) { if (c == null) return; assertTrue("Not a class", c instanceof Class); dependentClasses(); // cleans up the list hotwire_classes.add(new WeakReference(c)); Object local_log = getOpt(mc(), "local_log"); if (local_log != null) setOpt(c, "local_log", local_log); /*if (isTrue(getOpt(c, 'ping_actions_shareable))) setOpt(c, +ping_actions);*/ Object print_byThread = getOpt(mc(), "print_byThread"); if (print_byThread != null) setOpt(c, "print_byThread", print_byThread); callF(makeDependent_postProcess, c); } static void unlock(Lock lock, String msg) { if (lock == null) return; lock.unlock(); vmBus_send("unlocked", lock, "thread" , currentThread()); print("Unlocked: " + msg); // print afterwards to make sure the lock is always unlocked } static void unlock(Lock lock) { if (lock == null) return; lock.unlock(); vmBus_send("unlocked", lock, "thread" , currentThread()); } static boolean jreplace_multi(List tok, List ins, String out) { boolean change = false; for (String in : ins) if (jreplace(tok, in, out)) change = true; return change; } // doesn't loop static String jreplace_multi(String s, String... replacements) { if (empty(replacements)) return s; List tok = javaTok(s); boolean change = false; for (int i = 0; i < l(replacements); i += 2) if (jreplace(tok, replacements[i], replacements[i+1])) change = true; return change ? join(tok) : s; } static List identifiersOnly(Collection l) { List out = new ArrayList(); for (String a : unnull(l)) if (isIdentifier(a)) out.add(a); return out; } static List replaceInClonedList(List l, A a, A b) { return replace(cloneList(l), a, b); } static List replaceInClonedList(A a, A b, List l) { return replaceInClonedList(l, a, b); } static Collection indicesOf_collectionOfHasIndex(List l, A a) { if (l == null) return null; if (l instanceof IContentsIndexedList2) return ((IContentsIndexedList2) l).indicesOf_treeSetOfHasIndex(a); List x = new ArrayList(); int n = l(l); for (int i = 0; i < n; i++) if (eq(l.get(i), a)) x.add(new HasIndex(i)); return x; } static List newSubListOrSame(List l, int startIndex) { return newSubListOrSame(l, startIndex, l(l)); } static List newSubListOrSame(List l, int startIndex, int endIndex) { if (l == null) return null; int n = l(l); startIndex = max(0, startIndex); endIndex = min(n, endIndex); if (startIndex >= endIndex) return ll(); if (startIndex == 0 && endIndex == n) return l; return cloneList(l.subList(startIndex, endIndex)); } static List newSubListOrSame(List l, IntRange r) { return newSubListOrSame(l, r.start, r.end); } static int[] takeFirstOfIntArray(int[] b, int n) { return subIntArray(b, 0, n); } static int[] takeFirstOfIntArray(int n, int[] b) { return takeFirstOfIntArray(b, n); } static short[] takeFirstOfShortArray(short[] b, int n) { return subShortArray(b, 0, n); } static short[] takeFirstOfShortArray(int n, short[] b) { return takeFirstOfShortArray(b, n); } static byte[] takeFirstOfByteArray(byte[] b, int n) { return subByteArray(b, 0, n); } static byte[] takeFirstOfByteArray(int n, byte[] b) { return takeFirstOfByteArray(b, n); } static double[] takeFirstOfDoubleArray(double[] b, int n) { return subDoubleArray(b, 0, n); } static double[] takeFirstOfDoubleArray(int n, double[] b) { return takeFirstOfDoubleArray(b, n); } static Map takeFirstFromMap(int n, Map map) { if (map == null) return null; Map map2 = similarEmptyMap(map); if (n > 0) for (Map.Entry e : map.entrySet()) if (n-- <= 0) break; else map2.put(e.getKey(), e.getValue()); return map2; } static A optPar(ThreadLocal tl, A defaultValue) { A a = tl.get(); if (a != null) { tl.set(null); return a; } return defaultValue; } static A optPar(ThreadLocal tl) { return optPar(tl, null); } static Object optPar(Object[] params, String name) { return optParam(params, name); } static Object optPar(String name, Object[] params) { return optParam(params, name); } static Object optPar(String name, Map params) { return optParam(name, params); } static A optPar(Object[] params, String name, A defaultValue) { return optParam(params, name, defaultValue); } static A optPar(String name, Object[] params, A defaultValue) { return optParam(params, name, defaultValue); } static A optParam(ThreadLocal tl, A defaultValue) { return optPar(tl, defaultValue); } static A optParam(ThreadLocal tl) { return optPar(tl); } static Object optParam(String name, Map params) { return mapGet(params, name); } // now also takes a map as single array entry static A optParam(Object[] opt, String name, A defaultValue) { int n = l(opt); if (n == 1 && opt[0] instanceof Map) { Map map = (Map) (opt[0]); return map.containsKey(name) ? (A) map.get(name) : defaultValue; } if (!even(l(opt))) throw fail("Odd parameter length"); for (int i = 0; i < l(opt); i += 2) if (eq(opt[i], name)) return (A) opt[i+1]; return defaultValue; } static Object optParam(Object[] opt, String name) { return optParam(opt, name, null); } static Object optParam(String name, Object[] params) { return optParam(params, name); } static boolean endsWith(String a, String b) { return a != null && a.endsWith(b); } static boolean endsWith(String a, char c) { return nempty(a) && lastChar(a) == c; } static boolean endsWith(String a, String b, Matches m) { if (!endsWith(a, b)) return false; m.m = new String[] {dropLast(l(b), a)}; return true; } static boolean endsWithLetterOrDigit(String s) { return s != null && s.length() > 0 && Character.isLetterOrDigit(s.charAt(s.length()-1)); } // PersistableThrowable doesn't hold GC-disturbing class references in backtrace static volatile PersistableThrowable lastException_lastException; static PersistableThrowable lastException() { return lastException_lastException; } static void lastException(Throwable e) { lastException_lastException = persistableThrowable(e); } static String hideCredentials(URL url) { return url == null ? null : hideCredentials(str(url)); } static String hideCredentials(String url) { try { if (startsWithOneOf(url, "http://", "https://") && isAGIBlueDomain(hostNameFromURL(url))) return url; } catch (Throwable e) { print("HideCredentials", e); } return url.replaceAll("([&?])(_pass|key|cookie)=[^&\\s\"]*", "$1$2="); } static String hideCredentials(Object o) { return hideCredentials(str(o)); } static void rotateStringBuffer(StringBuffer buf, int max) { try { if (buf == null) return; synchronized(buf) { if (buf.length() <= max) return; try { int newLength = max/2; int ofs = buf.length()-newLength; String newString = buf.substring(ofs); buf.setLength(0); buf.append("[...] ").append(newString); } catch (Exception e) { buf.setLength(0); } buf.trimToSize(); } } catch (Exception __e) { throw rethrow(__e); } } static void rotateStringBuilder(StringBuilder buf, int max) { try { if (buf == null) return; synchronized(buf) { if (buf.length() <= max) return; try { int newLength = max/2; int ofs = buf.length()-newLength; String newString = buf.substring(ofs); buf.setLength(0); buf.append("[...] ").append(newString); } catch (Exception e) { buf.setLength(0); } buf.trimToSize(); } } catch (Exception __e) { throw rethrow(__e); } } static Object vmBus_wrapArgs(Object... args) { return empty(args) ? null : l(args) == 1 ? args[0] : args; } static void pcallFAll_minimalExceptionHandling(Collection l, Object... args) { if (l != null) for (Object f : cloneList(l)) { ping(); pcallF_minimalExceptionHandling(f, args); } } static void pcallFAll_minimalExceptionHandling(Iterator it, Object... args) { while (it.hasNext()) { ping(); pcallF_minimalExceptionHandling(it.next(), args); } } static Set vm_busListeners_live_cache; static Set vm_busListeners_live() { if (vm_busListeners_live_cache == null) vm_busListeners_live_cache = vm_busListeners_live_load(); return vm_busListeners_live_cache;} static Set vm_busListeners_live_load() { return vm_generalIdentityHashSet("busListeners"); } static Map vm_busListenersByMessage_live_cache; static Map vm_busListenersByMessage_live() { if (vm_busListenersByMessage_live_cache == null) vm_busListenersByMessage_live_cache = vm_busListenersByMessage_live_load(); return vm_busListenersByMessage_live_cache;} static Map vm_busListenersByMessage_live_load() { return vm_generalHashMap("busListenersByMessage"); } // assumptions: // -pingSource() stays constant within a stack frame (so you can cache it) // -all changes happen with tempSetPingSource // -multiple threads can share a PingSource static PingSource pingSource() { return pingSource_tl().get(); } static PingSource pingSource(Thread thread) { return pingSource_tl().get(thread); } static Map synchroMap() { return synchroHashMap(); } static Map synchroMap(Map map) { return Collections.synchronizedMap(map); } static TreeSet caseInsensitiveSet_treeSet() { return new TreeSet(caseInsensitiveComparator()); } static TreeSet caseInsensitiveSet_treeSet(Collection c) { return toCaseInsensitiveSet_treeSet(c); } static Object callOpt_withVarargs(Object o, String method, Object... args) { try { if (o == null) return null; if (o instanceof Class) { Class c = (Class) o; _MethodCache cache = callOpt_getCache(c); Method me = cache.findMethod(method, args); if (me == null) { // TODO: varargs return null; } if ((me.getModifiers() & Modifier.STATIC) == 0) return null; return invokeMethod(me, null, args); } else { Class c = o.getClass(); _MethodCache cache = callOpt_getCache(c); Method me = cache.findMethod(method, args); if (me != null) return invokeMethod(me, o, args); // try varargs List methods = cache.cache.get(method); if (methods != null) methodSearch: for (Method m : methods) { { if (!(m.isVarArgs())) continue; } Object[] newArgs = massageArgsForVarArgsCall(m, args); if (newArgs != null) return invokeMethod(m, o, newArgs); } return null; } } catch (Exception __e) { throw rethrow(__e); } } static String myJavaSource_code; static String myJavaSource() { return myJavaSource_code; } // TODO: optimize (use getOpt_cache) static void setOpt_raw(Object o, String field, Object value) { try { if (o == null) return; if (o instanceof Class) setOpt_raw((Class) o, field, value); else { Field f = setOpt_raw_findField(o.getClass(), field); if (f != null) { makeAccessible(f); smartSet(f, o, value); } } } catch (Exception __e) { throw rethrow(__e); } } static void setOpt_raw(Class c, String field, Object value) { try { if (c == null) return; Field f = setOpt_raw_findStaticField(c, field); if (f != null) { makeAccessible(f); smartSet(f, null, value); } } catch (Exception __e) { throw rethrow(__e); } } static Field setOpt_raw_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 Field setOpt_raw_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); return null; } static void smartSet(Field f, Object o, Object value) throws Exception { try { f.set(o, value); } catch (Exception e) { Class type = f.getType(); // take care of common case (long to int) if (type == int.class && value instanceof Long) { f.set(o, ((Long) value).intValue()); return; } if (type == boolean.class && value instanceof String) { f.set(o, isTrueOrYes(((String) value))); return; } if (type == LinkedHashMap.class && value instanceof Map) { f.set(o, asLinkedHashMap((Map) value)); return; } throw e; } } static A setDyn(A o, String key, Object value) { setDynObjectValue(o, key, value); return o; } static void setDyn(IMeta o, String key, Object value) { metaMapPut(o, key, value); } static Producer javaTokC_noMLS_iterator(final String s) { return javaTokC_noMLS_iterator(s, 0); } static Producer javaTokC_noMLS_iterator(final String s, final int startIndex) { return new Producer() { final int l = s.length(); int i = startIndex; public String next() { if (i >= l) return null; 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 && !s.substring(j, Math.min(j+2, l)).equals("*/")); j = Math.min(j+2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } i = j; if (i >= l) return null; c = s.charAt(i); d = i+1 >= l ? '\0' : s.charAt(i+1); // scan for non-whitespace if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { if (s.charAt(j) == opener || s.charAt(j) == '\n') { // end at \n to not propagate unclosed string literal errors ++j; break; } else if (s.charAt(j) == '\\' && j+1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && Character.isJavaIdentifierPart(s.charAt(j))); 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 ++j; String t = quickSubstring(s, i, j); i = j; return t; } }; } static Producer javaTokC_noMLS_onReader(final BufferedReader r) { final class X implements Producer { StringBuilder buf = new StringBuilder(); // stores from "i" char c, d, e = 'x'; // just not '\0' X() { // fill c, d and e nc(); nc(); nc(); } // get next character(s) into c, d and e void nc() { try { c = d; d = e; if (e == '\0') return; int i = r.read(); e = i < 0 ? '\0' : i == '\0' ? '_' // shouldn't happen anymore : (char) i; } catch (Exception __e) { throw rethrow(__e); } } void ncSave() { if (c != '\0') { buf.append(c); nc(); } } public String next() { // scan for whitespace while (c != '\0') { if (c == ' ' || c == '\t' || c == '\r' || c == '\n') nc(); else if (c == '/' && d == '*') { do nc(); while (c != '\0' && !(c == '*' && d == '/')); nc(); nc(); } else if (c == '/' && d == '/') { do nc(); while (c != '\0' && "\r\n".indexOf(c) < 0); } else break; } if (c == '\0') return null; // scan for non-whitespace if (c == '\'' || c == '"') { char opener = c; ncSave(); while (c != '\0') { if (c == opener || c == '\n') { // end at \n to not propagate unclosed string literal errors ncSave(); break; } else if (c == '\\') { ncSave(); ncSave(); } else ncSave(); } } else if (Character.isJavaIdentifierStart(c)) do ncSave(); while (Character.isJavaIdentifierPart(c) || c == '\''); // for stuff like "don't" else if (Character.isDigit(c)) { do ncSave(); while (Character.isDigit(c)); if (c == 'L') ncSave(); // Long constants like 1L } else ncSave(); String t = buf.toString(); buf.setLength(0); return t; } } return new X(); } static Object _defaultClassFinder_value = defaultDefaultClassFinder(); static Object _defaultClassFinder() { return _defaultClassFinder_value; } static BigInteger parseBigInt(String s) { return new BigInteger(s); } static double parseDouble(String s) { return empty(s) ? 0.0 : Double.parseDouble(s); } static float parseFloat(String s) { return Float.parseFloat(s); } static String trivialUnquote(String s) { return dropPrefixSuffix("\"", s); } static short[] shortArrayFromBytes(byte[] a) { return shortArrayFromBytes(a, 0, l(a)); } static short[] shortArrayFromBytes(byte[] a, int from, int to) { short[] b = new short[(to-from)/2]; for (int i = 0; i < b.length; i++) b[i] = shortFromBytes(a, from+i*2); return b; } static byte[] hexToBytes(String s) { if (odd(l(s))) throw fail("Hex string has odd length: " + quote(shorten(10, s))); int n = l(s) / 2; byte[] bytes = new byte[n]; for (int i = 0; i < n; i++) { int a = parseHexChar(s.charAt(i*2)); int b = parseHexChar(s.charAt(i*2+1)); if (a < 0 || b < 0) throw fail("Bad hex byte: " + quote(substring(s, i*2, i*2+2)) + " at " + i*2 + "/" + l(s)); bytes[i] = (byte) ((a << 4) | b); } return bytes; } static long[] longArrayFromBytes(byte[] a) { return longArrayFromBytes(a, 0, l(a)); } static long[] longArrayFromBytes(byte[] a, int from, int to) { long[] b = new long[(to-from)/8]; for (int i = 0; i < b.length; i++) b[i] = longFromBytes_bigEndian(a, from+i*8); return b; } static HashMap findClass_fullName_cache = new HashMap(); // returns null on not found // this is the simple version that is not case-tolerant static Class findClass_fullName(String name) { synchronized(findClass_fullName_cache) { if (findClass_fullName_cache.containsKey(name)) return findClass_fullName_cache.get(name); Class c; try { c = Class.forName(name); } catch (ClassNotFoundException e) { c = null; } findClass_fullName_cache.put(name, c); return c; } } static String unquoteUsingCharArray(String s, char[] buf) { if (s == null) return null; if (startsWith(s, '[')) { int i = 1; while (i < s.length() && s.charAt(i) == '=') ++i; if (i < s.length() && s.charAt(i) == '[') { String m = s.substring(1, i); if (s.endsWith("]" + m + "]")) return s.substring(i+1, s.length()-i-1); } } if (s.length() > 1) { char c = s.charAt(0); if (c == '\"' || c == '\'') { int l = endsWith(s, c) ? s.length()-1 : s.length(); if (l > buf.length) return unquote(s); // fallback int n = 0; for (int i = 1; i < l; i++) { char ch = s.charAt(i); if (ch == '\\') { char nextChar = (i == l - 1) ? '\\' : s.charAt(i + 1); // Octal escape? if (nextChar >= '0' && nextChar <= '7') { String code = "" + nextChar; i++; if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') { code += s.charAt(i + 1); i++; if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') { code += s.charAt(i + 1); i++; } } buf[n++] = (char) Integer.parseInt(code, 8); continue; } switch (nextChar) { case '\"': ch = '\"'; break; case '\\': ch = '\\'; break; case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case '\'': ch = '\''; break; // Hex Unicode: u???? case 'u': if (i >= l - 5) { ch = 'u'; break; } int code = Integer.parseInt( "" + s.charAt(i + 2) + s.charAt(i + 3) + s.charAt(i + 4) + s.charAt(i + 5), 16); char[] x = Character.toChars(code); int lx = x.length; for (int j = 0; j < lx; j++) buf[n++] = x[j]; i += 5; continue; default: ch = nextChar; // added by Stefan } i++; } buf[n++] = ch; } return new String(buf, 0, n); } } return s; // not quoted - return original } static boolean structure_isMarker(String s, int i, int j) { if (i >= j) return false; if (s.charAt(i) != 'm') return false; ++i; while (i < j) { char c = s.charAt(i); if (c < '0' || c > '9') return false; ++i; } return true; } static String internIfLongerThan(String s, int l) { return s == null ? null : l(s) >= l ? intern(s) : s; } static char unquoteCharacter(String s) { assertTrue(s.startsWith("'") && s.length() > 1); return unquote("\"" + s.substring(1, s.endsWith("'") ? s.length()-1 : s.length()) + "\"").charAt(0); } static TreeMap ciMap() { return caseInsensitiveMap(); } static List parseList(String s) { return (List) safeUnstructure(s); } static List synchroLinkedList() { return synchroList(new LinkedList()); } static NavigableMap synchroNavigableMap(NavigableMap map) { return Collections.synchronizedNavigableMap(map); } static SortedMap synchroSortedMap(SortedMap map) { return Collections.synchronizedSortedMap(map); } static List synchroList() { return synchroList(new ArrayList()); } static List synchroList(List l) { return Collections.synchronizedList(l); } static boolean[] boolArrayFromBytes(byte[] a, int n) { boolean[] b = new boolean[n]; int m = min(n, l(a)*8); for (int i = 0; i < m; i++) b[i] = (a[i/8] & 1 << (i & 7)) != 0; return b; } static boolean isAbstract(Class c) { return (c.getModifiers() & Modifier.ABSTRACT) != 0; } static boolean isAbstract(Method m) { return (m.getModifiers() & Modifier.ABSTRACT) != 0; } static Constructor nuStubInnerObject_findConstructor(Class c) { return nuStubInnerObject_findConstructor(c, null); } static Constructor nuStubInnerObject_findConstructor(Class c, Object classFinder) { try { Class outerType = getOuterClass(c, classFinder); Constructor m = c.getDeclaredConstructor(outerType); makeAccessible(m); return m; } catch (Exception __e) { throw rethrow(__e); } } static Map nuEmptyObject_cache = newDangerousWeakHashMap(); static A nuEmptyObject(Class c) { try { Constructor ctr; synchronized(nuEmptyObject_cache) { ctr = nuEmptyObject_cache.get(c); if (ctr == null) { nuEmptyObject_cache.put(c, ctr = nuEmptyObject_findConstructor(c)); makeAccessible(ctr); } } try { return (A) ctr.newInstance(); } catch (InstantiationException e) { if (empty(e.getMessage())) if ((c.getModifiers() & Modifier.ABSTRACT) != 0) throw fail("Can't instantiate abstract class " + className(c), e); else throw fail("Can't instantiate " + className(c), e); else throw rethrow(e); } } catch (Exception __e) { throw rethrow(__e); } } static Constructor nuEmptyObject_findConstructor(Class c) { for (Constructor m : getDeclaredConstructors_cached(c)) if (m.getParameterTypes().length == 0) return m; throw fail("No default constructor declared in " + c.getName()); } static void setOptAllDyn_pcall(DynamicObject o, Map fields) { if (fields == null || o == null) return; HashMap fieldMap = instanceFieldsMap(o); for (Map.Entry e : fields.entrySet()) { try { String field = e.getKey(); Object val = e.getValue(); Field f = fieldMap.get(field); if (f != null) smartSet(f, o, val); else { dynamicObject_setRawFieldValue(o, intern(field), val); } } catch (Throwable __e) { pcallFail(__e); }} } static void setOptAll_pcall(Object o, Map fields) { if (fields == null) return; for (String field : keys(fields)) try { setOpt(o, field, fields.get(field)); } catch (Throwable __e) { print(exceptionToStringShort(__e)); } } static void setOptAll_pcall(Object o, Object... values) { //values = expandParams(c.getClass(), values); warnIfOddCount(values); for (int i = 0; i+1 < l(values); i += 2) { String field = (String) values[i]; Object value = values[i+1]; try { setOpt(o, field, value); } catch (Throwable __e) { print(exceptionToStringShort(__e)); } } } static void fixOuterRefs(Object o) { try { if (o == null) return; Field[] l = thisDollarOneFields(o.getClass()); if (l.length <= 1) return; Object father = null; for (Field f : l) { father = f.get(o); if (father != null) break; } if (father == null) return; for (Field f : l) f.set(o, father); } catch (Exception __e) { throw rethrow(__e); } } static void setDynObjectValue(DynamicObject o, String field, Object value) { dynamicObject_setRawFieldValue(o, field, value); } static String intern(String s) { return fastIntern(s); } static void pcallOpt_noArgs(Object o, String method) { try { callOpt_noArgs(o, method); } catch (Throwable __e) { pcallFail(__e); } } static RuntimeException todo() { throw new RuntimeException("TODO"); } static RuntimeException todo(Object msg) { throw new RuntimeException("TODO: " + msg); } static Object newMultiDimensionalOuterArray(Class elementType, int dimensions, int length) { int[] dims = new int[dimensions]; dims[0] = length; return Array.newInstance(elementType, dims); } static int[] toIntArray(Collection l) { int[] a = new int[l(l)]; int i = 0; if (a.length != 0) for (int x : l) a[i++] = x; return a; } static double[] toDoubleArray(Collection l) { double[] a = new double[l(l)]; int i = 0; if (a.length != 0) for (double x : l) a[i++] = x; return a; } static double[] toDoubleArray(float... l) { double[] a = new double[l(l)]; for (int i = 0; i < a.length; i++) a[i] = l[i]; return a; } static double[] toDoubleArray(int... l) { double[] a = new double[l(l)]; for (int i = 0; i < a.length; i++) a[i] = l[i]; return a; } static float[] toFloatArray(List l) { float[] a = new float[l(l)]; for (int i = 0; i < a.length; i++) a[i] = l.get(i); return a; } static float[] toFloatArray(double[] l) { float[] a = new float[l(l)]; for (int i = 0; i < a.length; i++) a[i] = (float) l[i]; return a; } static void dynamicObject_setRawFieldValue(DynamicObject o, Object key, Object value) { if (o == null) return; // double sync, but should be OK here because of locking order o > o.fieldValues synchronized(o) { o.fieldValues = syncMapPut2_createLinkedHashMap((LinkedHashMap) o.fieldValues, key, value); } } // DIFFERENCES to jfind: always ignores case, doesn't recognize etc // You probably want jmatch2 static boolean jmatch(String pat, String s) { return jmatch(pat, s, null); } static boolean jmatch(String pat, String s, Matches matches) { if (s == null) return false; return jmatch(pat, javaTok(s), matches); } static boolean jmatch(String pat, List toks) { return jmatch(pat, toks, null); } static boolean jmatch(String pat, List toks, Matches matches) { List tokpat = javaTok(pat); String[] m = match2(tokpat, toks); //print(structure(tokpat) + " on " + structure(toks) + " => " + structure(m)); if (m == null) return false; else { if (matches != null) matches.m = m; return true; } } static Object nuObject(String className, Object... args) { try { return nuObject(classForName(className), args); } catch (Exception __e) { throw rethrow(__e); } } // too ambiguous - maybe need to fix some callers /*static O nuObject(O realm, S className, O... args) { ret nuObject(_getClass(realm, className), args); }*/ static A nuObject(Class c, Object... args) { try { if (args == null || args.length == 0) return nuObjectWithoutArguments(c); // cached! Constructor m = nuObject_findConstructor(c, args); makeAccessible(m); return (A) m.newInstance(args); } catch (Exception __e) { throw rethrow(__e); } } static Constructor nuObject_findConstructor(Class c, Object... args) { for (Constructor m : getDeclaredConstructors_cached(c)) { if (!nuObject_checkArgs(m.getParameterTypes(), args, false)) continue; return m; } throw fail("Constructor " + c.getName() + getClasses(args) + " not found" + (args.length == 0 && (c.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0 ? " - hint: it's a non-static class!" : "")); } static boolean nuObject_checkArgs(Class[] types, Object[] args, boolean debug) { if (types.length != args.length) { if (debug) System.out.println("Bad parameter length: " + args.length + " vs " + types.length); return false; } for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) { if (debug) System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]); return false; } return true; } static AutoCloseable tempSetTL(ThreadLocal tl, A a) { return tempSetThreadLocal(tl, a); } static AutoCloseable tempSetTL(BetterThreadLocal tl, A a) { return tempSetThreadLocalIfNecessary(tl, a); } static ThreadLocal DynamicObject_loading = or((ThreadLocal) get(getClass("x30_pkg.x30_util"), "DynamicObject_loading"), new ThreadLocal()); static ThreadLocal dynamicObjectIsLoading_threadLocal() { return DynamicObject_loading; } static ThreadLocal pcallPolicyForThread_tl_tl = new ThreadLocal(); static ThreadLocal pcallPolicyForThread_tl() { return pcallPolicyForThread_tl_tl; } static PCallPolicy defaultPCallPolicy = __1 -> printStackTrace(__1); static PCallPolicy defaultPCallPolicy() { return defaultPCallPolicy; } static void defaultPCallPolicy_set(PCallPolicy policy) { defaultPCallPolicy = policy; } static void clear(Collection c) { if (c != null) c.clear(); } static void clear(Map map) { if (map != null) map.clear(); } static void put(Map map, A a, B b) { if (map != null) map.put(a, b); } static void put(List l, int i, A a) { if (l != null && i >= 0 && i < l(l)) l.set(i, a); } static List _registerDangerousWeakMap_preList; static A _registerDangerousWeakMap(A map) { return _registerDangerousWeakMap(map, null); } static A _registerDangerousWeakMap(A map, Object init) { callF(init, map); if (init instanceof String) { final String f = (String) init; init = new VF1() { public void get(Map map) { try { callMC(f, map) ; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "callMC(f, map)"; }}; } if (javax() == null) { // We're in class init if (_registerDangerousWeakMap_preList == null) _registerDangerousWeakMap_preList = synchroList(); _registerDangerousWeakMap_preList.add(pair(map, init)); return map; } call(javax(), "_registerDangerousWeakMap", map, init); return map; } static void _onLoad_registerDangerousWeakMap() { assertNotNull(javax()); if (_registerDangerousWeakMap_preList == null) return; for (Pair p : _registerDangerousWeakMap_preList) _registerDangerousWeakMap(p.a, p.b); _registerDangerousWeakMap_preList = null; } static Class _getClass(String name) { try { return Class.forName(name); } catch (ClassNotFoundException e) { return null; // could optimize this } } static Class _getClass(Object o) { return o == null ? null : o instanceof Class ? (Class) o : o.getClass(); } static Class _getClass(Object realm, String name) { try { return classLoaderForObject(realm).loadClass(classNameToVM(name)); } catch (ClassNotFoundException e) { return null; // could optimize this } } static B syncMapGet2(Map map, A a) { if (map == null) return null; synchronized(collectionMutex(map)) { return map.get(a); } } static B syncMapGet2(A a, Map map) { return syncMapGet2(map, a); } static boolean isSubtypeOf(Class a, Class b) { return a != null && b != null && b.isAssignableFrom(a); // << always hated that method, let's replace it! } static Set reflection_classesNotToScan_value = litset( "jdk.internal.loader.URLClassPath" ); static Set reflection_classesNotToScan() { return reflection_classesNotToScan_value; } static void _onJavaXSet() {} static Throwable getExceptionCause(Throwable e) { Throwable c = e.getCause(); return c != null ? c : e; } static List classNames(Collection l) { return getClassNames(l); } static List classNames(Object[] l) { return getClassNames(asList(l)); } static boolean isInstanceX(Class type, Object arg) { if (type == boolean.class) return arg instanceof Boolean; if (type == int.class) return arg instanceof Integer; if (type == long.class) return arg instanceof Long; if (type == float.class) return arg instanceof Float; if (type == short.class) return arg instanceof Short; if (type == char.class) return arg instanceof Character; if (type == byte.class) return arg instanceof Byte; if (type == double.class) return arg instanceof Double; return type.isInstance(arg); } static String rep(int n, char c) { return repeat(c, n); } static String rep(char c, int n) { return repeat(c, n); } static List rep(A a, int n) { return repeat(a, n); } static List rep(int n, A a) { return repeat(n, a); } static String shortenSnippetID(String snippetID) { if (snippetID.startsWith("#")) snippetID = snippetID.substring(1); String httpBlaBla = "http://tinybrain.de/"; if (snippetID.startsWith(httpBlaBla)) snippetID = snippetID.substring(httpBlaBla.length()); return "" + parseLong(snippetID); } static String formatSnippetIDOpt(String s) { return isSnippetID(s) ? formatSnippetID(s) : s; } static Class getMainClass() { return mc(); } static Class getMainClass(Object o) { try { if (o == null) return null; if (o instanceof Class && eq(((Class) o).getName(), "x30")) return (Class) o; ClassLoader cl = (o instanceof Class ? (Class) o : o.getClass()).getClassLoader(); if (cl == null) return null; String name = mainClassNameForClassLoader(cl); return loadClassFromClassLoader_orNull(cl, name); } catch (Exception __e) { throw rethrow(__e); } } static ThreadLocal> checkFileNotTooBigToRead_tl = new ThreadLocal(); static void checkFileNotTooBigToRead(File f) { callF(checkFileNotTooBigToRead_tl.get(), f); } static String formatWithThousands(long l) { return formatWithThousandsSeparator(l); } static String plural(String s) { return getPlural(s); } static double fraction(double d) { return d % 1; } static String n_fancy2(long l, String singular, String plural) { return formatWithThousandsSeparator(l) + " " + trim(l == 1 ? singular : plural); } static String n_fancy2(Collection l, String singular, String plural) { return n_fancy2(l(l), singular, plural); } static String n_fancy2(Map m, String singular, String plural) { return n_fancy2(l(m), singular, plural); } static String n_fancy2(Object[] a, String singular, String plural) { return n_fancy2(l(a), singular, plural); } static Set synchronizedSet() { return synchroHashSet(); } static Set synchronizedSet(Set set) { return Collections.synchronizedSet(set); } static List antiFilter(Iterable c, Object pred) { if (pred instanceof F1) return antiFilter(c, (F1) pred); List x = new ArrayList(); if (c != null) for (Object o : c) if (!isTrue(callF(pred, o))) x.add(o); return x; } static List antiFilter(Object pred, Iterable c) { return antiFilter(c, pred); } static List antiFilter(Object pred, Object[] c) { return antiFilter(pred, wrapArrayAsList(c)); } static List antiFilter(Iterable c, F1 pred) { List x = new ArrayList(); if (c != null) for (B o : c) if (!pred.get(o).booleanValue()) x.add(o); return x; } static List antiFilter(F1 pred, Iterable c) { return antiFilter(c, pred); } static List antiFilter(Iterable c, IF1 pred) { List x = new ArrayList(); if (c != null) for (B o : c) if (!pred.get(o).booleanValue()) x.add(o); return x; } static List antiFilter(IF1 pred, Iterable c) { return antiFilter(c, pred); } static WeakHasherMap symbol_map = new WeakHasherMap(new Hasher() { public int hashCode(Symbol symbol) { return symbol.text.hashCode(); } public boolean equals(Symbol a, Symbol b) { if (a == null) return b == null; return b != null && eq(a.text, b.text); } }); static Symbol symbol(String s) { if (s == null) return null; synchronized(symbol_map) { // TODO: avoid object creation by passing the string to findKey Symbol symbol = new Symbol(s, true); Symbol existingSymbol = symbol_map.findKey(symbol); if (existingSymbol == null) symbol_map.put(existingSymbol = symbol, true); return existingSymbol; } } static Symbol symbol(CharSequence s) { if (s == null) return null; if (s instanceof Symbol) return (Symbol) s; if (s instanceof String) return symbol((String) s); return symbol(str(s)); } static Symbol symbol(Object o) { return symbol((CharSequence) o); } static A addComponents(A c, Collection components) { if (nempty(components)) { swing(() -> { for (Component comp : components) if (comp != null) c.add(comp); revalidate(c); }); } return c; } static A addComponents(A c, Component... components) { return addComponents(c, asList(components)); } public static File mkdirsForFile(File file) { File dir = file.getParentFile(); if (dir != null) { // is null if file is in current dir dir.mkdirs(); if (!dir.isDirectory()) if (dir.isFile()) throw fail("Please delete the file " + f2s(dir) + " - it is supposed to be a directory!"); else throw fail("Unknown IO exception during mkdirs of " + f2s(file)); } return file; } public static String mkdirsForFile(String path) { mkdirsForFile(new File(path)); return path; } static File copyFile(File src, File dest) { try { FileInputStream inputStream = new FileInputStream(src.getPath()); FileOutputStream outputStream = newFileOutputStream(dest.getPath()); try { copyStream(inputStream, outputStream); inputStream.close(); } finally { outputStream.close(); } return dest; } catch (Exception __e) { throw rethrow(__e); } } static FileOutputStream newFileOutputStream(File path) throws IOException { return newFileOutputStream(path.getPath()); } static FileOutputStream newFileOutputStream(String path) throws IOException { return newFileOutputStream(path, false); } static FileOutputStream newFileOutputStream(File path, boolean append) throws IOException { return newFileOutputStream(path.getPath(), append); } static FileOutputStream newFileOutputStream(String path, boolean append) throws IOException { mkdirsForFile(path); FileOutputStream f = new FileOutputStream(path, append); _registerIO(f, path, true); return f; } static List _registerWeakMap_preList; static A _registerWeakMap(A map) { if (javax() == null) { // We're in class init if (_registerWeakMap_preList == null) _registerWeakMap_preList = synchroList(); _registerWeakMap_preList.add(map); return map; } try { call(javax(), "_registerWeakMap", map); } catch (Throwable e) { printException(e); print("Upgrade JavaX!!"); } return map; } static void _onLoad_registerWeakMap() { assertNotNull(javax()); if (_registerWeakMap_preList == null) return; for (Object o : _registerWeakMap_preList) _registerWeakMap(o); _registerWeakMap_preList = null; } static x30_pkg.x30_util.BetterThreadLocal newPing_actionTL; static x30_pkg.x30_util.BetterThreadLocal newPing_actionTL() { if (newPing_actionTL == null) newPing_actionTL = vm_generalMap_getOrCreate("newPing_actionTL", () -> { Runnable value = (Runnable) (callF_gen(vm_generalMap_get("newPing_valueForNewThread"))); var tl = new x30_pkg.x30_util.BetterThreadLocal(); tl.set(value); return tl; }); return newPing_actionTL; } static int isAndroid_flag; static boolean isAndroid() { if (isAndroid_flag == 0) isAndroid_flag = System.getProperty("java.vendor").toLowerCase().indexOf("android") >= 0 ? 1 : -1; return isAndroid_flag > 0; } static Boolean isHeadless_cache; static boolean isHeadless() { if (isHeadless_cache != null) return isHeadless_cache; if (isAndroid()) return isHeadless_cache = true; if (GraphicsEnvironment.isHeadless()) return isHeadless_cache = true; // Also check if AWT actually works. // If DISPLAY variable is set but no X server up, this will notice. try { SwingUtilities.isEventDispatchThread(); return isHeadless_cache = false; } catch (Throwable e) { return isHeadless_cache = true; } } static String joinSubList_cToC(List l, int i, int j) { return joinSubList(l, i | 1, j & ~1); } static List dropAfter(A a, List l) { int n = l(l); for (int i = 0; i < n; i++) if (eq(a, l.get(i))) return takeFirst(l, i); return l; } static void addToContainer(Container a, Component... b) { if (a == null) return; { swing(() -> { for (Component c : unnullForIteration(b)) if (c != null) a.add(c); }); } } static String trimSubstring(String s, int x) { return trim(substring(s, x)); } static String trimSubstring(String s, int x, int y) { return trim(substring(s, x, y)); } static String trimSubstring(String s, IntRange r) { return trim(substring(s, r)); } static String trimSubstring(int x, String s) { return trimSubstring(s, x); } static int smartLastIndexOf(String s, char c) { if (s == null) return 0; int i = s.lastIndexOf(c); return i >= 0 ? i : l(s); } static int smartLastIndexOf(List l, A sub) { int i = lastIndexOf(l, sub); return i < 0 ? l(l) : i; } static A proxy(Class intrface, final Object target) { if (target == null) return null; if (isInstance(intrface, target)) return (A) target; return (A) java.lang.reflect.Proxy.newProxyInstance(intrface.getClassLoader(), new Class[] { intrface }, new proxy_InvocationHandler(target)); } static A proxy(Object target, Class intrface) { return proxy(intrface, target); } static Object vm_generalMap_get(Object key) { return vm_generalMap().get(key); } static File localSnippetFile(long snippetID) { return localSnippetsDir(snippetID + ".text"); } static File localSnippetFile(String snippetID) { return localSnippetFile(parseSnippetID(snippetID)); } static String or2(String a, String b) { return nempty(a) ? a : b; } static String or2(String a, String b, String c) { return or2(or2(a, b), c); } static String getFileInfoField(File f, String field) { return getOneLineFileInfoField(f, field); } static File dropExtension(File f) { return f == null ? null : fileInSameDir(f, dropExtension(f.getName())); } static String dropExtension(String s) { return takeFirst(s, smartLastIndexOf(s, '.')); } static File javaxDataDir_dir; // can be set to work on different base dir static File javaxDataDir() { return javaxDataDir_dir != null ? javaxDataDir_dir : new File(userHome(), "JavaX-Data"); } static File javaxDataDir(String... subs) { return newFile(javaxDataDir(), subs); } static String htmlQuery(Map params) { return empty(params) ? "" : "?" + makePostData(params); } static String htmlQuery(Object... data) { return empty(data) ? "" : "?" + makePostData(data); } static Object[] muricaCredentials() { String pass = muricaPassword(); return nempty(pass) ? new Object[] {"_pass", pass } : new Object[0]; } static boolean networkAllowanceTest(String url) { return isAllowed("networkAllowanceTest", url); } static void sleepSeconds(double s) { if (s > 0) sleep(round(s*1000)); } static A printWithTime(A a) { return printWithTime("", a); } static A printWithTime(String s, A a) { print(hmsWithColons() + ": " + s, a); return a; } static A getAndClearThreadLocal(ThreadLocal tl) { A a = tl.get(); tl.set(null); return a; } static void setHeaders(URLConnection con) throws IOException { String computerID = getComputerID_quick(); if (computerID != null) try { con.setRequestProperty("X-ComputerID", computerID); con.setRequestProperty("X-OS", System.getProperty("os.name") + " " + System.getProperty("os.version")); } catch (Throwable e) { //printShortException(e); } } static Map vm_generalSubMap(Object name) { synchronized(vm_generalMap()) { Map map = (Map) (vm_generalMap_get(name)); if (map == null) vm_generalMap_put(name, map = synchroMap()); return map; } } static InputStream urlConnection_getInputStream(URLConnection con) throws IOException { return con.getInputStream(); } static GZIPInputStream newGZIPInputStream(File f) { return gzInputStream(f); } static GZIPInputStream newGZIPInputStream(InputStream in) { return gzInputStream(in); } static String toHex(byte[] bytes) { return bytesToHex(bytes); } static String toHex(byte[] bytes, int ofs, int len) { return bytesToHex(bytes, ofs, len); } static byte[] utf8(String s) { return toUtf8(s); } static Matcher regexpMatcher(String pat, String s) { return compileRegexp(pat).matcher(unnull(s)); } static Matcher regexpMatcher(java.util.regex.Pattern pat, String s) { return pat.matcher(unnull(s)); } static URLConnection openConnection(String url) { try { return openConnection(new URL(url)); } catch (Exception __e) { throw rethrow(__e); } } static URLConnection openConnection(URL url) { try { ping(); callOpt(javax(), "recordOpenURLConnection", str(url)); return url.openConnection(); } catch (Exception __e) { throw rethrow(__e); } } static int toInt(Object o) { if (o == null) return 0; if (o instanceof Number) return ((Number) o).intValue(); if (o instanceof String) return parseInt((String) o); if (o instanceof Boolean) return boolToInt((Boolean) o); throw fail("woot not int: " + getClassName(o)); } static int toInt(long l) { if (l != (int) l) throw fail("Too large for int: " + l); return (int) l; } static URLConnection setURLConnectionTimeouts(URLConnection con, long timeout) { con.setConnectTimeout(toInt(timeout)); con.setReadTimeout(toInt(timeout)); if (con.getConnectTimeout() != timeout || con.getReadTimeout() != timeout) print("Warning: Timeouts not set by JDK."); return con; } static URLConnection setURLConnectionDefaultTimeouts(URLConnection con, long timeout) { if (con.getConnectTimeout() == 0) { con.setConnectTimeout(toInt(timeout)); if (con.getConnectTimeout() != timeout) print("Warning: URL connect timeout not set by JDK."); } if (con.getReadTimeout() == 0) { con.setReadTimeout(toInt(timeout)); if (con.getReadTimeout() != timeout) print("Warning: URL read timeout not set by JDK."); } return con; } static boolean saveTextFileIfDifferent(File f, String contents) { if (eq(loadTextFile(f), contents)) return false; // TODO: optimize { saveTextFile(f, contents); return true; } } static Throwable getInnerException(Throwable e) { if (e == null) return null; while (e.getCause() != null) e = e.getCause(); return e; } static Throwable getInnerException(Runnable r) { return getInnerException(getException(r)); } static String baseClassName(String className) { return substring(className, className.lastIndexOf('.')+1); } static String baseClassName(Object o) { return baseClassName(getClassName(o)); } static String prependIfNempty(String prefix, String s) { return empty(s) ? unnull(s) : prefix + s; } static String lastIdentifier(List l) { for (int i = l(l)-1; i >= 0; i--) { String t = l.get(i); if (isIdentifier(t)) return t; } return null; } static List tok_parseArgsList(String s) { return tok_parseArgsList(javaTok(s)); } static List tok_parseArgsList(List tok) { return tok_parseArgsList(tok, getBracketMap(tok)); } static List tok_parseArgsList(List tok, Map bracketMap) { int i = indexOfAny(tok, 0, "(", "{"); if (i < 0) return null; if (eq(get(tok, i), "{")) return ll(); // e.g. void bla { ... } int argStart = (i += 2); List args = new ArrayList(); while (i < l(tok)-2 && neq(get(tok, i), ")")) { Integer j = bracketMap.get(i); if (j != null) { i = j+2; continue; } if (eqGetOneOf(tok, i, ",")) { if (i > argStart) args.add(trimJoinSubList(tok, argStart, i)); argStart = i+2; } i += 2; } if (i > argStart) args.add(trimJoinSubList(tok, argStart, i)); return args; } static HashSet getBracketMapIncludingAngleBrackets_opening = lithashset("(", "{", "<"); static HashSet getBracketMapIncludingAngleBrackets_closing = lithashset(")", "}", ">"); static Map getBracketMapIncludingAngleBrackets(List tok) { return getBracketMap(tok, getBracketMapIncludingAngleBrackets_opening, getBracketMapIncludingAngleBrackets_closing); } static Map getBracketMapIncludingAngleBrackets(List tok, int from, int to) { return getBracketMap(tok, getBracketMapIncludingAngleBrackets_opening, getBracketMapIncludingAngleBrackets_closing, from, to); } static ArrayList intArrayToList(int[] a) { if (a == null) return null; return intArrayToList(a, 0, a.length); } // no range checking on from/to in the interest of S P E E E E E EEED static ArrayList intArrayToList(int[] a, int from, int to) { if (a == null) return null; ArrayList < Integer > l = new ArrayList<>(to-from); for (int i = from; i < to; i++) l.add(a[i]); return l; } static boolean nemptyString(String s) { return s != null && s.length() > 0; } static int listL(Collection l) { return l == null ? 0 : l.size(); } static String beautifyStructure(String s) { List tok = javaTokForStructure(s); structure_addTokenMarkers(tok); jreplace(tok, "lhm", ""); return join(tok); } // works on lists and strings and null static int indexOfIgnoreCase(List a, String b) { return indexOfIgnoreCase(a, b, 0); } static int indexOfIgnoreCase(List a, String b, int i) { int n = a == null ? 0 : a.size(); for (; i < n; i++) if (eqic(a.get(i), b)) return i; return -1; } static int indexOfIgnoreCase(String[] a, String b) { return indexOfIgnoreCase(a, b, 0); } static int indexOfIgnoreCase(String[] a, String b, int i) { int n = a == null ? 0 : a.length; for (; i < n; i++) if (eqic(a[i], b)) return i; return -1; } static int indexOfIgnoreCase(String a, String b) { return indexOfIgnoreCase_manual(a, b); /*Matcher m = Pattern.compile(b, Pattern.CASE_INSENSITIVE + Pattern.LITERAL).matcher(a); if (m.find()) return m.start(); else ret -1;*/ } static int indexOfIgnoreCase(String a, String b, int i) { return indexOfIgnoreCase_manual(a, b, i); } static String lineRange(String s, int from, int to) { return lines(subList(lines(s), from, to)); // optimizable } static Matcher regexpIC(Pattern pat, String s) { return pat.matcher(unnull(s)); } static Matcher regexpIC(String pat, String s) { return compileRegexpIC(pat).matcher(unnull(s)); } static Pattern regexpIC(String pat) { return compileRegexpIC(pat); } static int cmp(Number a, Number b) { return a == null ? b == null ? 0 : -1 : cmp(a.doubleValue(), b.doubleValue()); } static int cmp(double a, double b) { return a < b ? -1 : a == b ? 0 : 1; } static int cmp(int a, int b) { return a < b ? -1 : a == b ? 0 : 1; } static int cmp(long a, long b) { return a < b ? -1 : a == b ? 0 : 1; } static int cmp(Object a, Object b) { if (a == null) return b == null ? 0 : -1; if (b == null) return 1; return ((Comparable) a).compareTo(b); } static String _userHome; static String userHome() { if (_userHome == null) return actualUserHome(); return _userHome; } static File userHome(String path) { return new File(userDir(), path); } static File getProgramDir() { return programDir(); } static File getProgramDir(String snippetID) { return programDir(snippetID); } static Producer javaTokC_producer(String s) { return javaTokC_iterator(s); } // scans a Java construct (class, method) and checks its modifiers static boolean hasModifier(List tok, String modifier) { for (int i = 1; i < tok.size() && getJavaModifiers().contains(tok.get(i)); i += 2) if (tok.get(i).equals(modifier)) return true; return false; } static int rfindCodeTokens(List tok, String... tokens) { return rfindCodeTokens(tok, 1, false, tokens); } static int rfindCodeTokens(List tok, boolean ignoreCase, String... tokens) { return rfindCodeTokens(tok, 1, ignoreCase, tokens); } static int rfindCodeTokens(List tok, int startIdx, boolean ignoreCase, String... tokens) { return rfindCodeTokens(tok, startIdx, ignoreCase, tokens, null); } static List rfindCodeTokens_specials = litlist("*", "", "", "", "\\*"); static boolean rfindCodeTokens_debug = false; static int rfindCodeTokens_indexed, rfindCodeTokens_unindexed; static int rfindCodeTokens_bails, rfindCodeTokens_nonbails; static int rfindCodeTokens(List tok, int startIdx, boolean ignoreCase, String[] tokens, Object condition) { return rfindCodeTokens(tok, startIdx, l(tok), ignoreCase, tokens, condition); } static int rfindCodeTokens(List tok, int startIdx, int endIndex, boolean ignoreCase, String[] tokens, Object condition) { if (rfindCodeTokens_debug) { if (eq(getClassName(tok), "main$IndexedList2")) rfindCodeTokens_indexed++; else rfindCodeTokens_unindexed++; } // bail out early if first token not found (works great with IndexedList) if (!rfindCodeTokens_specials.contains(tokens[0]) && !tok.contains(tokens[0] /*, startIdx << no signature in List for this, unfortunately */)) { ++rfindCodeTokens_bails; return -1; } ++rfindCodeTokens_nonbails; outer: for (int i = min(endIndex, tok.size()-tokens.length*2) | 1; i >= startIdx; i -= 2) { for (int j = 0; j < tokens.length; j++) { String p = tokens[j], t = tok.get(i+j*2); boolean match = false; if (eq(p, "*")) match = true; else if (eq(p, "")) match = isQuoted(t); else if (eq(p, "")) match = isIdentifier(t); else if (eq(p, "")) match = isInteger(t); else if (eq(p, "\\*")) match = eq("*", t); else match = ignoreCase ? eqic(p, t) : eq(p, t); if (!match) continue outer; } if (condition == null || checkTokCondition(condition, tok, i-1)) // pass N index return i; } return -1; } static int minUnlessMinus1(int a, int b) { return a == -1 ? b : b == -1 ? a : min(a, b); } static List codeTokens_lazy(final List tok) { return new RandomAccessAbstractList() { final int size = l(tok)/2; public int size() { return size; } public String get(int i) { return tok.get(i*2+1); } }; } static int tok_skipAnnotations(List tok, int i) { while (eqGet(tok, i, "@") && isIdentifier(get(tok, i+2))) i += 4; return i; } static String replaceCurlyBracedWith(String s, String replacement) { return join(replaceCurlyBracedWith(javaTokWithAllBrackets_cached(s), replacement)); } static List replaceCurlyBracedWith(List tok, String replacement) { return mapCodeTokens(t -> isCurlyBraced_simple(t) ? replacement : t, tok); } static List tok_combineCurlyBrackets_keep(List tok) { List l = new ArrayList(); for (int i = 0; i < l(tok); i++) { String t = tok.get(i); if (odd(i) && eq(t, "{")) { int j = findEndOfCurlyBracketPart(tok, i); l.add(joinSubList(tok, i, j)); i = j-1; } else l.add(t); } return l; } static boolean jcontains_any(List tok, String... patterns) { return jcontainsOneOf(tok, patterns); } static boolean even(int i) { return (i & 1) == 0; } static boolean even(long i) { return (i & 1) == 0; } static boolean even(BigInteger n) { return even(n.intValue()); } // TODO: line comments inside of /* */ comments (super-special case) static List getJavaLineComments(String s) { return getJavaLineComments(javaTok(s)); } static List getJavaLineComments(List tok) { List out = new ArrayList(); for (int i = 0; i < l(tok); i += 2) addAll(out, regexpAllFirstGroups("//([^\r\n]*)", tok.get(i))); return out; } static List lambdaMap(IF1 f, Iterable l) { return map(l, f); } static List lambdaMap(IF1 f, A[] l) { return map(l, f); } static B secondOfPair(Pair p) { return p == null ? null : p.b; } static boolean tok_isPrimitiveType(String t) { return eqOneOf(t, "int", "char", "byte", "short", "long", "float", "double", "bool"); } static int hashCode(Object a) { return a == null ? 0 : a.hashCode(); } static int hashCode(long l) { return Long.hashCode(l); } static int hashCode(double d) { return Double.hashCode(d); } static IterableIterator> mapPairs(Map map) { final Iterator> it = map.entrySet().iterator(); return iteratorFromFunction(new F0>() { public Pair get() { try { if (it.hasNext()) { Map.Entry entry = it.next(); return pair(entry.getKey(), entry.getValue()); } return null; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (it.hasNext()) {\r\n Map.Entry entry = it.next();\r\n ret pair..."; }}); } static List mapPairs(Iterable> l, IF2 f) { return mapPairsToList(l, f); } static String joinPrependSpace(Collection l) { return join(prependAll(" ", allToString(l))); } static String joinNempties(String sep, Object... strings) { return joinStrings(sep, strings); } static String joinNempties(String sep, Iterable strings) { return joinStrings(sep, strings); } static Map mapKeys(Object func, Map map) { Map m = similarEmptyMap(map); // TODO: this might break when key type changes through func for (Object key : keys(map)) m.put(callF(func, key), map.get(key)); return m; } static Map mapKeys(Map map, Object func) { return mapKeys(func, map); } static Map mapKeys(Map map, IF1 func) { return mapKeys(map, (Object) func); } static Map mapKeys(IF1 func, Map map) { return mapKeys(map, func); } static MultiMap mapKeys(IF1 f, MultiMap mm) { return mapMultiMapKeys(f, mm); } static MultiSetMap mapKeys(IF1 f, MultiSetMap mm) { return mapMultiSetMapKeys(f, mm); } static String addDollarPrefix(String s) { return addPrefix("$", s); } static String strOrNull(Object o) { return o == null ? null : str(o); } static Map paramsToMap(Object... params) { int n = l(params); if (l(params) == 1 && params[0] instanceof Map) return (Map) params[0]; LinkedHashMap map = new LinkedHashMap(); for (int i = 0; i+1 < n; i += 2) mapPut(map, params[i], params[i+1]); return map; } // i must point at the (possibly imaginary) opening bracket ("{") // index returned is index of closing bracket + 1 (or l(tok)) // version using iterator (much faster than v1!) static int tok_findEndOfBlock_IContentsIndexedList2_v2(IContentsIndexedList2 tok, int i) { int n = l(tok); // find opening & closing brackets after start index HasIndex start = new HasIndex(i); TreeSet openers = tok.indicesOf_treeSetOfHasIndex("{"); Iterator iOpener = openers == null ? null : openers.tailSet(start, false).iterator(); TreeSet closers = tok.indicesOf_treeSetOfHasIndex("}"); Iterator iCloser = closers == null ? null : closers.tailSet(start, false).iterator(); // now step through both sets int level = 1; HasIndex nextOpener = iOpener != null && iOpener.hasNext() ? iOpener.next() : null; HasIndex nextCloser = iCloser != null && iCloser.hasNext() ? iCloser.next() : null; while (true) { if (nextCloser == null) return n; // block isn't closed if (nextOpener != null && nextOpener.idx < nextCloser.idx) { // process opener ++level; nextOpener = iOpener.hasNext() ? iOpener.next() : null; } else { // process closer if (--level == 0) return nextCloser.idx+1; nextCloser = iCloser.hasNext() ? iCloser.next() : null; } } } static boolean isUpperCase(char c) { return Character.isUpperCase(c); } static char charAt(String s, int i) { return s != null && i >= 0 && i < s.length() ? s.charAt(i) : '\0'; } static List firstOfPairs(Collection> l) { List out = new ArrayList(); for (Pair p : unnull(l)) out.add(firstOfPair(p)); return out; } static String reversedString(String s) { return reverseString(s); } static boolean tok_isAssignment(List tok, int i) { if (!eqGet(tok, i, "=")) return false; if (nempty(get(tok, i+1))) return true; if (eqGet(tok, i+2, "=")) return false; return true; } static void tok_insertCast(List tok, int i, String type) { String expr = tok.get(i); String prev = get(tok, i-2), next = get(tok, i+2); boolean needBrackets = !( doubleEq(prev, "=", next, ";") || doubleEq(prev, "(", next, ")") ); tok.set(i, roundBracketIf(needBrackets, "(" + type + ") " + expr)); } static List allToUpper(Collection l) { List x = new ArrayList(l(l)); if (l != null) for (String s : l) x.add(upper(s)); return x; } static void copyListPart(List a, int i1, List b, int i2, int n) { if (a == null || b == null) return; for (int i = 0; i < n; i++) b.set(i2+i, a.get(i1+i)); } static List splitByJavaToken(String s, String splitToken) { List tok = javaTok(s); List l = new ArrayList(); int i = 1; while (i < l(tok)) { int j = smartIndexOf(tok, splitToken, i); l.add(join(subList(tok, i, j-1))); i = j+2; } return l; } static String dollarVarsToStars(String s) { return dollarVarsToStars(s, null); } static String dollarVarsToStars(String s, List varNames_out) { List tok = javaTok(s); for (int i = 1; i < l(tok); i += 2) { String t = tok.get(i); if (isDollarVar(t)) { listAdd(varNames_out, t); tok.set(i, "*"); } else if (eq(t, "*")) listAdd(varNames_out, "*"); } return join(tok); } static List mapWithIndexStartingAt1(Collection l, IF2 f) { int n = l(l), i = 0; List out = emptyList(n); for (A a : unnullForIteration(l)) out.add(f.get(++i, a)); return out; } static boolean containsDollarVars(String s) { for (String t : javaTokC(s)) if (isDollarVar(t)) return true; return false; } static String appendColonIfNempty(String s) { return empty(s) ? "" : s + ": "; } static boolean isEmpty(Collection c) { return c == null || c.isEmpty(); } static boolean isEmpty(File f) { return f == null || f.length() == 0; } static boolean isEmpty(CharSequence s) { return s == null || s.length() == 0; } static boolean isEmpty(Object[] a) { return a == null || a.length == 0; } static boolean isEmpty(byte[] a) { return a == null || a.length == 0; } static boolean isEmpty(Map map) { return map == null || map.isEmpty(); } static boolean isEmpty(AppendableChain c) { return c == null; } static boolean isEmpty(IntSize l) { return l == null || l.size() == 0; } static int tok_skipModifiers(List tok, int i) { List mod = getJavaModifiers(); while (i < l(tok) && mod.contains(tok.get(i))) i += 2; return i; } static List similarEmptyList(Collection m) { return new ArrayList(); } // i must point at the opening bracket ("<") // index returned is index of closing bracket or comma static int tok_findEndOfTypeArg(List cnc, int i) { int j = i+2, level = 1; while (j < cnc.size()) { String t = cnc.get(j); if (t.equals("<")) ++level; else if (t.equals(">")) --level; if (level == 0 || level == 1 && eq(t, ",")) return j; ++j; } return cnc.size(); } static int indexOfOneOf(List l, int i, A... x) { return indexOfAny(l, i, x); } static int indexOfOneOf(List l, Collection x) { return indexOfAny(l, x); } static int indexOfOneOf(List l, int i, Collection x) { return indexOfAny(l, i, x); } static int indexOfOneOf(String s, int i, String chars) { return indexOfAny(s, i, chars); } static boolean subListEq(List l, List pat, int i) { return subListEquals(l, pat, i); } static boolean subListEq(List l, int i, A... pat) { return subListEquals(l, i, pat); } static String replaceSuffix(String a, String b, String s) { return endsWith(s, a) ? dropLast(s, l(a)) + b : s; } static Producer javaTokC_iterator(String s) { return new Producer() { final int l = strL(s); int i = 0; public String next() { if (i >= l) return null; 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 && !s.substring(j, Math.min(j+2, l)).equals("*/")); j = Math.min(j+2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } i = j; if (i >= l) return null; c = s.charAt(i); d = i+1 >= l ? '\0' : s.charAt(i+1); // scan for non-whitespace if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { if (s.charAt(j) == opener || s.charAt(j) == '\n') { // end at \n to not propagate unclosed string literal errors ++j; break; } else if (s.charAt(j) == '\\' && j+1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || "'".indexOf(s.charAt(j)) >= 0)); // 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+1 < l && !s.substring(j, j+2).equals("]]")); j = Math.min(j+2, l); } else if (c == '[' && d == '=' && i+2 < l && s.charAt(i+2) == '[') { do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]")); j = Math.min(j+3, l); } else ++j; String t = quickSubstring(s, i, j); i = j; return t; } }; } static boolean containsToken(List tok, String token) { return tok.contains(token); } static Set javaxModifiers_cache; static Set javaxModifiers() { if (javaxModifiers_cache == null) javaxModifiers_cache = javaxModifiers_load(); return javaxModifiers_cache;} static Set javaxModifiers_load() { return litset("mapLike", "mapMethodLike", "nuLike", "lambdaMapLike"); } static String joinNemptiesWithSpace(String... strings) { return joinNempties(" ", strings); } static String joinNemptiesWithSpace(Collection strings) { return joinNempties(" ", strings); } static List flattenCollections(Iterable a) { List l = new ArrayList(); for (Object x : a) if (x instanceof Collection) l.addAll(flattenCollections((Collection) x)); else l.add(x); return l; } static String stringIfTrue(boolean b, String s) { return b ? s : ""; } // Use like this: renderVars(+x, +y) // Or like this: renderVars("bla", +x, +y) static String renderVars_str(Object... params) { List l = new ArrayList(); int i = 0; if (odd(l(params))) { l.add(strOrNull(first(params))); ++i; } for (; i+1 < l(params); i += 2) l.add(params[i] + "=" + params[i+1]); return trim(joinWithComma(l)); } static String dropDollarPrefix(String s) { return dropPrefix("$", s); } static TreeMap litcimap(Object... x) { return litCIMap(x); } // f takes variable without $ sign. if it returns null, variable is kept static String replaceDollarVars_dyn(String s, IF1 f) { if (f == null) return s; return regexpReplaceIC(s, "\\$(\\w+)", matcher -> { String var = matcher.group(1); String val = f.get(var); return val == null ? matcher.group() : str(val); }); } static boolean startsWithIgnoreCase(String a, String b) { return regionMatchesIC(a, 0, b, 0, b.length()); } static boolean isDigit(char c) { return Character.isDigit(c); } static String toLower(String s) { return s == null ? null : s.toLowerCase(); } static char toLower(char c) { return Character.toLowerCase(c); } static List words(String s) { return codeTokens(dropPunctuation(javaTok(s))); } // i must point at the opening bracket (<) // index returned is index of closing bracket (>) // If there is NO opening bracket at i, we return nothing static int tok_findEndOfAngleBracketPart(List tok, int i) { int level = 0, n = l(tok); while (i < n) { ping(); String t = tok.get(i); if (eq(t, "<")) ++level; if (level < 1) return i-2; if (eq(t, ">")) --level; if (level < 1) return i; i += 2; } return n; } static boolean isSpaceEtc(char c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n'; } static List allToString(Iterable c) { List l = new ArrayList(); for (Object o : unnull(c)) l.add(str(o)); return l; } static List allToString(Object[] c) { List l = new ArrayList(); for (Object o : unnull(c)) l.add(str(o)); return l; } // binary legacy signature static Object[] toObjectArray(Collection c) { return toObjectArray((Iterable) c); } static Object[] toObjectArray(Iterable c) { List l = asList(c); return l.toArray(new Object[l.size()]); } static List flattenCollectionsAndArrays(Iterable a) { List l = new ArrayList(); for (Object x : a) if (x instanceof Collection) l.addAll(flattenCollectionsAndArrays((Collection) x)); else if (x instanceof Object[]) l.addAll(flattenCollectionsAndArrays(asList((Object[]) x))); else l.add(x); return l; } static List flattenCollectionsAndArrays(Object... whatever) { return flattenCollectionsAndArrays(ll(whatever)); } static boolean tok_isSingleIdentifier(String src) { return tok_isSingleIdentifier(javaTok(src)); } static boolean tok_isSingleIdentifier(List tok) { return l(tok) == 3 && isIdentifier(tok.get(1)); } static A pairA(Pair p) { return p == null ? null : p.a; } static B pairB(Pair p) { return p == null ? null : p.b; } static Object evalJava(String code) { return evalJava_main(evalJava_prep(code)); } static Class actualMC() { return or((Class) realMC(), mc()); } static boolean startsWithOneOf(String s, String... l) { for (String x : l) if (startsWith(s, x)) return true; return false; } static boolean startsWithOneOf(String s, Matches m, String... l) { for (String x : l) if (startsWith(s, x, m)) return true; return false; } static boolean isSubclass(Class a, Class b) { return a != null && b != null && b.isAssignableFrom(a); } static boolean isAnonymousClassName(String s) { for (int i = 0; i < l(s); i++) if (s.charAt(i) == '$' && Character.isDigit(s.charAt(i+1))) return true; return false; } // Note: This is actually broken. Inner classes must stay with a $ separator static String classNameToVM(String name) { return name.replace(".", "$"); } static String shortenClassName(String name) { if (name == null) return null; int i = lastIndexOf(name, "$"); if (i < 0) i = lastIndexOf(name, "."); return i < 0 ? name : substring(name, i+1); } static boolean isBoxedType(Class type) { return type == Boolean.class || type == Integer.class || type == Long.class || type == Float.class || type == Short.class || type == Character.class || type == Byte.class || type == Double.class; } static boolean isArrayType(Class type) { return type != null && type.isArray(); } static boolean hasThisDollarFields(Object o) { Matches m = new Matches(); for (var f : allFieldObjects_dontMakeAccessible(o)) if (startsWith(f.getName(), "this$", m) && isInteger(m.rest())) return true; return false; } static boolean hasSingleArgumentConstructor(Class c) { if (c != null) for (Constructor m : getDeclaredConstructors_cached(c)) if (l(m.getParameterTypes()) == 1) return true; return false; } // TODO: convert to regularly cleared normal map static Map getDeclaredConstructors_cached_cache = newDangerousWeakHashMap(); static Constructor[] getDeclaredConstructors_cached(Class c) { Constructor[] ctors; synchronized(getDeclaredConstructors_cached_cache) { ctors = getDeclaredConstructors_cached_cache.get(c); if (ctors == null) { getDeclaredConstructors_cached_cache.put(c, ctors = c.getDeclaredConstructors()); for (var ctor : ctors) makeAccessible(ctor); } } return ctors; } static String shortClassName(Object o) { if (o == null) return null; Class c = o instanceof Class ? (Class) o : o.getClass(); String name = c.getName(); return shortenClassName(name); } static byte[] boolArrayToBytes(boolean[] a) { byte[] b = new byte[(l(a)+7)/8]; for (int i = 0; i < l(a); i++) if (a[i]) b[i/8] |= 1 << (i & 7); return b; } static byte[] byteArrayFromShorts_bigEndian(short[] a) { return byteArrayFromShorts_bigEndian(a, 0, l(a)); } static byte[] byteArrayFromShorts_bigEndian(short[] a, int from, int to) { byte[] b = new byte[(to-from)*2]; for (int i = 0; i < a.length; i++) { short s = a[from+i]; b[i*2] = (byte) (s >> 8); b[i*2+1] = (byte) s; } return b; } static byte[] byteArrayFromLongs_bigEndian(long[] a) { return byteArrayFromLongs_bigEndian(a, 0, l(a)); } static byte[] byteArrayFromLongs_bigEndian(long[] a, int from, int to) { byte[] b = new byte[(to-from)*8]; for (int i = 0; i < a.length; i++) { long s = a[from+i]; b[i*8] = (byte) (s >> 56); b[i*8+1] = (byte) (s >> 48); b[i*8+2] = (byte) (s >> 40); b[i*8+3] = (byte) (s >> 32); b[i*8+4] = (byte) (s >> 24); b[i*8+5] = (byte) (s >> 16); b[i*8+6] = (byte) (s >> 8); b[i*8+7] = (byte) s; } return b; } static List> mapPairB(final Object f, Iterable> l) { return map(l, new F1, Pair>() { public Pair get(Pair p) { try { return p == null ? null : pair(p.a, (C) callF(f, p.b)); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "p == null ? null : pair(p.a, (C) callF(f, p.b))"; }}); } static List> mapPairB(final F1 f, Iterable> l) { return mapPairB((Object) f, l); } static List> mapPairB(final IF1 f, Iterable> l) { return mapPairB((Object) f, l); } static List> mapPairB(Iterable> l, IF1 f) { return mapPairB((Object) f, l); } static Pair mapPairB(IF1 f, Pair p) { return pairMapB(f, p); } static Pair mapPairB(Pair p, IF1 f) { return pairMapB(f, p); } static Method findMethod(Object o, String method, Object... args) { return findMethod_cached(o, method, args); } static boolean findMethod_checkArgs(Method m, Object[] args, boolean debug) { Class[] types = m.getParameterTypes(); if (types.length != args.length) { if (debug) System.out.println("Bad parameter length: " + args.length + " vs " + types.length); return false; } for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) { if (debug) System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]); return false; } return true; } static Map mapToKey(Iterable l, IF1 f) { return mapToKeys(l, f); } static Map mapToKey(IF1 f, Iterable l) { return mapToKeys(f, l); } static Map> getFieldOrder_cache = weakMap(); static List getFieldOrder(Object o) { return getFieldOrder(_getClass(o)); } static List getFieldOrder(Class c) { if (c == null) return null; return getOrCreate(getFieldOrder_cache, c, () -> splitAtSpace(toStringOpt(getOpt(c, "_fieldOrder")))); } // credits to stackoverflow.com/users/1442960/marcus static String lexicographicallyNextString(String input) { final int lastCharPosition = input.length()-1; String inputWithoutLastChar = input.substring(0, lastCharPosition); char lastChar = input.charAt(lastCharPosition); char incrementedLastChar = (char) (lastChar + 1); // Handle int/char overflow. This wasn't done above. if (incrementedLastChar == ((char) 0)) return input+incrementedLastChar; return inputWithoutLastChar+incrementedLastChar; } static String mainClassNameForClassLoader(ClassLoader cl) { return or((String) callOpt(cl, "mainClassName"), "main"); } static void assertFalse(Object o) { if (!(eq(o, false) /*|| isFalse(pcallF(o))*/)) throw fail(str(o)); } static boolean assertFalse(boolean b) { if (b) throw fail("oops"); return b; } static boolean assertFalse(String msg, boolean b) { if (b) throw fail(msg); return b; } static boolean _inCore() { return false; } static List hotwire_copyOver_after = synchroList(); static void hotwire_copyOver(Class c) { // TODO: make a mechanism for making such "inheritable" fields for (String field : ll("print_log", "print_silent", "androidContext", "_userHome")) setOptIfNotNull(c, field, getOpt(mc(), field)); setOptIfNotNull(c, "mainBot" , getMainBot()); setOpt(c, "creator_class" , new WeakReference(mc())); pcallFAll(hotwire_copyOver_after, c); } // i must point at the (possibly imaginary) closing bracket // index returned is index of opening bracket static int findBeginningOfBlock(List cnc, int i) { int j = i-2, level = 1; while (j > 0) { if (eq(cnc.get(j), "}")) ++level; else if (eq(cnc.get(j), "{")) --level; if (level == 0) return j; j -= 2; } return -1; } static A[] arrayOfSameType(A[] a, int n) { return newObjectArrayOfSameType(a, n); } static List wrapArrayAsList(A[] a) { return a == null ? null : Arrays.asList(a); } static String afterLineBreak(String s) { return substring(s, lastIndexOf(s, '\n')+1); } static String beforeLineBreak(String s) { int i = smartIndexOf(s, '\n'); if (i > 0 && s.charAt(i-1) == '\r') --i; return substring(s, 0, i); } static CloseableIterableIterator linesFromFile(File f) { return linesFromFile(f, null); } static CloseableIterableIterator linesFromFile(File f, IResourceHolder resourceHolder) { try { if (!fileExists(f)) return emptyCloseableIterableIterator(); if (ewic(f.getName(), ".gz")) return linesFromReader(utf8bufferedReader(newGZIPInputStream(f)), resourceHolder); return linesFromReader(utf8bufferedReader(f), resourceHolder); } catch (Exception __e) { throw rethrow(__e); } } static CloseableIterableIterator linesFromFile(String path) { return linesFromFile(path, null); } static CloseableIterableIterator linesFromFile(String path, IResourceHolder resourceHolder) { return linesFromFile(newFile(path), resourceHolder); } static String makeRandomID(int length) { return makeRandomID(length, defaultRandomGenerator()); } static String makeRandomID(int length, Random random) { char[] id = new char[length]; for (int i = 0; i < id.length; i++) id[i] = (char) ((int) 'a' + random.nextInt(26)); return new String(id); } static String makeRandomID(Random r, int length) { return makeRandomID(length, r); } static String standardCredentialsUser() { return trim(loadTextFile( oneOfTheFiles( javaxSecretDir("tinybrain-username"), userDir(".tinybrain/username")))); } static String standardCredentialsPass() { return trim(loadTextFile( oneOfTheFiles( javaxSecretDir("tinybrain-userpass"), userDir(".tinybrain/userpass")))); } static boolean isProperlyQuoted(String s) { return s.length() >= 2 && s.startsWith("\"") && s.endsWith("\"") && (!s.endsWith("\\\"") || s.endsWith("\\\\\"")) && !containsNewLine(s); } static Matcher regexp(String pat, String s) { return regexp(compileRegexp(pat), unnull(s)); } static Matcher regexp(java.util.regex.Pattern pat, String s) { return pat.matcher(unnull(s)); } static java.util.regex.Pattern regexp(String pat) { return compileRegexp(pat); } static Object jsonDecode(String text) { return new jsonDecode_Y(text).parse(); } // the miraculous class Y static class jsonDecode_Y { String text; List tok; boolean useOrderedMaps = false; int i = 1; jsonDecode_Y(String text) { this.text = text; tok = jsonTok(text); } transient IF1 fail; RuntimeException fail(String msg) { return fail != null ? fail.get(msg) : fail_base(msg); } final RuntimeException fail_fallback(IF1 _f, String msg) { return _f != null ? _f.get(msg) : fail_base(msg); } RuntimeException fail_base(String msg) { return main.fail(msg); } Object parse() { if (l(tok) == 1) return null; return parseExpr(); } Object parseExpr() { String t = tok.get(i); if (t.startsWith("\"") || t.startsWith("'")) { String s = unquote(tok.get(i)); i += 2; return s; } if (t.equals("{")) return parseMap(); if (t.equals("[")) return this.parseList(); // avoid loading standard function "parseList" if (t.equals("null")) { i += 2; return null; } if (t.equals("false")) { i += 2; return false; } if (t.equals("true")) { i += 2; return true; } boolean minus = false; if (t.equals("-")) { minus = true; i += 2; t = get(tok, i); } if (isInteger(t)) { int j = i; i += 2; if (eqOneOf(get(tok, i), ".", "e", "E")) { // rough parsing for doubles while (isInteger(get(tok, i)) || eqOneOf(get(tok, i), ".", "e", "E", "-")) i += 2; double d = parseDouble(joinSubList(tok, j, i-1)); if (minus) d = -d; return d; } else { long l = parseLong(t); return boxedIntOrLong(minus ? -l : l); } } throw fail("Unknown token " + (i+1) + ": " + t + ": " + text); } Object parseList() { consume("["); List list = new ArrayList(); while (!tok.get(i).equals("]")) { list.add(parseExpr()); if (tok.get(i).equals(",")) i += 2; } consume("]"); return list; } Object parseMap() { consume("{"); Map map = useOrderedMaps ? new LinkedHashMap() : new TreeMap(); while (!tok.get(i).equals("}")) { String key = unquote(tok.get(i)); i += 2; consume(":"); Object value = parseExpr(); map.put(key, value); if (tok.get(i).equals(",")) i += 2; } consume("}"); return map; } void consume(String s) { if (!tok.get(i).equals(s)) { String prevToken = i-2 >= 0 ? tok.get(i-2) : ""; String nextTokens = join(tok.subList(i, Math.min(i+4, tok.size()))); throw fail(quote(s) + " expected: " + prevToken + " " + nextTokens + " (" + i + "/" + tok.size() + ")"); } i += 2; } } static String makePostData(Map map) { StringBuilder buf = new StringBuilder(); for (Map.Entry e : castMapToMapO(map).entrySet()) { String key = (String) (e.getKey()); Object val = e.getValue(); if (val != null) { String value = str(val); if (nempty(buf)) buf.append("&"); buf.append(urlencode(key)).append("=").append(urlencode(/*escapeMultichars*/(value))); } } return str(buf); } static String makePostData(Object... params) { StringBuilder buf = new StringBuilder(); int n = l(params); for (int i = 0; i+1 < n; i += 2) { String key = (String) (params[i]); Object val = params[i+1]; if (val != null) { String value = str(val); if (nempty(buf)) buf.append("&"); buf.append(urlencode(key)).append("=").append(urlencode(/*escapeMultichars*/(value))); } } return str(buf); } static int lUtf8(String s) { return l(utf8(s)); } static String loadPage_utf8(URL url) { return loadPage_utf8(url.toString()); } static String loadPage_utf8(String url) { AutoCloseable __1 = tempSetTL(loadPage_charset, "UTF-8"); try { return loadPage(url); } finally { _close(__1); }} static String loadPage_utf8(URLConnection con, URL url, boolean addHeaders) throws IOException { AutoCloseable __2 = tempSetTL(loadPage_charset, "UTF-8"); try { return loadPage(con, url, addHeaders); } finally { _close(__2); }} static List tlft(String s) { return toLinesFullTrim(s); } static List tlft(File f) { return toLinesFullTrim(f); } static String joinLines(List lines) { return fromLines(lines); } static String joinLines(String glue, String text) { return join(glue, toLines(text)); } static String javaDropComments(String s) { return javaDropAllComments(s); } static Charset utf8charset_cache; static Charset utf8charset() { if (utf8charset_cache == null) utf8charset_cache = utf8charset_load(); return utf8charset_cache;} static Charset utf8charset_load() { return Charset.forName("UTF-8"); } // f: A -> Comparable static List sortInPlaceByCalculatedField(List l, final F1 f) { sort(l, new Comparator() { public int compare(A a, A b) { return stdcompare(f.get(a), f.get(b)); } }); return l; } static List sortInPlaceByCalculatedField(List l, final IF1 f) { sort(l, new Comparator() { public int compare(A a, A b) { return stdcompare(f.get(a), f.get(b)); } }); return l; } static Rect toRect(Rectangle r) { return r == null ? null : new Rect(r); } static Rect toRect(RectangularShape r) { return r == null ? null : toRect(r.getBounds()); } static Rect toRect(Rect r) { return r; } // returns index of trailing N token static int scanToEndOfInitializer(List tok, Map bracketMap, int i) { while (i < l(tok)) { if (eqOneOf(tok.get(i), ";", ",", ")", "}")) return i-1; Integer j = bracketMap.get(i); if (j != null) i = j+1; else i++; } return i; } static boolean odd(int i) { return (i & 1) != 0; } static boolean odd(long i) { return (i & 1) != 0; } static boolean odd(BigInteger i) { return odd(toInt(i)); } static int charIndexToUserLandLineNr(String text, int charIndex) { int i = 0, row = 1; charIndex = min(charIndex, l(text)); while (i < charIndex) { i = smartIndexOf(text, '\n', i)+1; if (charIndex < i) break; ++row; if (charIndex == i) break; } return row; } static Map singular_specials = litmap( "children", "child", "images", "image", "chess", "chess"); static Set singular_specials2 = litciset("time", "machine", "line", "rule"); static String singular(String s) { if (s == null) return null; { String __1 = singular_specials.get(s); if (!empty(__1)) return __1; } //try answer hippoSingulars().get(lower(s)); if (singular_specials2.contains(dropSuffix("s", afterLastSpace(s)))) return dropSuffix("s", s); if (s.endsWith("ness")) return s; if (s.endsWith("ges")) return dropSuffix("s", s); if (endsWith(s, "bases")) return dropLast(s); s = dropSuffix("es", s); s = dropSuffix("s", s); return s; } static Set getPlural_specials = litciset("sheep", "fish"); static String getPlural(String s) { if (contains(getPlural_specials, s)) return s; if (ewic(s, "y")) return dropSuffixIgnoreCase("y", s) + "ies"; if (ewicOneOf(s, "ss", "ch")) return s + "es"; if (ewic(s, "s")) return s; return s + "s"; } static Map stdFunctions_cached_map; // name -> snippet ID static Lock stdFunctions_cached_lock = lock(); static Map stdFunctions_cached() { Lock __0 = stdFunctions_cached_lock; lock(__0); try { if (stdFunctions_cached_map == null) stdFunctions_cached_map = stdFunctions_uncached(); return stdFunctions_cached_map; } finally { unlock(__0); } } static synchronized void stdFunctions_clearCache() { stdFunctions_cached_map = null; } static final Map callOpt_cache = newDangerousWeakHashMap(); static Object callOpt_cached(Object o, String methodName, Object... args) { try { if (o == null) return null; if (o instanceof Class) { Class c = (Class) o; _MethodCache cache = callOpt_getCache(c); // TODO: (super-rare) case where method exists static and non-static // with different args Method me = cache.findMethod(methodName, args); if (me == null || (me.getModifiers() & Modifier.STATIC) == 0) return null; return invokeMethod(me, null, args); } else { Class c = o.getClass(); _MethodCache cache = callOpt_getCache(c); Method me = cache.findMethod(methodName, args); if (me == null) return null; return invokeMethod(me, o, args); } } catch (Exception __e) { throw rethrow(__e); } } // no longer synchronizes! (see #1102990) static _MethodCache callOpt_getCache(Class c) { _MethodCache cache = callOpt_cache.get(c); if (cache == null) callOpt_cache.put(c, cache = new _MethodCache(c)); return cache; } static boolean isStaticMethod(Method m) { return methodIsStatic(m); } static Object[] massageArgsForVarArgsCall(Executable m, Object[] args) { Class[] types = m.getParameterTypes(); int n = types.length-1, nArgs = l(args); if (nArgs < n) return null; for (int i = 0; i < n; i++) if (!argumentCompatibleWithType(args[i], types[i])) return null; Class varArgType = types[n].getComponentType(); for (int i = n; i < nArgs; i++) if (!argumentCompatibleWithType(args[i], varArgType)) return null; Object[] newArgs = new Object[n+1]; arraycopy(args, 0, newArgs, 0, n); // TODO: optimize int nVarArgs = nArgs-n; Object varArgs = Array.newInstance(varArgType, nVarArgs); for (int i = 0; i < nVarArgs; i++) Array.set(varArgs, i, args[n+i]); newArgs[n] = varArgs; return newArgs; } static String formatArgumentClasses(Object[] args) { return joinWithComma(map(__68 -> getClassName(__68), args)); } static Map vm_threadInterruptionReasonsMap() { return vm_generalWeakSubMap("Thread interruption reasons"); } static String strOr(Object o, String ifNull) { return o == null ? ifNull : str(o); } static void lockOrFail(Lock lock, long timeout) { try { ping(); vmBus_send("locking", lock, "thread" , currentThread()); if (!lock.tryLock(timeout, TimeUnit.MILLISECONDS)) { String s = "Couldn't acquire lock after " + timeout + " ms."; if (lock instanceof ReentrantLock) { ReentrantLock l = (ReentrantLock) lock; s += " Hold count: " + l.getHoldCount() + ", owner: " + call(l, "getOwner"); } throw fail(s); } vmBus_send("locked", lock, "thread" , currentThread()); ping(); } catch (Exception __e) { throw rethrow(__e); } } static ReentrantLock fairLock() { return new ReentrantLock(true); } static List dependentClasses() { return cleanUpAndGetWeakReferencesList(hotwire_classes); } static int[] subIntArray(int[] b, int start) { return subIntArray(b, start, l(b)); } static int[] subIntArray(int[] b, int start, int end) { start = max(start, 0); end = min(end, l(b)); if (start == 0 && end == l(b)) return b; if (start >= end) return new int[0]; int[] x = new int[end-start]; System.arraycopy(b, start, x, 0, end-start); return x; } static int[] subIntArray(int[] a, IntRange r) { return r == null ? null : subIntArray(a, r.start, r.end); } static short[] subShortArray(short[] b, int start, int end) { start = max(start, 0); end = min(end, l(b)); if (start == 0 && end == l(b)) return b; if (start >= end) return new short[0]; short[] x = new short[end-start]; System.arraycopy(b, start, x, 0, end-start); return x; } static byte[] subByteArray(byte[] b, int start) { return subByteArray(b, start, l(b)); } static byte[] subByteArray(byte[] b, int start, int end) { start = max(start, 0); end = min(end, l(b)); if (start == 0 && end == l(b)) return b; if (start >= end) return new byte[0]; byte[] x = new byte[end-start]; System.arraycopy(b, start, x, 0, end-start); return x; } static byte[] subByteArray(byte[] b, IntRange r) { return r == null ? null : subByteArray(b, r.start, r.end); } static double[] subDoubleArray(double[] b, int start) { return subDoubleArray(b, start, l(b)); } static double[] subDoubleArray(double[] b, int start, int end) { start = max(start, 0); end = min(end, l(b)); if (start == 0 && end == l(b)) return b; if (start >= end) return new double[0]; double[] x = new double[end-start]; System.arraycopy(b, start, x, 0, end-start); return x; } static Map similarEmptyMap(Map m) { if (m instanceof TreeMap) return new TreeMap(((TreeMap) m).comparator()); if (m instanceof LinkedHashMap) return new LinkedHashMap(); // default to a hash map return new HashMap(); } static Map similarEmptyMap(Iterable m) { if (m instanceof TreeSet) return new TreeMap(((TreeSet) m).comparator()); if (m instanceof LinkedHashSet) return new LinkedHashMap(); return new HashMap(); } static List> hotwire_classes = synchroList(); static Class hotwireDependent(String src) { Class c = hotwire(src); makeDependent(c); return c; } static char lastChar(String s) { return empty(s) ? '\0' : s.charAt(l(s)-1); } static PersistableThrowable persistableThrowable(Throwable e) { return e == null ? null : new PersistableThrowable(e); } static boolean isAGIBlueDomain(String domain) { return domainIsUnder(domain, theAGIBlueDomain()); } static String hostNameFromURL(String url) { try { return empty(url) ? null : new URL(url).getHost(); } catch (Exception __e) { throw rethrow(__e); } } static Object pcallF_minimalExceptionHandling(Object f, Object... args) { try { return callFunction(f, args); } catch (Throwable e) { System.out.println(getStackTrace(e)); _storeException(e); } return null; } static Set vm_generalIdentityHashSet(Object name) { synchronized(vm_generalMap()) { Set set = (Set) (vm_generalMap_get(name)); if (set == null) vm_generalMap_put(name, set = syncIdentityHashSet()); return set; } } static Map vm_generalHashMap(Object name) { synchronized(vm_generalMap()) { Map m = (Map) (vm_generalMap_get(name)); if (m == null) vm_generalMap_put(name, m = syncHashMap()); return m; } } static BetterThreadLocal pingSource_tl_var = new BetterThreadLocal() { @Override public PingSource initialValue() { return ping_v3_pingSourceMaker().get(); } }; static BetterThreadLocal pingSource_tl() { return pingSource_tl_var; } static Comparator caseInsensitiveComparator() { return betterCIComparator(); } static TreeSet toCaseInsensitiveSet_treeSet(Iterable c) { if (isCISet(c)) return (TreeSet) c; TreeSet set = caseInsensitiveSet_treeSet(); addAll(set, c); return set; } static TreeSet toCaseInsensitiveSet_treeSet(String... x) { TreeSet set = caseInsensitiveSet_treeSet(); addAll(set, x); return set; } static boolean isTrueOrYes(Object o) { return isTrueOpt(o) || o instanceof String && (eqicOneOf(((String) o), "1", "t", "true") || isYes(((String) o))); } static LinkedHashMap asLinkedHashMap(Map map) { if (map instanceof LinkedHashMap) return (LinkedHashMap) map; LinkedHashMap m = new LinkedHashMap(); if (map != null) synchronized(collectionMutex(map)) { m.putAll(map); } return m; } static void metaMapPut(IMeta o, Object key, Object value) { { if (o != null) o.metaPut(key, value); } } static void metaMapPut(Object o, Object key, Object value) { var meta = initIMeta(o); { if (meta != null) meta.metaPut(key, value); } } static String quickSubstring(String s, int i, int j) { if (i >= j) return ""; return s.substring(i, j); } static Object defaultDefaultClassFinder() { return new F1() { public Class get(String name) { // Fix some buggy concepts files out there name = replacePrefix("main$main$", "main$", name); Class c = get2(name); return c; } Class get2(String name) { // special invocation to find main class irrelevant of name if (eq(name, "
")) return mc(); { Class c = findClass_fullName(name); if (c != null) return c; } if (startsWithAny(name, "loadableUtils.utils$", "main$", mcDollar())) for (String pkg : ll("loadableUtils.utils$", mcDollar())) { String newName = pkg + afterDollar(name); { Class c = findClass_fullName(newName); if (c != null) return c; } } return null; } }; } static String dropPrefixSuffix(String prefix, String s) { return dropPrefixSuffix(prefix, prefix, s); } static String dropPrefixSuffix(String prefix, String suffix, String s) { return dropPrefix(prefix, dropSuffix(suffix, s)); } static short shortFromBytes(byte[] a, int i) { return (short) (ubyteToInt(a[i]) << 8 | ubyteToInt(a[i+1])); } static int parseHexChar(char c) { if (c >= '0' && c <= '9') return charDiff(c, '0'); if (c >= 'a' && c <= 'f') return charDiff(c, 'a')+10; if (c >= 'A' && c <= 'F') return charDiff(c, 'A')+10; return -1; } static long longFromBytes_bigEndian(byte[] a, int i) { return twoIntsToLong_bigEndian( intFromBytes_bigEndian(a, i), intFromBytes_bigEndian(a, i+4)); } static TreeMap caseInsensitiveMap() { return new TreeMap(caseInsensitiveComparator()); } static Object safeUnstructure(String s) { return unstructure(s, true); } static Object safeUnstructure(File f) { return safeUnstructureGZFile(f); } static Class getOuterClass(Class c) { return getOuterClass(c, null); } static Class getOuterClass(Class c, Object classFinder) { try { String s = c.getName(); int i = s.lastIndexOf('$'); String name = substring(s, 0, i); return classForName(name, classFinder); } catch (Exception __e) { throw rethrow(__e); } } static Class getOuterClass(Object o) { return getOuterClass(o, null); } static Class getOuterClass(Object o, Object classFinder) { return getOuterClass(_getClass(o), classFinder); } static HashMap instanceFieldsMap(Object o) { return (HashMap) getOpt_getFieldMap(o); } static void warnIfOddCount(Object... list) { if (odd(l(list))) printStackTrace("Odd list size: " + list); } static Map thisDollarOneFields_cache = newDangerousWeakHashMap(); static Field[] thisDollarOneFields(Class c) { synchronized(thisDollarOneFields_cache) { Field[] l = thisDollarOneFields_cache.get(c); if (l == null) thisDollarOneFields_cache.put(c, l = thisDollarOneFields_uncached(c)); return l; } } static Field[] thisDollarOneFields_uncached(Class c) { List fields = new ArrayList(); do { for (Field f : c.getDeclaredFields()) if (f.getName().startsWith("this$")) fields.add(makeAccessible(f)); c = c.getSuperclass(); } while (c != null); return toArray(new Field[l(fields)], fields); } static Method fastIntern_method; static String fastIntern(String s) { try { if (s == null) return null; if (fastIntern_method == null) { fastIntern_method = findMethodNamed(javax(), "internPerProgram"); if (fastIntern_method == null) upgradeJavaXAndRestart(); } return (String) fastIntern_method.invoke(null, s); } catch (Exception __e) { throw rethrow(__e); } } static Map> callOpt_noArgs_cache = newDangerousWeakHashMap(); static Object callOpt_noArgs(Object o, String method) { try { if (o == null) return null; if (o instanceof Class) return callOpt(o, method); // not optimized Class c = o.getClass(); HashMap map; synchronized(callOpt_noArgs_cache) { map = callOpt_noArgs_cache.get(c); if (map == null) map = callOpt_noArgs_makeCache(c); } Method m = map.get(method); return m != null ? m.invoke(o) : null; } catch (Exception __e) { throw rethrow(__e); } } // used internally - we are in synchronized block static HashMap callOpt_noArgs_makeCache(Class c) { HashMap map = new HashMap(); Class _c = c; do { for (Method m : c.getDeclaredMethods()) if (m.getParameterTypes().length == 0 && !reflection_isForbiddenMethod(m)) { makeAccessible(m); String name = m.getName(); if (!map.containsKey(name)) map.put(name, m); } _c = _c.getSuperclass(); } while (_c != null); callOpt_noArgs_cache.put(c, map); return map; } static LinkedHashMap syncMapPut2_createLinkedHashMap(LinkedHashMap map, A key, B value) { if (key != null) if (value != null) { if (map == null) map = new LinkedHashMap(); synchronized(collectionMutex(map)) { map.put(key, value); } } else if (map != null) synchronized(collectionMutex(map)) { map.remove(key); } return map; } // match2 matches multiple "*" (matches a single token) wildcards and zero or one "..." wildcards (matches multiple tokens) static String[] match2(List pat, List tok) { // standard case (no ...) int i = pat.indexOf("..."); if (i < 0) return match2_match(pat, tok); pat = new ArrayList(pat); // We're modifying it, so copy first pat.set(i, "*"); while (pat.size() < tok.size()) { pat.add(i, "*"); pat.add(i+1, ""); // doesn't matter } return match2_match(pat, tok); } static String[] match2_match(List pat, List tok) { List result = new ArrayList(); if (pat.size() != tok.size()) { return null; } for (int i = 1; i < pat.size(); i += 2) { String p = pat.get(i), t = tok.get(i); if (eq(p, "*")) result.add(t); else if (!equalsIgnoreCase(unquote(p), unquote(t))) // bold change - match quoted and unquoted now. TODO: should remove return null; } return result.toArray(new String[result.size()]); } static Map classForName_cache = synchroHashMap(); static Class classForName(String name) { return classForName(name, null); } static Class classForName(String name, Object classFinder) { // first clause is when we're in class init if (classForName_cache == null || classFinder != null) return classForName_uncached(name, classFinder); Class c = classForName_cache.get(name); if (c == null) classForName_cache.put(name, c = classForName_uncached(name, null)); return c; } static Class classForName_uncached(String name, Object classFinder) { try { if (classFinder != null) return (Class) callF(classFinder, name); return Class.forName(name); } catch (Exception __e) { throw rethrow(__e); } } static Map nuObjectWithoutArguments_cache = newDangerousWeakHashMap(); static Object nuObjectWithoutArguments(String className) { try { return nuObjectWithoutArguments(classForName(className)); } catch (Exception __e) { throw rethrow(__e); } } static A nuObjectWithoutArguments(Class c) { try { if (nuObjectWithoutArguments_cache == null) // in class init return (A) nuObjectWithoutArguments_findConstructor(c).newInstance(); Constructor m = nuObjectWithoutArguments_cache.get(c); if (m == null) nuObjectWithoutArguments_cache.put(c, m = nuObjectWithoutArguments_findConstructor(c)); return (A) m.newInstance(); } catch (Exception __e) { throw rethrow(__e); } } static Constructor nuObjectWithoutArguments_findConstructor(Class c) { for (Constructor m : getDeclaredConstructors_cached(c)) if (empty(m.getParameterTypes())) { makeAccessible(m); return m; } throw fail("No default constructor found in " + c.getName()); } static List getClasses(Object[] array) { List l = emptyList(l(array)); for (Object o : array) l.add(_getClass(o)); return l; } static AutoCloseable tempSetThreadLocalIfNecessary(ThreadLocal tl, A a) { if (tl == null) return null; A prev = tl.get(); if (eq(prev, a)) return null; tl.set(a); return new AutoCloseable() { public String toString() { return "tl.set(prev);"; } public void close() throws Exception { tl.set(prev); }}; } static AutoCloseable tempSetThreadLocalIfNecessary(BetterThreadLocal tl, A a) { if (tl == null) return null; A prev = tl.get(); if (eq(prev, a)) return null; tl.set(a); return new AutoCloseable() { public String toString() { return "tl.set(prev);"; } public void close() throws Exception { tl.set(prev); }}; } static Class getClass(String name) { return _getClass(name); } static Class getClass(Object o) { return _getClass(o); } static Class getClass(Object realm, String name) { return _getClass(realm, name); } static HashMap> callMC_cache = new HashMap(); static String callMC_key; static Method callMC_value; // varargs assignment fixer for a single string array argument static Object callMC(String method, String[] arg) { return callMC(method, new Object[] {arg}); } static Object callMC(String method, Object... args) { try { Method me; if (callMC_cache == null) callMC_cache = new HashMap(); // initializer time workaround synchronized(callMC_cache) { me = method == callMC_key ? callMC_value : null; } if (me != null) try { return invokeMethod(me, null, args); } catch (IllegalArgumentException e) { throw new RuntimeException("Can't call " + me + " with arguments " + classNames(args), e); } List m; synchronized(callMC_cache) { m = callMC_cache.get(method); } if (m == null) { if (callMC_cache.isEmpty()) { callMC_makeCache(); m = callMC_cache.get(method); } if (m == null) throw fail("Method named " + method + " not found in main"); } int n = m.size(); if (n == 1) { me = m.get(0); synchronized(callMC_cache) { callMC_key = method; callMC_value = me; } try { return invokeMethod(me, null, args); } catch (IllegalArgumentException e) { throw new RuntimeException("Can't call " + me + " with arguments " + classNames(args), e); } } for (int i = 0; i < n; i++) { me = m.get(i); if (call_checkArgs(me, args, false)) return invokeMethod(me, null, args); } throw fail("No method called " + method + " with arguments (" + joinWithComma(getClasses(args)) + ") found in main"); } catch (Exception __e) { throw rethrow(__e); } } static void callMC_makeCache() { synchronized(callMC_cache) { callMC_cache.clear(); Class _c = (Class) mc(), c = _c; while (c != null) { for (Method m : c.getDeclaredMethods()) if ((m.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) { makeAccessible(m); multiMapPut(callMC_cache, m.getName(), m); } c = c.getSuperclass(); } } } static A assertNotNull(A a) { assertTrue(a != null); return a; } static A assertNotNull(String msg, A a) { assertTrue(msg, a != null); return a; } static A assertNotNull(Scorer scorer, String msg, A a) { if (scorer == null) return assertNotNull(msg, a); if (a == null) { print("BAD - " + msg + " is null: " + a); scorer.add(false); } else { print("OK, " + msg + " not null: " + a); scorer.add(true); } return a; } static ClassLoader classLoaderForObject(Object o) { if (o instanceof ClassLoader) return ((ClassLoader) o); if (o == null) return null; return _getClass(o).getClassLoader(); } static List getClassNames(Collection l) { List out = new ArrayList(); if (l != null) for (Object o : l) out.add(o == null ? null : getClassName(o)); return out; } static String repeat(char c, int n) { n = Math.max(n, 0); char[] chars = new char[n]; for (int i = 0; i < n; i++) chars[i] = c; return new String(chars); } static List repeat(A a, int n) { n = Math.max(n, 0); List l = new ArrayList(n); for (int i = 0; i < n; i++) l.add(a); return l; } static List repeat(int n, A a) { return repeat(a, n); } static Class loadClassFromClassLoader_orNull(ClassLoader cl, String name) { try { return cl == null ? null : cl.loadClass(name); } catch (ClassNotFoundException e) { return null; } } static String formatWithThousandsSeparator(long l) { return NumberFormat.getInstance(new Locale("en_US")).format(l); } static Object swing(Object f) { return swingAndWait(f); } static void swing(Runnable f) { swingAndWait(f); } static A swing(F0 f) { return (A) swingAndWait(f); } static A swing(IF0 f) { return (A) swingAndWait(f); } static A revalidate(final A c) { if (c == null || !c.isShowing()) return c; { swing(() -> { // magic combo to actually relayout and repaint c.revalidate(); c.repaint(); }); } return c; } static void revalidate(JFrame f) { revalidate((Component) f); } static void revalidate(JInternalFrame f) { revalidate((Component) f); } static void copyStream(InputStream in, OutputStream out) { try { byte[] buf = new byte[65536]; while (true) { int n = in.read(buf); if (n <= 0) return; out.write(buf, 0, n); } } catch (Exception __e) { throw rethrow(__e); } } static void _registerIO(Object object, String path, boolean opened) { } static A printException(A e) { printStackTrace(e); return e; } static A vm_generalMap_getOrCreate(Object key, F0 create) { return vm_generalMap_getOrCreate(key, f0ToIF0(create)); } static A vm_generalMap_getOrCreate(Object key, IF0 create) { Map generalMap = vm_generalMap(); if (generalMap == null) return null; // must be x30 init synchronized(generalMap) { // should switch to locks here A a = (A) (vm_generalMap_get(key)); if (a == null) vm_generalMap_put(key, a = create == null ? null : create.get()); return a; } } static A callF_gen(F0 f) { return f == null ? null : f.get(); } static B callF_gen(F1 f, A a) { return f == null ? null : f.get(a); } static A callF_gen(IF0 f) { return f == null ? null : f.get(); } static B callF_gen(IF1 f, A a) { return f == null ? null : f.get(a); } static B callF_gen(A a, IF1 f) { return f == null ? null : f.get(a); } static C callF_gen(F2 f, A a, B b) { return f == null ? null : f.get(a, b); } static C callF_gen(IF2 f, A a, B b) { return f == null ? null : f.get(a, b); } static void callF_gen(VF1 f, A a) { { if (f != null) f.get(a); } } static void callF_gen(A a, IVF1 f) { { if (f != null) f.get(a); } } static void callF_gen(IVF1 f, A a) { { if (f != null) f.get(a); } } static Object callF_gen(Runnable r) { { if (r != null) r.run(); } return null; } static Object callF_gen(Object f, Object... args) { return callF(f, args); } static boolean isInstance(Class type, Object arg) { return type.isInstance(arg); } static Map vm_generalMap_map; static Map vm_generalMap() { if (vm_generalMap_map == null) vm_generalMap_map = (Map) get(javax(), "generalMap"); return vm_generalMap_map; } static File localSnippetsDir() { return javaxDataDir("Personal Programs"); } static File localSnippetsDir(String sub) { return newFile(localSnippetsDir(), sub); } static String getOneLineFileInfoField(File f, String field) { File infoFile = associatedInfosFile(f); List lines = lines(loadTextFile(infoFile)); return firstStartingWithIC_drop(lines, field + ": "); } static File fileInSameDir(File f, String newName) { return newFile(parentFile(f), newName); } static volatile boolean muricaPassword_pretendNotAuthed = false; static String muricaPassword() { if (muricaPassword_pretendNotAuthed) return null; return trim(loadTextFile(muricaPasswordFile())); } static volatile Object isAllowed_function; // func(S, O[]) -> bool static volatile boolean isAllowed_all = true; static boolean isAllowed(String askingMethod, Object... args) { // check on VM level Object f = vm_generalMap_get("isAllowed_function"); if (f != null && !isTrue(callF(f, askingMethod, args))) return false; // check locally return isAllowed_all || isTrue(callF(isAllowed_function, askingMethod, args)); } static volatile boolean sleep_noSleep = false; static void sleep(long ms) { ping(); if (ms < 0) return; // allow spin locks if (isAWTThread() && ms > 100) throw fail("Should not sleep on AWT thread"); try { Thread.sleep(ms); } catch (Exception e) { throw new RuntimeException(e); } } static void sleep() { try { if (sleep_noSleep) throw fail("nosleep"); print("Sleeping."); sleepQuietly(); } catch (Exception __e) { throw rethrow(__e); } } static long round(double d) { return Math.round(d); } static String round(String s) { return roundBracket(s); } static Complex round(Complex c) { return new Complex(round(c.re), round(c.im)); } static String hmsWithColons() { return hmsWithColons(now()); } static String hmsWithColons(long time) { return new SimpleDateFormat("HH:mm:ss").format(time); } static String getComputerID_quick() { return computerID(); } static Object vm_generalMap_put(Object key, Object value) { return mapPutOrRemove(vm_generalMap(), key, value); } static int gzInputStream_defaultBufferSize = 65536; static GZIPInputStream gzInputStream(File f) { try { return gzInputStream(new FileInputStream(f)); } catch (Exception __e) { throw rethrow(__e); } } static GZIPInputStream gzInputStream(File f, int bufferSize) { try { return gzInputStream(new FileInputStream(f), bufferSize); } catch (Exception __e) { throw rethrow(__e); } } static GZIPInputStream gzInputStream(InputStream in) { return gzInputStream(in, gzInputStream_defaultBufferSize); } static GZIPInputStream gzInputStream(InputStream in, int bufferSize) { try { return _registerIOWrap(new GZIPInputStream(in, gzInputStream_defaultBufferSize), in); } catch (Exception __e) { throw rethrow(__e); } } static Map compileRegexp_cache = syncMRUCache(10); static java.util.regex.Pattern compileRegexp(String pat) { java.util.regex.Pattern p = compileRegexp_cache.get(pat); if (p == null) { compileRegexp_cache.put(pat, p = java.util.regex.Pattern.compile(pat)); } return p; } static int boolToInt(boolean b) { return b ? 1 : 0; } static Throwable getException(Runnable r) { try { callF(r); return null; } catch (Throwable e) { return e; } } static List javaTokForStructure(String s) { return javaTok_noMLS(s); } static String structure_addTokenMarkers(String s) { return join(structure_addTokenMarkers(javaTokForStructure(s))); } static List structure_addTokenMarkers(List tok) { // find references TreeSet refs = new TreeSet(); for (int i = 1; i < l(tok); i += 2) { String t = tok.get(i); if (t.startsWith("t") && isInteger(t.substring(1))) refs.add(parseInt(t.substring(1))); } if (empty(refs)) return tok; // add markers for (int i : refs) { int idx = i*2+1; if (idx >= l(tok)) continue; // broken structure String t = ""; if (endsWithLetterOrDigit(tok.get(idx-1))) t = " "; tok.set(idx, t + "m" + i + " " + tok.get(idx)); } return tok; } static int indexOfIgnoreCase_manual(String a, String b) { return indexOfIgnoreCase_manual(a, b, 0); } static int indexOfIgnoreCase_manual(String a, String b, int i) { int la = strL(a), lb = strL(b); if (la < lb) return -1; int n = la-lb; loop: for (; i <= n; i++) { for (int j = 0; j < lb; j++) { char c1 = a.charAt(i+j), c2 = b.charAt(j); if (!eqic(c1, c2)) continue loop; } return i; } return -1; } static Map compileRegexpIC_cache = syncMRUCache(10); static java.util.regex.Pattern compileRegexpIC(String pat) { java.util.regex.Pattern p = compileRegexpIC_cache.get(pat); if (p == null) { try { compileRegexpIC_cache.put(pat, p = java.util.regex.Pattern.compile(pat, Pattern.CASE_INSENSITIVE)); } catch (PatternSyntaxException e) { throw rethrow(wrapPatternSyntaxException(e)); } } return p; } static String actualUserHome_value; static String actualUserHome() { if (actualUserHome_value == null) { if (isAndroid()) actualUserHome_value = "/storage/emulated/0/"; else actualUserHome_value = System.getProperty("user.home"); } return actualUserHome_value; } static File actualUserHome(String sub) { return newFile(new File(actualUserHome()), sub); } static File userDir() { return new File(userHome()); } static File userDir(String path) { return new File(userHome(), path); } static File programDir_mine; // set this to relocate program's data static File programDir() { return programDir(getProgramID()); } static File programDir(String snippetID) { boolean me = sameSnippetID(snippetID, programID()); if (programDir_mine != null && me) return programDir_mine; File dir = new File(javaxDataDir(), formatSnippetIDOpt(snippetID)); if (me) { String c = caseID(); if (nempty(c)) dir = newFile(dir, c); } return dir; } static File programDir(String snippetID, String subPath) { return new File(programDir(snippetID), subPath); } static Map> javaTokWithAllBrackets_cached_cache = synchronizedMRUCache(defaultTokenizerCacheSize()); static List javaTokWithAllBrackets_cached(String s) { List tok = javaTokWithAllBrackets_cached_cache.get(s); if (tok == null) javaTokWithAllBrackets_cached_cache.put(s, tok = javaTokWithAllBrackets(s)); return tok; } static List mapCodeTokens(Object f, List l) { List out = emptyList(l); for (int i = 0; i < l(l); i++) { Object o = l.get(i); out.add(odd(i) ? callF(f, o) : o); } return out; } static List mapCodeTokens(List l, Object f) { return mapCodeTokens(f, l); } static List mapCodeTokens(List tok, IF1 f) { return mapCodeTokens(tok, (Object) f); } static List mapCodeTokens(IF1 f, List tok) { return mapCodeTokens(tok, f); } static boolean isCurlyBraced_simple(String s) { return startsWith(s, "{") && endsWith(s, "}"); } // i must point at the (possibly imaginary) opening bracket // index returned is index of closing bracket + 1 static int findEndOfCurlyBracketPart(List cnc, int i) { int j = i+2, level = 1; while (j < cnc.size()) { if (eq(cnc.get(j), "{")) ++level; else if (eq(cnc.get(j), "}")) --level; if (level == 0) return j+1; ++j; } return cnc.size(); } static boolean jcontainsOneOf(List tok, String... patterns) { return jfindOneOf(tok, patterns) >= 0; } static List regexpAllFirstGroups(String pattern, String text) { List l = new ArrayList(); Matcher matcher = regexp(pattern, text); while (matcher.find()) l.add(matcher.group(1)); return l; } // f: func -> A (stream ends when f returns null) static IterableIterator iteratorFromFunction(final Object f) { class IFF extends IterableIterator { A a; boolean done = false; public boolean hasNext() { getNext(); return !done; } public A next() { getNext(); if (done) throw fail(); A _a = a; a = null; return _a; } void getNext() { if (done || a != null) return; a = (A) callF(f); done = a == null; } }; return new IFF(); } // optimized version for F0 argument static IterableIterator iteratorFromFunction(F0 f) { return iteratorFromFunction_f0(f); } static IterableIterator iteratorFromFunction(IF0 f) { return iteratorFromFunction_if0(f); } static List mapPairsToList(Iterable> l, F2 f) { List x = emptyList(l); if (l != null) for (Pair p : l) x.add(callF(f, p.a, p.b)); return x; } static List mapPairsToList(Iterable> l, IF2 f) { List x = emptyList(l); if (l != null) for (Pair p : l) x.add(f.get(p.a, p.b)); return x; } static List mapPairsToList(Object f, Iterable> l) { List x = emptyList(l); if (l != null) for (Pair p : l) x.add(callF(f, p.a, p.b)); return x; } static List prependAll(final String s, Collection l) { return map(new F1() { public String get(String x) { try { return s + x; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "s + x"; }}, l); } static String joinStrings(String sep, Object... strings) { return joinStrings(sep, Arrays.asList(strings)); } static String joinStrings(String sep, Iterable strings) { StringBuilder buf = new StringBuilder(); for (Object o : unnull(strings)) { String s = strOrNull(o); if (nempty(s)) { if (nempty(buf)) buf.append(sep); buf.append(s); } } return str(buf); } static MultiMap mapMultiMapKeys(IF1 f, MultiMap mm) { MultiMap m = similarEmptyMultiMap(mm); for (var key : keys(mm)) m.put(f.get(key), mm.get(key)); return m; } static MultiMap mapMultiMapKeys(MultiMap mm, IF1 f) { return mapMultiMapKeys(f, mm); } static MultiSetMap mapMultiSetMapKeys(IF1 f, MultiSetMap mm) { MultiSetMap m = similarEmptyMultiSetMap(mm); for (var key : keys(mm)) m.put(f.get(key), mm.get(key)); return m; } static MultiSetMap mapMultiSetMapKeys(MultiSetMap mm, IF1 f) { return mapMultiSetMapKeys(f, mm); } static String addPrefix(String prefix, String s) { return s.startsWith(prefix) ? s : prefix + s; } static A firstOfPair(Pair p) { return p == null ? null : p.a; } static String reverseString(String s) { return empty(s) ? s : new StringBuilder(s).reverse().toString(); } // do these type parameters work? or back to O? static boolean doubleEq(A a1, A a2, B b1, B b2) { return eq(a1, a2) && eq(b1, b2); } static String roundBracketIf(boolean b, String s) { return b ? roundBracket(s) : s; } static String upper(String s) { return s == null ? null : s.toUpperCase(); } static char upper(char c) { return Character.toUpperCase(c); } static boolean isDollarVar(String s) { // Possible BREAKING CHANGE (although probably OK): now also accepting $1 etc. return startsWith(s, '$') && l(s) > 1; // OLD: ret startsWith(s, '$') && isJavaIdentifierAfter(s, 1); } static void listAdd(Collection c, A a) { if (c != null) c.add(a); } static TreeMap litCIMap(Object... x) { TreeMap map = caseInsensitiveMap(); litmap_impl(map, x); return map; } // f : Matcher -> S static String regexpReplaceIC(String s, String pat, Object f) { return regexReplaceIC(s, pat, f); } static String regexpReplaceIC(String s, String pat, String replacement) { return regexReplaceIC(s, pat, replacement); } static String regexpReplaceIC(String s, String pat, IF1 f) { return regexReplaceIC(s, pat, f); } static boolean regionMatchesIC(String a, int offsetA, String b, int offsetB, int len) { return a != null && a.regionMatches(true, offsetA, b, offsetB, len); } static List dropPunctuation_keep = ll("*", "<", ">"); static List dropPunctuation(List tok) { tok = new ArrayList(tok); for (int i = 1; i < tok.size(); i += 2) { String t = tok.get(i); if (t.length() == 1 && !Character.isLetter(t.charAt(0)) && !Character.isDigit(t.charAt(0)) && !dropPunctuation_keep.contains(t)) { tok.set(i-1, tok.get(i-1) + tok.get(i+1)); tok.remove(i); tok.remove(i); i -= 2; } } return tok; } static String dropPunctuation(String s) { return join(dropPunctuation(nlTok(s))); } static Object evalJava_main(String main) { return callCalc(evalJava_prep2(main)); } static String evalJava_prep(String code) { return evalJava_prep(code, "calc"); } static String evalJava_prep(String code, String mainName) { return evalJava_prep(code, mainName, ""); } static ThreadLocal evalJava_prep_args = new ThreadLocal(); static String evalJava_prep(String code, String mainName, String preCode) { EvalJavaPrep prep = new EvalJavaPrep(); List tok = evalJava_prePrep(code, prep); code = tok_addReturn(tok); String returnType = containsReturnWithArgument(code) ? "Object" : "void"; String main = lines(prep.global) + "static " + returnType + " " + mainName + "(" + unnull(evalJava_prep_args.get()) + ") throws Exception {\n" + preCode + code + "\n" + "}"; return main; } static Object realMC() { return getThreadLocal(realMC_tl()); } static List allFieldObjects_dontMakeAccessible(Object o) { List fields = new ArrayList(); Class _c = _getClass(o); do { addAll(fields, _c.getDeclaredFields()); _c = _c.getSuperclass(); } while (_c != null); return fields; } static Pair pairMapB(Object f, Pair p) { return p == null ? null : pair(p.a, callF(f, p.b)); } static Pair pairMapB(IF1 f, Pair p) { return p == null ? null : pair(p.a, f.get(p.b)); } static Pair pairMapB(Pair p, Object f) { return pairMap(f, p); } static Method findMethod_cached(Object o, String method, Object... args) { try { if (o == null) return null; if (o instanceof Class) { _MethodCache cache = callOpt_getCache((Class) o); List methods = cache.cache.get(method); if (methods != null) for (Method m : methods) if (isStaticMethod(m) && findMethod_checkArgs(m, args, false)) return m; return null; } else { _MethodCache cache = callOpt_getCache(o.getClass()); List methods = cache.cache.get(method); if (methods != null) for (Method m : methods) if (findMethod_checkArgs(m, args, false)) return m; return null; } } catch (Exception __e) { throw rethrow(__e); } } static Map mapToKeys(Iterable l, IF1 f) { if (l == null) return null; HashMap map = new HashMap(); for (A a : l) map.put(f.get(a), a); return map; } static Map mapToKeys(IF1 f, A[] l) { return mapToKeys(f, asList(l)); } static Map mapToKeys(IF1 f, Iterable l) { return mapToKeys(l, f); } static Map weakMap() { return newWeakHashMap(); } // allows null keys but not null values static B getOrCreate(Map map, A key, Class c) { try { B b = map.get(key); if (b == null) map.put(key, b = c.newInstance()); return b; } catch (Exception __e) { throw rethrow(__e); } } // f : func -> B static B getOrCreate(Map map, A key, Object f) { try { B b = map.get(key); if (b == null) map.put(key, b = (B) callF(f)); return b; } catch (Exception __e) { throw rethrow(__e); } } static B getOrCreate(IF0 f, Map map, A key) { return getOrCreate(map, key, f); } static B getOrCreate(Map map, A key, IF0 f) { B b = map.get(key); if (b == null) map.put(key, b = f.get()); return b; } static B getOrCreate(Class c, Map map, A key) { return getOrCreate(map, key, c); } static String toStringOpt(Object o) { return o instanceof String ? ((String) o) : null; } static void setOptIfNotNull(Object o, String field, Object value) { if (value != null) setOpt(o, field, value); } static Object mainBot; static Object getMainBot() { return mainBot; } static void pcallFAll(Collection l, Object... args) { if (l != null) for (Object f : cloneList(l)) pcallF(f, args); } static void pcallFAll(Iterator it, Object... args) { while (it.hasNext()) pcallF(it.next(), args); } static A[] newObjectArrayOfSameType(A[] a) { return newObjectArrayOfSameType(a, a.length); } static A[] newObjectArrayOfSameType(A[] a, int n) { return (A[]) Array.newInstance(a.getClass().getComponentType(), n); } static boolean fileExists(String path) { return path != null && new File(path).exists(); } static boolean fileExists(File f) { return f != null && f.exists(); } static CloseableIterableIterator emptyCloseableIterableIterator_instance = new CloseableIterableIterator() { public Object next() { throw fail(); } public boolean hasNext() { return false; } }; static CloseableIterableIterator emptyCloseableIterableIterator() { return emptyCloseableIterableIterator_instance; } static boolean ewic(String a, String b) { return endsWithIgnoreCase(a, b); } static boolean ewic(String a, String b, Matches m) { return endsWithIgnoreCase(a, b, m); } static CloseableIterableIterator linesFromReader(Reader r) { return linesFromReader(r, null); } static CloseableIterableIterator linesFromReader(Reader r, IResourceHolder resourceHolder) { final BufferedReader br = bufferedReader(r); return holdResource(resourceHolder, iteratorFromFunction_f0_autoCloseable(new F0() { public String get() { try { return readLineFromReaderWithClose(br); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "return readLineFromReaderWithClose(br);"; }}, _wrapIOCloseable(r))); } static CloseableIterableIterator linesFromReader(InputStream in) { return linesFromReader(inputStreamReader(in)); } static BufferedReader utf8bufferedReader(InputStream in) { try { return in == null ? null : bufferedReader(_registerIOWrap(new InputStreamReader(in, "UTF-8"), in)); } catch (Exception __e) { throw rethrow(__e); } } static BufferedReader utf8bufferedReader(File f) { try { return utf8bufferedReader(newFileInputStream(f)); } catch (Exception __e) { throw rethrow(__e); } } static Random defaultRandomGenerator() { { Random r = customRandomizerForThisThread(); if (r != null) return r; } return ThreadLocalRandom.current(); } static File oneOfTheFiles(String... paths) { if (paths != null) for (String path : paths) if (fileExists(path)) return newFile(path); return null; } static File oneOfTheFiles(File... files) { return oneOfTheFiles(asList(files)); } static File oneOfTheFiles(Iterable files) { if (files != null) for (File f : files) if (fileExists(f)) return f; return null; } static File javaxSecretDir_dir; // can be set to work on different base dir static File javaxSecretDir() { return javaxSecretDir_dir != null ? javaxSecretDir_dir : new File(userHome(), "JavaX-Secret"); } static File javaxSecretDir(String sub) { return newFile(javaxSecretDir(), sub); } static List jsonTok(String s) { List tok = new ArrayList(); int l = l(s); int i = 0; while (i < l) { int j = i; char c; String cc; // scan for whitespace while (j < l) { c = s.charAt(j); cc = s.substring(j, Math.min(j+2, l)); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (cc.equals("/*")) { do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/")); j = Math.min(j+2, l); } else if (cc.equals("//")) { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } tok.add(s.substring(i, j)); i = j; if (i >= l) break; c = s.charAt(i); // cc is not needed in rest of loop body // scan for non-whitespace (json strings, "null" identifier, numbers. everything else automatically becomes a one character token.) if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { if (s.charAt(j) == opener) { ++j; break; } else if (s.charAt(j) == '\\' && j+1 < l) j += 2; else ++j; } } else if (Character.isLetter(c)) do ++j; while (j < l && Character.isLetter(s.charAt(j))); else if (Character.isDigit(c)) do ++j; while (j < l && Character.isDigit(s.charAt(j))); else ++j; tok.add(s.substring(i, j)); i = j; } if ((tok.size() % 2) == 0) tok.add(""); return tok; } static Number boxedIntOrLong(long l) { return l != (int) l ? boxed(l) : boxed((int) l); } static Map castMapToMapO(Map map) { return map; } static List toLinesFullTrim(String s) { List l = new ArrayList(); for (String line : toLines(s)) if (nempty(line = trim(line))) l.add(line); return l; } static List toLinesFullTrim(File f) { List l = new ArrayList(); for (String line : linesFromFile(f)) if (nempty(line = trim(line))) l.add(line); return l; } static String javaDropAllComments(String s) { return join(javaDropAllComments(javaTok(s))); } static List javaDropAllComments(List tok) { for (int i = 0; i < l(tok); i += 2) tok.set(i, tok_javaDropCommentsFromWhitespace(tok.get(i))); return tok; } static void sort(T[] a, Comparator c) { if (a != null) Arrays.sort(a, c); } static void sort(T[] a) { if (a != null) Arrays.sort(a); } static void sort(int[] a) { if (a != null) Arrays.sort(a); } static void sort(List a, Comparator c) { if (a != null) Collections.sort(a, c); } static void sort(List a) { if (a != null) Collections.sort(a); } static int iround(double d) { return (int) Math.round(d); } static int iround(Number n) { return iround(toDouble(n)); } static TreeSet litciset(String... items) { TreeSet set = caseInsensitiveSet(); for (String a : items) set.add(a); return set; } static TreeSet litciset(Symbol... items) { TreeSet set = treeSet(); // HashSet would also do, but we might have the return type fixed somewhere, and they might want a NavigableMap. for (Symbol a : items) set.add(a); return set; } static String afterLastSpace(String s) { return s == null ? null : substring(s, s.lastIndexOf(' ')+1); } static String dropSuffixIgnoreCase(String suffix, String s) { return ewic(s, suffix) ? s.substring(0, l(s)-l(suffix)) : s; } static boolean ewicOneOf(String s, String... l) { if (s != null) for (String x : l) if (ewic(s, x)) return true; return false; } static Map stdFunctions_uncached() { return stdFunctions_uncached(new HashMap()); } static Map stdFunctions_uncached(Map map) { for (var snippetID : stdFunctionListSnippetIDs()) parseStdFunctionsList(loadSnippet(snippetID), map); return map; } static boolean methodIsStatic(Method m) { return (m.getModifiers() & Modifier.STATIC) != 0; } static boolean argumentCompatibleWithType(Object arg, Class type) { return arg == null ? !type.isPrimitive() : isInstanceX(type, arg); } static void arraycopy(Object[] a, Object[] b) { if (a != null && b != null) arraycopy(a, 0, b, 0, Math.min(a.length, b.length)); } static void arraycopy(Object src, int srcPos, int destPos, int n) { arraycopy(src, srcPos, src, destPos, n); } static void arraycopy(Object src, int srcPos, Object dest, int destPos, int n) { if (n != 0) System.arraycopy(src, srcPos, dest, destPos, n); } static Map vm_generalWeakSubMap(Object name) { synchronized(vm_generalMap()) { Map map = (Map) (vm_generalMap_get(name)); if (map == null) vm_generalMap_put(name, map = newWeakMap()); return map; } } static List cleanUpAndGetWeakReferencesList(List> l) { if (l == null) return null; synchronized(l) { List out = new ArrayList(); for (int i = 0; i < l(l); i++) { A a = l.get(i).get(); if (a == null) l.remove(i--); else out.add(a); } return out; } } static boolean domainIsUnder(String domain, String mainDomain) { return eqic(domain, mainDomain) || ewic(domain, "." + mainDomain); } static String theAGIBlueDomain() { return "agi.blue"; } static Object callFunction(Object f, Object... args) { return callF(f, args); } static Throwable _storeException_value; static void _storeException(Throwable e) { _storeException_value = e; } static Set syncIdentityHashSet() { return (Set) synchronizedSet(identityHashSet()); } static Map syncHashMap() { return synchroHashMap(); } static IF0 ping_v3_pingSourceMaker_cache; static IF0 ping_v3_pingSourceMaker() { if (ping_v3_pingSourceMaker_cache == null) ping_v3_pingSourceMaker_cache = ping_v3_pingSourceMaker_load(); return ping_v3_pingSourceMaker_cache;} static IF0 ping_v3_pingSourceMaker_load() { return or((IF0) vm_generalMap_get("ping_v3_pingSourceMaker"), () -> null); } static betterCIComparator_C betterCIComparator_instance; static betterCIComparator_C betterCIComparator() { if (betterCIComparator_instance == null) betterCIComparator_instance = new betterCIComparator_C(); return betterCIComparator_instance; } final static class betterCIComparator_C implements Comparator { public int compare(String s1, String s2) { if (s1 == null) return s2 == null ? 0 : -1; if (s2 == null) return 1; int n1 = s1.length(); int n2 = s2.length(); int min = Math.min(n1, n2); for (int i = 0; i < min; i++) { char c1 = s1.charAt(i); char c2 = s2.charAt(i); if (c1 != c2) { c1 = Character.toUpperCase(c1); c2 = Character.toUpperCase(c2); if (c1 != c2) { c1 = Character.toLowerCase(c1); c2 = Character.toLowerCase(c2); if (c1 != c2) { // No overflow because of numeric promotion return c1 - c2; } } } } return n1 - n2; } } static boolean isCISet(Iterable l) { return l instanceof TreeSet && ((TreeSet) l).comparator() == caseInsensitiveComparator(); } static boolean isTrueOpt(Object o) { if (o instanceof Boolean) return ((Boolean) o).booleanValue(); return false; } static boolean isTrueOpt(String field, Object o) { return isTrueOpt(getOpt(field, o)); } static boolean eqicOneOf(String s, String... l) { for (String x : l) if (eqic(s, x)) return true; return false; } static List isYes_yesses = litlist("y", "yes", "yeah", "y", "yup", "yo", "corect", "sure", "ok", "afirmative"); // << collapsed words, so "corect" means "correct" static boolean isYes(String s) { return isYes_yesses.contains(collapseWord(toLowerCase(firstWord2(s)))); } static IMeta initIMeta(Object o) { if (o == null) return null; if (o instanceof IMeta) return ((IMeta) o); if (o instanceof JComponent) return initMetaOfJComponent((JComponent) o); // This is not really used. Try to use BufferedImageWithMeta instead if (o instanceof BufferedImage) return optCast(IMeta.class, ((BufferedImage) o).getProperty("meta")); return null; } static String replacePrefix(String prefix, String replacement, String s) { if (!startsWith(s, prefix)) return s; return replacement + substring(s, l(prefix)); } static Object get2(Object o, String field1, String field2) { return get(get(o, field1), field2); } static boolean startsWithAny(String a, Collection b) { for (String prefix : unnullForIteration(b)) if (startsWith(a, prefix)) return true; return false; } static boolean startsWithAny(String a, String... b) { if (b != null) for (String prefix : unnullForIteration(b)) if (startsWith(a, prefix)) return true; return false; } static boolean startsWithAny(String a, Collection b, Matches m) { for (String prefix : unnullForIteration(b)) if (startsWith(a, prefix, m)) return true; return false; } static String mcDollar() { return mcName() + "$"; } static String afterDollar(String s) { return substring(s, smartIndexOf(s, '$')+1); } static int ubyteToInt(byte b) { return b & 0x0FF; } static int ubyteToInt(char c) { return c & 0x0FF; } static int charDiff(char a, char b) { return (int) a-(int) b; } static int charDiff(String a, char b) { return charDiff(stringToChar(a), b); } static long twoIntsToLong_bigEndian(int a, int b) { return twoIntsToLong(a, b); } static int intFromBytes_bigEndian(byte[] a, int i) { return intFromBytes(a, i); } static Object safeUnstructureGZFile(File f) { try { if (!fileExists(f)) return null; BufferedReader reader = utf8BufferedReader(gzInputStream(f)); return unstructure_tok(javaTokC_noMLS_onReader(reader), true, null); } catch (Exception __e) { throw rethrow(__e); } } static Object[] toArray(Collection c) { return toObjectArray(c); } static A[] toArray(Class type, Iterable c) { return toArray(c, type); } static A[] toArray(Class type, Collection c) { return toArray(c, type); } static A[] toArray(Collection c, Class type) { A[] a = arrayOfType(l(c), type); if (a.length == 0) return a; asList(c).toArray(a); return a; } static A[] toArray(Iterable c, Class type) { var c2 = asList(c); A[] a = arrayOfType(l(c2), type); if (a.length == 0) return a; c2.toArray(a); return a; } // array must have correct length and will be filled static A[] toArray(A[] array, Collection c) { if (array == null || c == null) return null; asList(c).toArray(array); return array; } static void upgradeJavaXAndRestart() { run("#1001639"); restart(); sleep(); } static boolean reflection_isForbiddenMethod(Method m) { return m.getDeclaringClass() == Object.class && eqOneOf(m.getName(), "finalize", "clone", "registerNatives"); } static boolean equalsIgnoreCase(String a, String b) { return eqic(a, b); } static boolean equalsIgnoreCase(char a, char b) { return eqic(a, b); } static void multiMapPut(Map> map, A a, B b) { List l = map.get(a); if (l == null) map.put(a, l = new ArrayList()); l.add(b); } static void multiMapPut(MultiMap mm, A key, B value) { if (mm != null && key != null && value != null) mm.put(key, value); } static void swingAndWait(Runnable r) { try { if (isAWTThread()) r.run(); else { r = addThreadInfoToRunnable(r); executingSwingCode(r); EventQueue.invokeAndWait(r); } } catch (Exception __e) { throw rethrow(__e); } } static Object swingAndWait(Object f) { if (isAWTThread()) return callF(f); else { Var result = new Var(); swingAndWait(new Runnable() { public void run() { try { result.set(callF(f)); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "result.set(callF(f));"; }}); return result.get(); } } static IF0 f0ToIF0(F0 f) { return f == null ? null : () -> f.get(); } static File associatedInfosFile(File f) { return replaceExtension(f, ".infos"); } static String firstStartingWithIC_drop(Collection l, final String prefix) { for (String s : unnull(l)) if (swic(s, prefix)) return substring(s, l(prefix)); return null; } static String firstStartingWithIC_drop(String prefix, Collection l) { return firstStartingWithIC_drop(l, prefix); } static File parentFile(File f) { return dirOfFile(f); } static File muricaPasswordFile() { return new File(javaxSecretDir(), "murica/muricaPasswordFile"); } static Object sleepQuietly_monitor = new Object(); static void sleepQuietly() { try { assertFalse(isAWTThread()); synchronized(sleepQuietly_monitor) { sleepQuietly_monitor.wait(); } } catch (Exception __e) { throw rethrow(__e); } } static String _computerID; static Lock computerID_lock = lock(); public static String computerID() { if (_computerID == null) { Lock __0 = computerID_lock; lock(__0); try { if (_computerID != null) return _computerID; File file = computerIDFile(); _computerID = loadTextFile(file.getPath()); if (_computerID == null) { // legacy load _computerID = loadTextFile(userDir(".tinybrain/computer-id")); if (_computerID == null) _computerID = makeRandomID(12, new SecureRandom()); saveTextFile(file, _computerID); } } finally { unlock(__0); } } return _computerID; } static B mapPutOrRemove(Map map, A key, B value) { if (map != null && key != null) if (value != null) return map.put(key, value); else return map.remove(key); return null; } static A _registerIOWrap(A wrapper, Object wrapped) { return wrapper; } static Map syncMRUCache(int size) { return synchroMap(new MRUCache(size)); } static List javaTok_noMLS(String s) { ArrayList tok = new ArrayList(); int l = s == null ? 0 : s.length(); int i = 0, n = 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 && !s.substring(j, Math.min(j+2, l)).equals("*/")); 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)); ++n; i = j; if (i >= l) break; c = s.charAt(i); d = i+1 >= l ? '\0' : s.charAt(i+1); // scan for non-whitespace 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))); 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 ++j; tok.add(javaTok_substringC(s, i, j)); ++n; i = j; } if ((tok.size() % 2) == 0) tok.add(""); return tok; } static RuntimeException wrapPatternSyntaxException(PatternSyntaxException e) { if (e == null) return null; String pat = e.getPattern(); int i = e.getIndex(); return new RuntimeException("Regular expression error between " + multiLineQuoteWithSpaces(substring(pat, 0, i)) + " and " + multiLineQuoteWithSpaces(substring(pat, i)) + " - " + e.getMessage()); } static volatile String caseID_caseID; static String caseID() { return caseID_caseID; } static void caseID(String id) { caseID_caseID = id; } static int defaultTokenizerCacheSize() { return 1000; } static List javaTokWithAllBrackets(String s) { return javaTokPlusBrackets2(s); } static A getNext(Iterator it) { return nextFromIterator(it); } static IterableIterator iteratorFromFunction_f0(final F0 f) { class IFF2 extends IterableIterator { A a; boolean done = false; public boolean hasNext() { getNext(); return !done; } public A next() { getNext(); if (done) throw fail(); A _a = a; a = null; return _a; } void getNext() { if (done || a != null) return; a = f.get(); done = a == null; } }; return new IFF2(); } static IterableIterator iteratorFromFunction_if0(final IF0 f) { class IFF2 extends IterableIterator { A a; boolean done = false; public boolean hasNext() { getNext(); return !done; } public A next() { getNext(); if (done) throw fail(); A _a = a; a = null; return _a; } void getNext() { if (done || a != null) return; a = f.get(); done = a == null; } }; return new IFF2(); } // TODO: comparators!? static MultiMap similarEmptyMultiMap(MultiMap m) { if (m instanceof TreeMultiMap) return new TreeMultiMap((TreeMultiMap) m); return similarEmptyMultiMap(m == null ? null : m.data); } static MultiMap similarEmptyMultiMap(Map m) { MultiMap mm = new MultiMap(); if (m != null) mm.data = similarEmptyMap(m); return mm; } static MultiSetMap similarEmptyMultiSetMap(MultiSetMap m) { return similarEmptyMultiSetMap(m == null ? null : m.data); } static MultiSetMap similarEmptyMultiSetMap(Map m) { MultiSetMap mm = new MultiSetMap(); if (m != null) mm.data = similarEmptyMap(m); return mm; } // f : Matcher -> S static String regexReplaceIC(String s, String pat, Object f) { return regexReplace(regexpMatcherIC(pat, s), f); } static String regexReplaceIC(String s, String pat, String replacement) { return regexpReplaceIC_direct(s, pat, replacement); } static List nlTok(String s) { return javaTokPlusPeriod(s); } static Object callCalc(Object o, Object... args) { return call(o, "calc", args); } // flag is per thread, cache is per program (in-memory cache of JavaX source -> loaded Class) static ThreadLocal evalJava_prep2_useCacheInThread = new ThreadLocal(); static volatile boolean evalJava_prep2_useCache = false; // cached main classes, used only when you enable it static Map evalJava_prep2_cache = synchronizedMRUCache(100); static Object evalJava_prep2(String main) { boolean _useCache = evalJava_prep2_useCache || isTrue(evalJava_prep2_useCacheInThread.get()); if (_useCache) { Object obj = evalJava_prep2_cache.get(main); if (obj != null) return obj; } Object obj = veryQuickJava(main); if (_useCache) evalJava_prep2_cache.put(main, obj); makeDependent(obj); setOpt(obj, "getProgramName_cache", "User Code"); return obj; } static ThreadLocal evalJava_prep_voidMagic = new ThreadLocal(); // set to false to avoid looking up standard function return types static List evalJava_prePrep(String code) { return evalJava_prePrep(code, new EvalJavaPrep()); } static List evalJava_prePrep(String code, EvalJavaPrep prep) { List tok = javaTok(trim(code)); int idx; while ((idx = jfind(tok, "global {")) >= 0) { int j = findEndOfBracketPart(tok, idx+2); prep.global.add(joinSubList(tok, idx+3, j-1)); clearTokens_reTok(tok, idx, j+1); } // =1*2 as in Lua if (eqGet(tok, 1, "=")) tok = subList(tok, 2); // if code is something like "sclass Bla {}", just return as is if (tok_isStaticLevelCode(tok)) return tok; if (!isFalse(evalJava_prep_voidMagic.get()) && tok_shouldAddReturn(tok) && eqGet(tok, 3, "(") && isIdentifier(get(tok, 1)) && isKnownVoidFunction_uncached(get(tok, 1))) tokAppend_reTok(tok, l(tok)-2, ";"); String name = null; // just a single identifier: interpret as function call if (l(tok) == 3 && isIdentifier(name = firstToken(tok))) tokAppend_reTok(tok, 1, "()" + (isKnownVoidFunction_uncached(name) ? ";" : "")); return tok; } static ThreadLocal realMC_tl_tl = new ThreadLocal(); static ThreadLocal realMC_tl() { return realMC_tl_tl; } static Pair pairMap(Object f, Pair p) { return p == null ? null : pair(callF(f, p.a), callF(f, p.b)); } static Pair pairMap(IF1 f, Pair p) { return p == null ? null : pair(callF(f, p.a), callF(f, p.b)); } static Pair pairMap(Pair p, Object f) { return pairMap(f, p); } static Object pcallF(Object f, Object... args) { return pcallFunction(f, args); } static A pcallF(F0 f) { try { return f == null ? null : f.get(); } catch (Throwable __e) { pcallFail(__e); } return null; } static B pcallF(F1 f, A a) { try { return f == null ? null : f.get(a); } catch (Throwable __e) { pcallFail(__e); } return null; } static void pcallF(VF1 f, A a) { try { { if (f != null) f.get(a); } } catch (Throwable __e) { pcallFail(__e); } } static Object pcallF(Runnable r) { try { { if (r != null) r.run(); } } catch (Throwable __e) { pcallFail(__e); } return null; } static A pcallF(IF0 f) { try { return f == null ? null : f.get(); } catch (Throwable __e) { pcallFail(__e); } return null; } static B pcallF(IF1 f, A a) { try { return f == null ? null : f.get(a); } catch (Throwable __e) { pcallFail(__e); } return null; } static boolean endsWithIgnoreCase(String a, String b) { int la = l(a), lb = l(b); return la >= lb && regionMatchesIC(a, la-lb, b, 0, lb); } static boolean endsWithIgnoreCase(String a, String b, Matches m) { if (!endsWithIgnoreCase(a, b)) return false; if (m != null) m.m = new String[] { substring(a, 0, l(a)-l(b)) }; return true; } static BufferedReader bufferedReader(Reader r) { return bufferedReader(r, 8192); } static BufferedReader bufferedReader(Reader r, int bufSize) { if (r == null) return null; return r instanceof BufferedReader ? (BufferedReader) r : _registerIOWrap(new BufferedReader(r, bufSize), r); } static BufferedReader bufferedReader(File f) { return utf8bufferedReader(f); } static A holdResource(IResourceHolder holder, A a) { { if (holder != null) holder.add(a); } return a; } static CloseableIterableIterator iteratorFromFunction_f0_autoCloseable(final F0 f, final AutoCloseable closeable) { class IFF2 extends CloseableIterableIterator { A a; boolean done = false; public boolean hasNext() { getNext(); return !done; } public A next() { getNext(); if (done) throw fail(); A _a = a; a = null; return _a; } void getNext() { if (done || a != null) return; a = f.get(); done = a == null; } public void close() throws Exception { if (closeable != null) closeable.close(); } }; return new IFF2(); } static String readLineFromReaderWithClose(BufferedReader r) { try { String s = r.readLine(); if (s == null) r.close(); return s; } catch (Exception __e) { throw rethrow(__e); } } static AutoCloseable _wrapIOCloseable(final AutoCloseable c) { return c == null ? null : new AutoCloseable() { public String toString() { return "c.close();\r\n _registerIO(c, null, false);"; } public void close() throws Exception { c.close(); _registerIO(c, null, false); }}; } static BufferedReader inputStreamReader(InputStream in) { return utf8Reader(in); } static BufferedReader inputStreamReader(File f) { return utf8Reader(f); } static FileInputStream newFileInputStream(File path) throws IOException { return newFileInputStream(path.getPath()); } static FileInputStream newFileInputStream(String path) throws IOException { FileInputStream f = new FileInputStream(path); _registerIO(f, path, true); return f; } static Random customRandomizerForThisThread() { return customRandomizerForThisThread_tl().get(); } static Integer boxed(int i) { return i; } static Long boxed(long l) { return l; } static String tok_javaDropCommentsFromWhitespace(String s) { int l = l(s), j = 0; StringBuilder buf = new StringBuilder(); while (j < l) { char c = s.charAt(j); char d = j+1 >= l ? '\0' : s.charAt(j+1); if (c == '/' && d == '*') { do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/")); j = Math.min(j+2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else { buf.append(c); ++j; } } return str(buf); } static double toDouble(Object o) { if (o instanceof Number) return ((Number) o).doubleValue(); if (o instanceof BigInteger) return ((BigInteger) o).doubleValue(); if (o instanceof String) return parseDouble((String) o); if (o == null) return 0.0; throw fail(o); } static TreeSet treeSet() { return new TreeSet(); } static List stdFunctionListSnippetIDs() { return ll("#1006654", "#761"); } // map contains function name -> snippet id static Map parseStdFunctionsList(String snippetSrc) { return parseStdFunctionsList(snippetSrc, new LinkedHashMap()); } static Map parseStdFunctionsList(String snippetSrc, Map map) { List tok = javaTok(snippetSrc); int i = findCodeTokens(tok, "standardFunctions", "=", "litlist", "("); int opening = i+6; int closing = indexOf(tok, ")", opening)-1; for (i = opening+2; i < closing; i += 4) { String[] f = unquote(tok.get(i)).split("/"); map.put(f[1], f[0]); } return map; } static Map newWeakMap() { return newWeakHashMap(); } static Set identityHashSet() { return Collections.newSetFromMap(new IdentityHashMap()); } static String collapseWord(String s) { if (s == null) return ""; StringBuilder buf = new StringBuilder(); for (int i = 0; i < l(s); i++) if (i == 0 || !charactersEqualIC(s.charAt(i), s.charAt(i-1))) buf.append(s.charAt(i)); return buf.toString(); } static List toLowerCase(List strings) { List x = new ArrayList(); for (String s : strings) x.add(s.toLowerCase()); return x; } static String[] toLowerCase(String[] strings) { String[] x = new String[l(strings)]; for (int i = 0; i < l(strings); i++) x[i] = strings[i].toLowerCase(); return x; } static String toLowerCase(String s) { return s == null ? "" : s.toLowerCase(); } static String firstWord2(String s) { s = xltrim(s); if (empty(s)) return ""; if (isLetterOrDigit(first(s))) return takeCharsWhile(__69 -> isLetterOrDigit(__69), s); else return "" + first(s); } static IMeta initMetaOfJComponent(JComponent c) { if (c == null) return null; IMeta meta = (IMeta) (c.getClientProperty(IMeta.class)); if (meta == null) c.putClientProperty(IMeta.class, meta = new Meta()); return meta; } static A optCast(Class c, Object o) { return isInstance(c, o) ? (A) o : null; } static String mcName() { return mc().getName(); } static char stringToChar(String s) { if (l(s) != 1) throw fail("bad stringToChar: " + s); return firstChar(s); } static long twoIntsToLong(int a, int b) { return (((long) a) << 32) | (((long) b) & 0xFFFFFFFFL); } static int intFromBytes(byte[] a, int i) { return ubyteToInt(a[i]) << 24 | ubyteToInt(a[i+1]) << 16 | ubyteToInt(a[i+2]) << 8 | ubyteToInt(a[i+3]); } static BufferedReader utf8BufferedReader(InputStream in) { return utf8bufferedReader(in); } static BufferedReader utf8BufferedReader(File f) { return utf8bufferedReader(f); } static A[] arrayOfType(Class type, int n) { return makeArray(type, n); } static A[] arrayOfType(int n, Class type) { return arrayOfType(type, n); } static Class run(String progID, String... args) { Class main = hotwire(progID); callMain(main, args); return main; } static void restart() { Object j = getJavaX(); call(j, "cleanRestart", get(j, "fullArgs")); } static Runnable addThreadInfoToRunnable(final Object r) { final Object info = _threadInfo(); return info == null ? asRunnable(r) : new Runnable() { public void run() { try { _inheritThreadInfo(info); callF(r); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "_inheritThreadInfo(info); callF(r);"; }}; } //static event executingSwingCode(Runnable code); static transient Set> onExecutingSwingCode; public static void onExecutingSwingCode(IVF1 f) { onExecutingSwingCode = createOrAddToSyncLinkedHashSet(onExecutingSwingCode, f); } public static void removeExecutingSwingCodeListener(IVF1 f) { main.remove(onExecutingSwingCode, f); } public static void executingSwingCode(Runnable code) { if (onExecutingSwingCode != null) for (var listener : onExecutingSwingCode) pcallF_typed(listener, code); } static File replaceExtension(File f, String extOld, String extNew) { return newFile(replaceExtension(f2s(f), extOld, extNew)); } static File replaceExtension(File f, String extNew) { return replaceExtension(f, fileExtension(f), extNew); } static String replaceExtension(String s, String extOld, String extNew) { s = dropSuffixIC(addPrefixOptIfNempty(".", extOld), s); return s + addPrefixOptIfNempty(".", extNew); } static String replaceExtension(String name, String extNew) { return replaceExtension(name, fileExtension(name), extNew); } static File dirOfFile(File f) { return f == null ? null : f.getParentFile(); } static File computerIDFile() { return javaxDataDir("Basic Info/computer-id.txt"); } static String multiLineQuoteWithSpaces(String s) { return multiLineQuote(" " + s + " "); } static List javaTokPlusBrackets2(String s) { return tok_combineRoundCurlySquareBrackets_keep(javaTok(s)); } static A nextFromIterator(Iterator it) { return it == null || !it.hasNext() ? null : it.next(); } // f : Matcher -> S static String regexReplace(String s, String pat, Object f) { Matcher m = Pattern.compile(pat).matcher(s); return regexReplace(m, f); } static String regexReplace(String s, String pat, String replacement) { return regexpReplace_direct(s, pat, replacement); } static String regexReplace(Matcher m, Object f) { StringBuffer buf = new StringBuffer(); while (m.find()) m.appendReplacement(buf, m.quoteReplacement(str(callF(f, m)))); m.appendTail(buf); return str(buf); } static String regexReplace(String s, String pat, IF1 f) { return regexReplace(s, pat, (Object) f); } static Matcher regexpMatcherIC(String pat, String s) { return compileRegexpIC(pat).matcher(unnull(s)); } static String regexpReplaceIC_direct(String s, String pat, String replacement) { Matcher m = regexpIC(pat, s); StringBuffer buf = new StringBuffer(); while (m.find()) m.appendReplacement(buf, replacement); m.appendTail(buf); return str(buf); } // This is made for NL parsing. // It's javaTok extended with "..." token, "$n" and "#n" and // special quotes (which are converted to normal ones). static List javaTokPlusPeriod(String s) { List tok = new ArrayList(); if (s == null) return tok; int l = s.length(); int i = 0; while (i < l) { int j = i; char c; String cc; // scan for whitespace while (j < l) { c = s.charAt(j); cc = s.substring(j, Math.min(j+2, l)); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (cc.equals("/*")) { do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/")); j = Math.min(j+2, l); } else if (cc.equals("//")) { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } tok.add(s.substring(i, j)); i = j; if (i >= l) break; c = s.charAt(i); cc = s.substring(i, Math.min(i+2, l)); // scan for non-whitespace if (c == (char) 0x201C || c == (char) 0x201D) c = '"'; // normalize quotes if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { char _c = s.charAt(j); if (_c == (char) 0x201C || _c == (char) 0x201D) _c = '"'; // normalize quotes if (_c == opener) { ++j; break; } else if (s.charAt(j) == '\\' && j+1 < l) j += 2; else ++j; } if (j-1 >= i+1) { tok.add(opener + s.substring(i+1, j-1) + opener); i = j; continue; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || s.charAt(j) == '\'')); // for things like "this one's" else if (Character.isDigit(c)) do ++j; while (j < l && Character.isDigit(s.charAt(j))); else if (cc.equals("[[")) { do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]")); j = Math.min(j+2, l); } else if (cc.equals("[=") && i+2 < l && s.charAt(i+2) == '[') { do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]")); j = Math.min(j+3, l); } else if (s.substring(j, Math.min(j+3, l)).equals("...")) j += 3; else if (c == '$' || c == '#') do ++j; while (j < l && Character.isDigit(s.charAt(j))); else ++j; tok.add(s.substring(i, j)); i = j; } if ((tok.size() % 2) == 0) tok.add(""); return tok; } // mainJava is a complete program, but without the !752/!759 at the top // returns link to main class static Class veryQuickJava(CharSequence mainJava) { return veryQuickJava3(str(mainJava)); // Latest version with internal compiler bot. } static boolean tok_isStaticLevelCode(List tok) { return eqOneOf(firstCodeToken(tok), "static", "sclass", "sinterface", "sS", "sO"); } static boolean tok_isStaticLevelCode(String src) { return tok_isStaticLevelCode(javaTok(src)); } static boolean isKnownVoidFunction_uncached(String name) { return standardFunctionAlwaysReturnsVoid_uncached(name); } static String firstToken(String s) { return firstJavaToken(s); } static String firstToken(List tok) { return get(tok, 1); } static Object pcallFunction(Object f, Object... args) { try { return callFunction(f, args); } catch (Throwable __e) { pcallFail(__e); } return null; } static BufferedReader utf8Reader(InputStream in) { return utf8BufferedReader(in); } static BufferedReader utf8Reader(File f) { return utf8BufferedReader(f); } static ThreadLocal customRandomizerForThisThread_tl = new ThreadLocal(); static ThreadLocal customRandomizerForThisThread_tl() { return customRandomizerForThisThread_tl; } static boolean charactersEqualIC(char c1, char c2) { if (c1 == c2) return true; char u1 = Character.toUpperCase(c1); char u2 = Character.toUpperCase(c2); if (u1 == u2) return true; return Character.toLowerCase(u1) == Character.toLowerCase(u2); } static String xltrim(String s) { int i = 0, n = l(s); while (i < n && contains(" \t\r\n", s.charAt(i))) ++i; return substr(s, i); } static boolean isLetterOrDigit(char c) { return Character.isLetterOrDigit(c); } // pred: char -> bool static String takeCharsWhile(String s, Object pred) { int i = 0; while (i < l(s) && isTrue(callF(pred, s.charAt(i)))) ++i; return substring(s, 0, i); } static String takeCharsWhile(IF1 f, String s) { return takeCharsWhile(s, f); } static char firstChar(String s) { return s.charAt(0); } static A[] makeArray(Class type, int n) { return (A[]) Array.newInstance(type, n); } static List> _threadInfo_makers = synchroList(); static Object _threadInfo() { if (empty(_threadInfo_makers)) return null; HashMap map = new HashMap(); pcallFAll(_threadInfo_makers, map); return map; } static Runnable asRunnable(Object o) { return toRunnable(o); } static void _inheritThreadInfo(Object info) { _threadInheritInfo(info); } static Set createOrAddToSyncLinkedHashSet(Set set, A a) { if (set == null) set = syncLinkedHashSet(); set.add(a); return set; } static void remove(List l, int i) { if (l != null && i >= 0 && i < l(l)) l.remove(i); } static void remove(Collection l, A a) { if (l != null) l.remove(a); } static B remove(Map map, Object a) { return map == null ? null : map.remove(a); } static void remove(BitSet bs, int i) { bs.clear(i); } static A pcallF_typed(F0 f) { try { return f == null ? null : f.get(); } catch (Throwable __e) { pcallFail(__e); } return null; } static B pcallF_typed(F1 f, A a) { try { return f == null ? null : f.get(a); } catch (Throwable __e) { pcallFail(__e); } return null; } static void pcallF_typed(VF1 f, A a) { try { { if (f != null) f.get(a); } } catch (Throwable __e) { pcallFail(__e); } } static void pcallF_typed(IVF1 f, A a) { try { { if (f != null) f.get(a); } } catch (Throwable __e) { pcallFail(__e); } } static void pcallF_typed(IVF2 f, A a, B b) { try { { if (f != null) f.get(a, b); } } catch (Throwable __e) { pcallFail(__e); } } static Object pcallF_typed(Runnable r) { try { { if (r != null) r.run(); } } catch (Throwable __e) { pcallFail(__e); } return null; } static A pcallF_typed(IF0 f) { try { return f == null ? null : f.get(); } catch (Throwable __e) { pcallFail(__e); } return null; } static B pcallF_typed(IF1 f, A a) { try { return f == null ? null : f.get(a); } catch (Throwable __e) { pcallFail(__e); } return null; } static String fileExtension(File f) { if (f == null) return null; return fileExtension(f.getName()); } static String fileExtension(String s) { return substring(s, smartLastIndexOf(s, '.')); } static String dropSuffixIC(String suffix, String s) { return s == null ? null : ewic(s, suffix) ? s.substring(0, l(s)-l(suffix)) : s; } static String addPrefixOptIfNempty(String prefix, String s) { return addPrefixIfNotEmpty2(prefix, s); } static String multiLineQuote(String s) { for (int i = 0; ; i++) { String closer = "]" + rep('=', i) + "]"; if (!contains(s, closer)) return "[" + rep('=', i) + "[" + s + closer; } } static List tok_combineRoundCurlySquareBrackets_keep(List tok) { List l = new ArrayList(); for (int i = 0; i < l(tok); i++) { String t = tok.get(i); if (odd(i) && eqOneOf(t, "{", "(", "[")) { int j = findEndOfBracketPart2(tok, i); l.add(joinSubList(tok, i, j)); i = j-1; } else l.add(t); } return l; } static String regexpReplace_direct(String s, String pat, String replacement) { Matcher m = regexp(pat, s); return regexpReplace_direct(m, replacement); } static String regexpReplace_direct(Matcher m, String replacement) { StringBuffer buf = new StringBuffer(); while (m.find()) m.appendReplacement(buf, replacement); m.appendTail(buf); return str(buf); } static boolean veryQuickJava_silent = true; static boolean veryQuickJava_useCompilerBot = true; // we always use it now static ThreadLocal veryQuickJava_transpiled = new ThreadLocal(); static Object veryQuickJava3_cacheFunction; // func(S, LS) -> Class static ThreadLocal> veryQuickJava_onJavaSource = new ThreadLocal(); // mainJava is a complete program, but without the !752/!759 at the top // returns link to main class static Class veryQuickJava3(String mainJava) { return veryQuickJava3(mainJava, emptyList()); } static Class veryQuickJava3(String mainJava, List libs) { Class c = (Class) (callF(veryQuickJava3_cacheFunction, mainJava, libs)); if (c != null) return c; transpileRaw_silent = veryQuickJava_silent; String src = transpileRaw(mainJava); // transpiled, with lib references if (empty(src)) { printWithIndent("JAVAX> ", mainJava); throw fail("Transpiler returned empty result"); } if (veryQuickJava_transpiled.get() != null) veryQuickJava_transpiled.set(src); callF(veryQuickJava_onJavaSource.get(), src); return veryQuickJava_finish(src, libs); } static String firstCodeToken(String s) { return firstJavaToken(s); } static String firstCodeToken(List tok) { return get(tok, 1); } static boolean standardFunctionAlwaysReturnsVoid_uncached(String name) { return tok_staticFunctionAlwaysReturnsVoid(javaTok(textOfStandardFunction_uncached(name)), name); } static String firstJavaToken(String s) { if (s == null) return null; int l = s.length(); int j = 0; 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 && !s.substring(j, Math.min(j+2, l)).equals("*/")); j = Math.min(j+2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } if (j >= l) return null; int i = j; c = s.charAt(i); d = i+1 >= l ? '\0' : s.charAt(i+1); // scan for non-whitespace if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { if (s.charAt(j) == opener || s.charAt(j) == '\n') { // end at \n to not propagate unclosed string literal errors ++j; break; } else if (s.charAt(j) == '\\' && j+1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || "'".indexOf(s.charAt(j)) >= 0)); // 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+1 < l && !s.substring(j, j+2).equals("]]")); j = Math.min(j+2, l); } else if (c == '[' && d == '=' && i+2 < l && s.charAt(i+2) == '[') { do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]")); j = Math.min(j+3, l); } else ++j; return quickSubstring(s, i, j); } static String substr(String s, int x) { return substring(s, x); } static String substr(String s, int x, int y) { return substring(s, x, y); } static Runnable toRunnable(final Object o) { if (o == null) return null; if (o instanceof Runnable) return (Runnable) o; return new Runnable() { public void run() { try { callF(o) ; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "callF(o)"; }}; } static List> _threadInheritInfo_retrievers = synchroList(); static void _threadInheritInfo(Object info) { if (info == null) return; pcallFAll(_threadInheritInfo_retrievers, (Map) info); } static Set syncLinkedHashSet() { return synchroLinkedHashSet(); } static String addPrefixIfNotEmpty2(String prefix, String s) { return empty(s) ? "" : addPrefix(prefix, s); } static boolean transpileRaw_silent = true; static boolean transpileRaw_useDiskCache = false; static Class transpileRaw_trans; static boolean transpileRaw_mine = true; static boolean transpileRaw_verySilent = false; static boolean transpileRaw_dontCopyFromCreator = false; static Lock transpileRaw_lock = lock(); static ThreadLocal transpileRaw_asInclude = new ThreadLocal(); static ThreadLocal transpileRaw_progID = new ThreadLocal(); static String transpileRaw(String mainJava) { return transpileRaw(mainJava, false, transpileRaw_useDiskCache); } static String transpileRaw(String mainJava, boolean fragment) { return transpileRaw(mainJava, fragment, transpileRaw_useDiskCache); } static String transpileRaw(String mainJava, boolean fragment, boolean useDiskCache) { mainJava = dropTranslators(mainJava); if (!transpileRaw_dontCopyFromCreator) transpileRaw_copyFromCreator(); Lock __0 = transpileRaw_lock; lock(__0); try { File cacheFile = null; if (useDiskCache) { cacheFile = new File(javaxCodeDir(), "Transpilations/" + uniqueFileNameUsingMD5_80_v2(mainJava) + ".java"); { String __3 = loadTextFile(cacheFile); if (!empty(__3)) return __3; } } AutoCloseable __4 = transpileRaw_verySilent ? null : tempLoadingAnim("Transpiling..."); try { transpileRaw_translator(); //setOpt(transpileRaw_trans, dontPrintSource := true); setOpt(transpileRaw_trans, "localStuffOnly" , fragment); setOpt(transpileRaw_trans, "asInclude" , isTrue(transpileRaw_asInclude.get())); setOpt(transpileRaw_trans, "mainSnippetID" , transpileRaw_progID.get()); set(transpileRaw_trans, "mainJava", mainJava); // TODO: setOpt(transpileRaw_trans, transpilingSnippetID := ); set(transpileRaw_trans, "print_byThread", print_byThread); if (!transpileRaw_verySilent) print("Running translator " + getOpt(transpileRaw_trans, "programID")); callMain(transpileRaw_trans); //print("Ran translator " + identityHashCode(transpileRaw_trans)); String main = (String) (get(transpileRaw_trans, "mainJava")); if (useDiskCache) { saveTextFile(new File(cacheFile.getPath() + "x"), mainJava); saveTextFile(cacheFile, main); } return main; } finally { _close(__4); }} finally { unlock(__0); } } static IF0 transpileRaw_translator; static Class transpileRaw_translator() { return transpileRaw_translator != null ? transpileRaw_translator.get() : transpileRaw_translator_base(); } final static Class transpileRaw_translator_fallback(IF0 _f) { return _f != null ? _f.get() : transpileRaw_translator_base(); } static Class transpileRaw_translator_base() { if (transpileRaw_trans == null) { //print("Loading translator."); transpileRaw_trans = transpileRaw_makeTranslator(); transpileRaw_mine = true; makeDependent(transpileRaw_trans); //print("Loaded translator: " + identityHashCode(transpileRaw_trans)); } setOpt(transpileRaw_trans, "print_silent", transpileRaw_silent); return transpileRaw_trans; } static IF0 transpileRaw_makeTranslator; static Class transpileRaw_makeTranslator() { return transpileRaw_makeTranslator != null ? transpileRaw_makeTranslator.get() : transpileRaw_makeTranslator_base(); } final static Class transpileRaw_makeTranslator_fallback(IF0 _f) { return _f != null ? _f.get() : transpileRaw_makeTranslator_base(); } static Class transpileRaw_makeTranslator_base() { return hotwireSharingLibraries_silently(defaultJavaXTranslatorID()); } static void transpileRaw_copyFromCreator() { Lock __1 = transpileRaw_lock; lock(__1); try { if (transpileRaw_trans != null) return; Object c = creator(); if (c == null) return; Class trans = (Class) (getOpt(c, "transpileRaw_trans")); Lock lock = (Lock) (getOpt(c, "transpileRaw_lock")); if (trans != null && lock != null) { print("Using creator's transpiler: " + getProgramID(c) + " => " + programID()); transpileRaw_lock = lock; transpileRaw_trans = trans; transpileRaw_mine = false; } } finally { unlock(__1); } } static void cleanMeUp_transpileRaw() { if (transpileRaw_mine) cleanUp(transpileRaw_trans); transpileRaw_trans = null; // release proactively (it's big) } static A printWithIndent(A o) { return printIndent(o); } static A printWithIndent(String indent, A o) { return printIndent(indent, o); } static void printWithIndent(int indent, Object o) { printIndent(indent, o); } static Class veryQuickJava_finish(String src, List libs) { libs = cloneList(libs); src = findTranslators2(src, libs); //print("Libs found: " + struct(libs)); String dehlibs = join(" ", libs); File bytecode = null; //try { bytecode = javaCompile_overInternalBot(src, dehlibs); /*} on fail { print("Was compiling: " + src + "\n"); }*/ return hotwireCore(concatLists(ll(bytecode), loadLibraries(libs))); } static boolean tok_staticFunctionAlwaysReturnsVoid(List tok, String name) { Set types = tok_returnTypesOfStaticFunction_uncleaned(tok, name); if (empty(types)) return false; for (String type : types) if (!containsOneOf(javaTokC(type), javaxVoidAliases())) return false; return true; } static String textOfStandardFunction_uncached(String sfName) { return loadSnippet(stdFunctions_uncached().get(sfName)); } // BREAKING CHANGE! // Also NOTE: Iterators of these sync-wrapped collections // after generally NOT thread-safe! // TODO: change that? static Set synchroLinkedHashSet() { return synchronizedSet(new CompactLinkedHashSet()); } static String dropTranslators(String src) { return findTranslators2(src, null); } // modifies original tok static List dropTranslators(List tok) { return findTranslators2(tok, null); } static File javaxCodeDir_dir; // can be set to work on different base dir static File javaxCodeDir() { return javaxCodeDir_dir != null ? javaxCodeDir_dir : new File(userHome(), "JavaX-Code"); } static File javaxCodeDir(String sub) { return newFile(javaxCodeDir(), sub); } static String uniqueFileNameUsingMD5_80_v2(String fullName) { return uniqueFileNameUsingMD5_80_v2(fullName, md5(fullName)); } static String uniqueFileNameUsingMD5_80_v2(String fullName, String md5) { return takeFirst(80-33, fileNameEncode(fullName)) + " - " + md5; } static AutoCloseable tempLoadingAnim(String msg) { return tempDisposeWindow(loadingAnim(msg)); } static Class hotwireSharingLibraries_silently(String progID) { AutoCloseable __1 = temp_loadPage_silent(); try { return hotwireSharingLibraries(progID); } finally { _close(__1); }} static WeakReference creator_class; static Object creator() { return creator_class == null ? null : creator_class.get(); } static boolean cleanUp_interruptThreads = false; // experimental static void cleanUp(Object c) { if (c == null) return; if (c instanceof AutoCloseable) { close_pcall((AutoCloseable) c); return; } if (c instanceof java.util.Timer) { ((java.util.Timer) c).cancel(); return; } if (c instanceof Collection) { cleanUp((Collection) c); return; } if (c instanceof Map) { for (Object o : keysList((Map) c)) cleanUp(o); for (Object o : valuesList((Map) c)) cleanUp(o); syncClear((Map) c); return; } //if (!(c instanceof Class)) ret; try { // revoke license preCleanUp(c); // unpause setOpt_raw(c, "ping_pauseAll", false); // call custom cleanMeUp() and cleanMeUp_*() functions innerCleanUp(c); // Java spec says finalize should only be called by GC, // but we care to differ. // Edit: Not anymore (illegal access warnings) /*if (isTrue(vmMap_get('callFinalize))) pcallOpt(c, "finalize");*/ // remove all virtual bots (hope this works) List androids = (List) getOpt(c, "record_list"); for (Object android : unnull(androids)) pcallOpt(android, "dispose"); // heck we'll dispose anything // sub-cleanup List classes = (List) (getOpt(c, "hotwire_classes")); if (classes != null) for (WeakReference cc : classes) { try { cleanUp(cc.get()); } catch (Throwable __e) { pcallFail(__e); }} // interrupt all threads (experimental, they might be doing cleanup?) if (cleanUp_interruptThreads) { List threads = registeredThreads(c); if (nempty(threads)) { print("cleanUp: Interrupting " + n2(threads, "thread") + ": " + joinWithComma(allToString(threads))); interruptThreads(threads); } } } catch (Throwable __e) { pcallFail(__e); } setOpt_raw(c, "cleaningUp_flag" , false); if (c instanceof Class && ((Class) c).getName().equals("main")) retireClassLoader(((Class) c).getClassLoader()); } static void cleanUp(Collection l) { if (l == null) return; for (Object c : l) cleanUp(c); l.clear(); } static A printIndent(A o) { print(indentx(str(o))); return o; } static A printIndent(String indent, A o) { print(indentx(indent, str(o))); return o; } static void printIndent(int indent, Object o) { print(indentx(indent, str(o))); } // probably better than findTranslators (uses tokens) // removes invocations from src static String findTranslators2(String src, List libsOut) { return join(findTranslators2(javaTok(src), libsOut)); } // modifies original tok static List findTranslators2(List tok, List libsOut) { int i; while ((i = jfind(tok, "!")) >= 0) { setAdd(libsOut, tok.get(i+2)); clearTokens(tok, i, i+3); } return tok; } static File javaCompile_overInternalBot(String src) { return javaCompile_overInternalBot(src, ""); } // returns path to jar static synchronized File javaCompile_overInternalBot(String src, String dehlibs) { return CompilerBot.compile(src, dehlibs); } static Class hotwireCore(List files) { try { // make class loader JavaXClassLoader classLoader = hotwire_makeClassLoader(files); // load & return main class Class theClass = classLoader.loadClass("main"); setOpt(theClass, "__javax", getJavaX()); if (getOpt(theClass, "programID") == null) setOpt(theClass, "programID", "#3999999"); if (!_inCore()) hotwire_copyOver(theClass); return theClass; } catch (Exception __e) { throw rethrow(__e); } } static List loadLibraries(List snippetIDs) { return map(__70 -> loadLibrary(__70), snippetIDs); } static Set tok_returnTypesOfStaticFunction_uncleaned(List tok, String functionName) { List> funcs = findFullFunctionDefs(tok, true); TreeSet out = new TreeSet(); for (List tokF : funcs) { int i = indexOfAny(tokF, 0, "(", "{"); if (i < 0) continue; String fname = get(tokF, i-2); if (!eq(fname, functionName)) continue; out.add(joinSubList(tokF, 1, i-3)); } return out; } static String fileNameEncode_safeChars = " "; //" ()[]#"; static String fileNameEncode(String s) { s = dropLeadingDots(s); // don't produce file names starting with a dot! StringBuilder buf = new StringBuilder(); int n = l(s); for (int i = 0; i < n; i++) { char c = s.charAt(i); if (contains(fileNameEncode_safeChars, c)) buf.append(c); else buf.append(urlencode(str(c))); } return str(buf); } static AutoCloseable tempDisposeWindow(final Window w) { return new AutoCloseable() { public void close() { disposeWindow(w); } }; } static JWindow loadingAnim() { return showLoadingAnimation(); } static JWindow loadingAnim(String text) { return showLoadingAnimation(text); } static AutoCloseable temp_loadPage_silent() { return tempSetThreadLocal(loadPage_silent, true); } static Class hotwireSharingLibraries(String progID) { try { Pair p = CompilerBot.compileSnippet2(progID); File jar = p.a; assertTrue(f2s(jar), jar.isFile()); // collect files (program + libraries) List files = ll(jar); String dehlibs = unnull(loadTextFileFromZip(jar, "libraries")); List myLibraries = myLibraryFiles(); //print("My libraries: " + myLibraries); Matcher matcher = Pattern.compile("\\d+").matcher(dehlibs); while (matcher.find()) { String libID = matcher.group(); File lib = loadLibrary(libID); if (myLibraries.contains(lib)) { //print("Skipping lib " + lib); } else { //print("Adding lib " + lib); files.add(lib); } } // make class loader JavaXClassLoaderWithParent classLoader = new JavaXClassLoaderWithParent(progID, files, myClassLoader()); return hotwire_finish(classLoader, progID, p.b); } catch (Exception __e) { throw rethrow(__e); } } static void close_pcall(AutoCloseable c) { if (c != null) { try { c.close(); } catch (Throwable __e) { pcallFail(__e); }} } static List keysList(Map map) { return cloneListSynchronizingOn(keys(map), map); } static List valuesList(Map map) { return cloneListSynchronizingOn(values(map), map); } static List valuesList(MultiMap mm) { return mm == null ? emptyList() : concatLists(values(mm.data)); } static void syncClear(Collection c) { if (c != null) synchronized(collectionMutex(c)) { c.clear(); } } static void syncClear(Map map) { if (map != null) synchronized(collectionMutex(map)) { map.clear(); } } static void preCleanUp(Object c) { if (c instanceof Collection) { for (Object o : ((Collection) c)) preCleanUp(o); return; } callOpt(c, "licensed_off"); setOpt_raw(c, "ping_anyActions" , true); // so ping notices setOpt_raw(c, "cleaningUp_flag" , true); } static void innerCleanUp(Object c) { // call custom cleanMeUp() and cleanMeUp_*() functions if (!isFalse(pcallOpt(c, "cleanMeUp"))) for (String name : sorted(methodsStartingWith(c, "cleanMeUp_"))) try { callOpt(c, name); } catch (Throwable e) { print("Error cleaning up: " + programID(c)); _handleException(e); } } static void innerCleanUp() { innerCleanUp(mc()); } static Object pcallOpt(Object o, String method, Object... args) { try { return callOpt(o, method, args); } catch (Throwable __e) { pcallFail(__e); } return null; } static List registeredThreads(Object o) { Map map = (Map) (getOpt(o, "_registerThread_threads")); if (map == null) return ll(); map.size(); // force clean-up synchronized(map) { return asList(keys(map)); } } static List registeredThreads() { _registerThread_threads.size(); // force clean-up return asList(keys(_registerThread_threads)); } static void interruptThreads(Collection threads) { for (Thread t : unnull(threads)) interruptThread(t); } static void interruptThreads(Class mainClass) { interruptThreads(registeredThreads(mainClass)); } static void retireClassLoader(ClassLoader cl) { try { if (isJavaXClassLoader(cl)) setOptAll(cl, "retired" , true, "retiredMarker" , new DefunctClassLoader()); } catch (Throwable __e) { pcallFail(__e); } } static String indentx(Object s) { return indentx(strOrEmpty(s)); } static String indentx(String s) { return indentx(indent_default, s); } static String indentx(int n, String s) { return dropSuffix(repeat(' ', n), indent(n, s)); } static String indentx(String indent, String s) { return dropSuffix(indent, indent(indent, s)); } static JavaXClassLoader hotwire_makeClassLoader(List files) { Collection toShare = hotwire_classesToShare(); return nempty(toShare) ? new JavaXClassLoaderWithParent2(null, files, myClassLoader(), cloneList(toShare)) : new JavaXClassLoader(null, files); } static File loadLibrary(String snippetID) { return loadBinarySnippet(snippetID); } static Set findFullFunctionDefs_keywords = new HashSet(splitAtSpace("static svoid ssvoid ssynchronized sbool sS sO sL")); // returns actual CNC static List> findFullFunctionDefs(List tok, boolean topLevelOnly) { int n = l(tok); List> functions = new ArrayList(); for (int i = 1; i < n; i += 2) { String t = tok.get(i); if (topLevelOnly && eq(t, "{")) i = findEndOfBlock(tok, i)-1; else if (findFullFunctionDefs_keywords.contains(t)) { int j = i+2; while (j < n && !eqOneOf(tok.get(j), ";", "=", "(", "{")) j += 2; if ((eqGet(tok, j, "(") || eq(t, "svoid") && eqGet(tok, j, "{")) && isIdentifier(tok.get(j-2)) && !contains(subList(tok, i, j), "new")) { int k = smartIndexOf(tok, "{", j); if (k < l(tok)) { k = findEndOfBlock(tok, k)+1; functions.add(subList(tok, i-1, k)); i = k-2; } } } } return functions; } static List> findFullFunctionDefs(String s, boolean topLevelOnly) { return findFullFunctionDefs(javaTok(s), topLevelOnly); } static Map _registerThread_threads; static Object _onRegisterThread; // voidfunc(Thread) static Thread _registerThread(Thread t) { if (_registerThread_threads == null) _registerThread_threads = newWeakHashMap(); _registerThread_threads.put(t, true); vm_generalWeakSubMap("thread2mc").put(t, weakRef(mc())); callF(_onRegisterThread, t); return t; } static void _registerThread() { _registerThread(Thread.currentThread()); } static String dropLeadingDots(String s) { int i = 0; while (charAt(s, i) == '.') ++i; return dropFirst(s, i); } static void disposeWindow(final Window window) { if (window != null) { swing(() -> { window.dispatchEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSING)); // call listeners myFrames_list.remove(window); window.dispose(); }); } } static void disposeWindow(final Component c) { disposeWindow(getWindow(c)); } static void disposeWindow(Object o) { if (o != null) disposeWindow(((Component) o)); } static void disposeWindow() { disposeWindow(heldInstance(Component.class)); } static JWindow showLoadingAnimation() { return showLoadingAnimation("Hold on user..."); } static JWindow showLoadingAnimation(String text) { try { return showAnimationInTopRightCorner("#1003543", text); } catch (Throwable __e) { return null; } } static String loadTextFileFromZip(File inZip, String fileName) { return loadTextFileFromZipFile(inZip, fileName); } static List myLibraryFiles() { Collection files = (Collection) (getOpt(myClassLoader(), "files")); if (files != null) return asList(files); return ll(getBytecodePathForClass(mc())); } static ClassLoader myClassLoader() { return _getClass(mc()).getClassLoader(); } static Class hotwire_finish(ClassLoader classLoader, String progID, String javaSource) { return hotwire_finish(classLoader, progID, javaSource, "main"); } static Class hotwire_finish(ClassLoader classLoader, String progID, String javaSource, String mainClass) { try { // load & return main class Class theClass = classLoader.loadClass(mainClass); Class j = getJavaX(); setOpt(theClass, "myJavaSource_code", javaSource); synchronized(j) { // hopefully this goes well... call(j, "setVars", theClass, progID); callOpt(j, "addInstance", progID, theClass); } hotwire_copyOver(theClass); vmBus_send("hotwireFinished", theClass, mc()); return theClass; } catch (Exception __e) { throw rethrow(__e); } } static ArrayList cloneListSynchronizingOn(Collection l, Object mutex) { if (l == null) return new ArrayList(); synchronized(mutex) { return new ArrayList(l); } } static List sorted(Collection c, Object comparator) { List l = cloneList(c); sort(l, makeComparator(comparator)); return l; } static List sorted(Collection c) { List l = cloneList(c); sort(l); return l; } static List sorted(Comparator comparator, Collection c) { List l = cloneList(c); sort(l, comparator); return l; } static List methodsStartingWith(Object o, final String prefix) { return filter(allMethodNames(o), new F1() { public Object get(String s) { try { return startsWith(s, prefix); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "startsWith(s, prefix)"; }}); } static volatile PersistableThrowable _handleException_lastException; static List _handleException_onException = synchroList(ll((IVF1) (__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 boolean interruptThread_verbose = false; static void interruptThread(Thread t) { if (t == null) return; if (interruptThread_verbose) print("Interrupting thread " + t); // note reason in global map vm_threadInterruptionReasonsMap().put(t, getStackTrace()); t.interrupt(); URLConnection c = (URLConnection) (vm_generalSubMap("URLConnection per thread").get(t)); if (c != null) { try { print("Closing URLConnection of interrupted thread."); call(c, "disconnect"); } catch (Throwable __e) { pcallFail(__e); }} } static boolean isJavaXClassLoader(ClassLoader cl) { return startsWithOneOf(className(cl), "main$JavaXClassLoader", "x30$JavaXClassLoader"); } static void setOptAll(Object o, Map fields) { if (fields == null) return; for (String field : keys(fields)) setOpt/*_flex*/(o, field, fields.get(field)); } static void setOptAll(Object o, Object... values) { //values = expandParams(c.getClass(), values); warnIfOddCount(values); for (int i = 0; i+1 < l(values); i += 2) { String field = (String) values[i]; Object value = values[i+1]; setOpt(o, field, value); } } static int indent_default = 2; static String indent(int indent) { return repeat(' ', indent); } static String indent(int indent, String s) { return indent(repeat(' ', indent), s); } static String indent(String indent, String s) { return indent + replace(unnull(s), "\n", "\n" + indent); } static String indent(String s) { return indent(indent_default, s); } static List indent(String indent, List lines) { List l = new ArrayList(); if (lines != null) for (String s : lines) l.add(indent + s); return l; } static Set hotwire_classesToShare = synchroSet(); static Set hotwire_classesToShare() { return hotwire_classesToShare; } static File loadBinarySnippet(String snippetID) { IResourceLoader rl = vm_getResourceLoader(); if (rl != null) return rl.loadLibrary(snippetID); return loadBinarySnippet_noResourceLoader(snippetID); } static File loadBinarySnippet_noResourceLoader(String snippetID) { try { long id = parseSnippetID(snippetID); if (isImageServerSnippet(id)) return loadImageAsFile(snippetID); File f = DiskSnippetCache_getLibrary(id); if (fileSize(f) == 0) f = loadDataSnippetToFile_noResourceLoader(snippetID); return f; } catch (Exception __e) { throw rethrow(__e); } } static Map myFrames_list = weakHashMap(); static List myFrames() { return swing(new F0>() { public List get() { try { return keysList(myFrames_list); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "return keysList(myFrames_list);"; }}); } static WeakReference weakRef(A a) { return newWeakReference(a); } static Window getWindow(Object o) { if (!(o instanceof Component)) return null; return swing(() -> { Component c = (Component) o; while (c != null) { if (c instanceof Window) return ((Window) c); c = c.getParent(); } return null; }); } static A heldInstance(Class c) { List l = holdInstance_l.get(); for (int i = l(l)-1; i >= 0; i--) { Object o = l.get(i); if (isInstanceOf(o, c)) return (A) o; } throw fail("No instance of " + className(c) + " held"); } static boolean showAnimationInTopRightCorner_alwaysOnTop = true; static boolean showAnimationInTopRightCorner_on = true; // automatically switches to AWT thread for you // text is optional text below image static JWindow showAnimationInTopRightCorner(String imageID, String text) { if (isHeadless() || !showAnimationInTopRightCorner_on) return null; return showAnimationInTopRightCorner(imageIcon(imageID), text); } static JWindow showAnimationInTopRightCorner(final Image image, final String text) { if (image == null || isHeadless() || !showAnimationInTopRightCorner_on) return null; return showAnimationInTopRightCorner(imageIcon(image), text); } static JWindow showAnimationInTopRightCorner(final ImageIcon imageIcon, final String text) { if (isHeadless() || !showAnimationInTopRightCorner_on) return null; return (JWindow) swingAndWait(new F0() { public Object get() { try { JLabel label = new JLabel(imageIcon); if (nempty(text)) { label.setText(text); label.setVerticalTextPosition(SwingConstants.BOTTOM); label.setHorizontalTextPosition(SwingConstants.CENTER); } final JWindow window = showInTopRightCorner(label); onClick(label, new Runnable() { public void run() { try { window.dispose() ; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "window.dispose()"; }}); if (showAnimationInTopRightCorner_alwaysOnTop) window.setAlwaysOnTop(true); return window; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "JLabel label = new JLabel(imageIcon);\r\n if (nempty(text)) {\r\n label.s..."; }}); } static JWindow showAnimationInTopRightCorner(final String imageID) { return showAnimationInTopRightCorner(imageID, ""); } static JWindow showAnimationInTopRightCorner(String imageID, double seconds) { return showAnimationInTopRightCorner(imageID, "", seconds); } static JWindow showAnimationInTopRightCorner(String imageID, String text, double seconds) { if (isHeadless()) return null; return disposeWindowAfter(iround(seconds*1000), showAnimationInTopRightCorner(imageID, text)); } static JWindow showAnimationInTopRightCorner(BufferedImage img, String text, double seconds) { return disposeWindowAfter(iround(seconds*1000), showAnimationInTopRightCorner(img, text)); } static String loadTextFileFromZipFile(File inZip, String fileName) { try { if (!fileExists(inZip)) return null; try { ZipFile zip = new ZipFile(inZip); try { return loadTextFileFromZipFile(zip, fileName); } finally { _close(zip); }} catch (Throwable e) { throw fail(f2s(inZip), e); } } catch (Exception __e) { throw rethrow(__e); } } static String loadTextFileFromZipFile(ZipFile zip, String fileName) { try { ZipEntry entry = zip.getEntry(fileName); if (entry == null) return null; InputStream fin = zip.getInputStream(entry); try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); copyStream(fin, baos); return fromUTF8(baos.toByteArray()); } finally { _close(fin); }} catch (Exception __e) { throw rethrow(__e); } } static File getBytecodePathForClass(Object o) { return getBytecodePathForClass(_getClass(o)); } static File getBytecodePathForClass(Class c) { try { return c == null ? null : new File(c.getProtectionDomain().getCodeSource().getLocation().toURI()); } catch (Exception __e) { throw rethrow(__e); } } static Comparator makeComparator(final Object f) { if (f instanceof Comparator) return (Comparator) f; return new Comparator() { public int compare(Object a, Object b) { return (Integer) callF(f, a, b); } }; } static List filter(Iterable c, Object pred) { if (pred instanceof F1) return filter(c, (F1) pred); List x = new ArrayList(); if (c != null) for (Object o : c) if (isTrue(callF(pred, o))) x.add(o); return x; } static List filter(Object pred, Iterable c) { return filter(c, pred); } static List filter(Iterable c, F1 pred) { List x = new ArrayList(); if (c != null) for (B o : c) if (pred.get(o)) x.add(o); return x; } static List filter(F1 pred, Iterable c) { return filter(c, pred); } //ifclass IF1 static List filter(Iterable c, IF1 pred) { List x = new ArrayList(); if (c != null) for (B o : c) if (pred.get(o)) x.add(o); return x; } static List filter(B[] c, IF1 pred) { List x = new ArrayList(); if (c != null) for (B o : c) if (pred.get(o)) x.add(o); return x; } static List filter(IF1 pred, Iterable c) { return filter(c, pred); } //endif static List allMethodNames(Object o) { Class c = _getClass(o); TreeSet names = new TreeSet(); while (c != null) { for (Method m : c.getDeclaredMethods()) names.add(m.getName()); c = c.getSuperclass(); } return asList(names); } static Throwable printStackTrace2(Throwable e) { // we go to system.out now - system.err is nonsense print(getStackTrace2(e)); return e; } static void printStackTrace2() { printStackTrace2(new Throwable()); } static void printStackTrace2(String msg) { printStackTrace2(new Throwable(msg)); } static Throwable innerException(Throwable e) { return getInnerException(e); } static Set synchroSet() { return synchroHashSet(); } static Set synchroSet(Set set) { return synchronizedSet(set); } static File loadImageAsFile(String snippetIDOrURL) { try { if (isURL(snippetIDOrURL)) throw fail("not implemented"); if (!isSnippetID(snippetIDOrURL)) throw fail("Not a URL or snippet ID: " + snippetIDOrURL); String snippetID = "" + parseSnippetID(snippetIDOrURL); File file = imageSnippetCacheFile(snippetID); if (fileSize(file) > 0) return file; String imageURL = snippetImageURL_noHttps(snippetID); System.err.println("Loading image: " + imageURL); byte[] data = loadBinaryPage(imageURL); saveBinaryFile(file, data); return file; } catch (Exception __e) { throw rethrow(__e); } } // If you change this, also change DiskSnippetCache_fileToLibID static File DiskSnippetCache_file(long snippetID) { return new File(getGlobalCache(), "data_" + snippetID + ".jar"); } // Data files are immutable, use centralized cache public static File DiskSnippetCache_getLibrary(long snippetID) throws IOException { File file = DiskSnippetCache_file(snippetID); return file.exists() ? file : null; } public static File DiskSnippetCache_getLibrary(String snippetID) { try { return DiskSnippetCache_getLibrary(psI(snippetID)); } catch (Exception __e) { throw rethrow(__e); } } public static void DiskSnippetCache_putLibrary(long snippetID, byte[] data) throws IOException { saveBinaryFile(DiskSnippetCache_file(snippetID), data); } static byte[] loadDataSnippetImpl(String snippetID) throws IOException { byte[] data; try { URL url = new URL(dataSnippetLink(snippetID)); print("Loading library: " + hideCredentials(url)); try { data = loadBinaryPage(url.openConnection()); } catch (RuntimeException e) { data = null; } if (data == null || data.length == 0) { url = new URL(tb_mainServer() + "/blobs/" + parseSnippetID(snippetID)); print("Loading library: " + hideCredentials(url)); data = loadBinaryPage(url.openConnection()); } print("Bytes loaded: " + data.length); } catch (FileNotFoundException e) { throw new IOException("Binary snippet #" + snippetID + " not found or not public"); } return data; } static long fileSize(String path) { return getFileSize(path); } static long fileSize(File f) { return getFileSize(f); } static File loadDataSnippetToFile(String snippetID) { try { IResourceLoader rl = vm_getResourceLoader(); if (rl != null) return rl.loadLibrary(snippetID); return loadDataSnippetToFile_noResourceLoader(snippetID); } catch (Exception __e) { throw rethrow(__e); } } static File loadDataSnippetToFile_noResourceLoader(String snippetID) { try { snippetID = fsI(snippetID); File f = DiskSnippetCache_file(parseSnippetID(snippetID)); List urlsTried = new ArrayList(); List errors = new ArrayList(); try { URL url = addAndReturn(urlsTried, new URL(dataSnippetLink(snippetID))); print("Loading library: " + hideCredentials(url)); try { loadBinaryPageToFile(openConnection(url), f); if (fileSize(f) == 0) throw fail(); } catch (Throwable e) { errors.add(e); url = addAndReturn(urlsTried, new URL(tb_mainServer() + "/blobs/" + psI(snippetID))); print(e); print("Trying other server: " + hideCredentials(url)); loadBinaryPageToFile(openConnection(url), f); print("Got bytes: " + fileSize(f)); } // TODO: check if we hit the "LOADING" message if (fileSize(f) == 0) throw fail(); System.err.println("Bytes loaded: " + fileSize(f)); } catch (Throwable e) { //printStackTrace(e); errors.add(e); throw fail("Binary snippet " + snippetID + " not found or not public. URLs tried: " + allToString(urlsTried) + ", errors: " + allToString(errors)); } return f; } catch (Exception __e) { throw rethrow(__e); } } static ThreadLocal> holdInstance_l = new ThreadLocal(); static AutoCloseable holdInstance(Object o) { if (o == null) return null; listThreadLocalAdd(holdInstance_l, o); return new AutoCloseable() { public void close() { listThreadLocalPopLast(holdInstance_l); } }; } static boolean loadBufferedImage_useImageCache = true; static BufferedImage loadBufferedImage(String snippetIDOrURLOrFile) { try { ping(); if (snippetIDOrURLOrFile == null) return null; if (isURL(snippetIDOrURLOrFile)) return imageIO_readURL(snippetIDOrURLOrFile); if (isSnippetID(snippetIDOrURLOrFile)) { String snippetID = "" + parseSnippetID(snippetIDOrURLOrFile); IResourceLoader rl = vm_getResourceLoader(); if (rl != null) return loadBufferedImage(rl.loadLibrary(snippetID)); File dir = imageSnippetsCacheDir(); if (loadBufferedImage_useImageCache) { dir.mkdirs(); File file = new File(dir, snippetID + ".png"); if (file.exists() && file.length() != 0) try { return ImageIO.read(file); } catch (Throwable e) { e.printStackTrace(); // fall back to loading from sourceforge } } String imageURL = snippetImageURL_http(snippetID); print("Loading image: " + imageURL); BufferedImage image = imageIO_readURL(imageURL); if (loadBufferedImage_useImageCache) { File tempFile = new File(dir, snippetID + ".tmp." + System.currentTimeMillis()); ImageIO.write(image, "png", tempFile); tempFile.renameTo(new File(dir, snippetID + ".png")); //Log.info("Cached image."); } //Log.info("Loaded image."); return image; } else return loadBufferedImage(new File(snippetIDOrURLOrFile)); } catch (Exception __e) { throw rethrow(__e); } } static BufferedImage loadBufferedImage(File file) { return loadBufferedImageFile(file); } static Map weakHashMap() { return newWeakHashMap(); } static WeakReference newWeakReference(A a) { return a == null ? null : new WeakReference(a); } static boolean isInstanceOf(Object o, Class type) { return type.isInstance(o); } static int imageIcon_cacheSize = 10; static boolean imageIcon_verbose = false; static Map imageIcon_cache; static Lock imageIcon_lock = lock(); static ThreadLocal imageIcon_fixGIF = new ThreadLocal(); // not going through BufferedImage preserves animations static ImageIcon imageIcon(String imageID) { try { if (imageID == null) return null; Lock __0 = imageIcon_lock; lock(__0); try { if (imageIcon_cache == null) imageIcon_cache = new MRUCache(imageIcon_cacheSize); imageID = fsI(imageID); ImageIcon ii = imageIcon_cache.get(imageID); if (ii == null) { if (imageIcon_verbose) print("Loading image icon: " + imageID); File f = loadBinarySnippet(imageID); Boolean b = imageIcon_fixGIF.get(); if (!isFalse(b)) ii = new ImageIcon(loadBufferedImageFixingGIFs(f)); else ii = new ImageIcon(f.toURI().toURL()); } else imageIcon_cache.remove(imageID); // move to front of cache on access imageIcon_cache.put(imageID, ii); return ii; } finally { unlock(__0); } } catch (Exception __e) { throw rethrow(__e); } } // doesn't fix GIFs static ImageIcon imageIcon(File f) { try { return new ImageIcon(f.toURI().toURL()); } catch (Exception __e) { throw rethrow(__e); } } static ImageIcon imageIcon(Image img) { return img == null ? null : new ImageIcon(img); } static JWindow showInTopRightCorner(Component c) { return swing(() -> { JWindow w = new JWindow(); w.add(c); w.pack(); moveToTopRightCorner(w); w.setVisible(true); return w; }); } static A onClick(A c, IVF1 runnable) { return onClick(c, (Object) runnable); } static A onClick(A c, Object runnable) { if (c != null) { swing(() -> { c.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { callF(runnable, e); } }); }); } return c; } // re-interpreted for buttons static void onClick(JButton btn, Object runnable) { onEnter(btn, runnable); } static A disposeWindowAfter(int delay, final A w) { if (w != null) swingLater(delay, new Runnable() { public void run() { try { w.dispose(); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "w.dispose();"; }}); return w; } static A disposeWindowAfter(A w, double seconds) { return disposeWindowAfter(toMS_int(seconds), w); } static A disposeWindowAfter(double seconds, A w) { return disposeWindowAfter(w, seconds); } static String fromUTF8(byte[] bytes) { return fromUtf8(bytes); } static String getStackTrace2(Throwable e) { return hideCredentials(getStackTrace(unwrapTrivialExceptionWraps(e)) + replacePrefix("java.lang.RuntimeException: ", "FAIL: ", hideCredentials(str(innerException2(e)))) + "\n"); } static boolean isURL(String s) { return startsWithOneOf(s, "http://", "https://", "file:"); } static File imageSnippetCacheFile(String snippetID) { File dir = imageSnippetsCacheDir(); if (!loadBufferedImage_useImageCache) return null; return new File(dir, parseSnippetID(snippetID) + ".png"); } static String snippetImageURL_noHttps(String snippetID) { return snippetImageURL_noHttps(snippetID, "png"); } static String snippetImageURL_noHttps(String snippetID, String contentType) { return snippetImageURL(snippetID, contentType) .replace("https://www.botcompany.de:8443/", "http://www.botcompany.de:8080/") .replace("https://botcompany.de/", "http://botcompany.de/"); } static ThreadLocal>> loadBinaryPage_responseHeaders = new ThreadLocal(); static ThreadLocal> loadBinaryPage_extraHeaders = new ThreadLocal(); static byte[] loadBinaryPage(String url) { try { print("Loading " + url); return loadBinaryPage(loadPage_openConnection(new URL(url))); } catch (Exception __e) { throw rethrow(__e); } } static byte[] loadBinaryPage(URLConnection con) { try { Map extraHeaders = getAndClearThreadLocal(loadBinaryPage_extraHeaders); setHeaders(con); for (String key : keys(extraHeaders)) con.setRequestProperty(key, extraHeaders.get(key)); return loadBinaryPage_noHeaders(con); } catch (Exception __e) { throw rethrow(__e); } } static byte[] loadBinaryPage_noHeaders(URLConnection con) { try { ByteArrayOutputStream buf = new ByteArrayOutputStream(); InputStream inputStream = con.getInputStream(); loadBinaryPage_responseHeaders.set(con.getHeaderFields()); long len = 0; try { len = con.getContentLength/*Long*/(); } catch (Throwable e) { printStackTrace(e); } int n = 0; while (true) { int ch = inputStream.read(); if (ch < 0) break; buf.write(ch); if (++n % 100000 == 0) println(" " + n + (len != 0 ? "/" + len : "") + " bytes loaded."); } inputStream.close(); return buf.toByteArray(); } catch (Exception __e) { throw rethrow(__e); } } /** writes safely (to temp file, then rename) */ public static byte[] saveBinaryFile(String fileName, byte[] contents) { try { File file = new File(fileName); File parentFile = file.getParentFile(); if (parentFile != null) parentFile.mkdirs(); String tempFileName = fileName + "_temp"; try (FileOutputStream fileOutputStream = newFileOutputStream(tempFileName)) { fileOutputStream.write(contents); } if (file.exists() && !file.delete()) throw new IOException("Can't delete " + fileName); if (!new File(tempFileName).renameTo(file)) throw new IOException("Can't rename " + tempFileName + " to " + fileName); vmBus_send("wroteFile", file); return contents; } catch (Exception __e) { throw rethrow(__e); } } static byte[] saveBinaryFile(File fileName, byte[] contents) { return saveBinaryFile(fileName.getPath(), contents); } static String dataSnippetLink(String snippetID) { long id = parseSnippetID(snippetID); if (id >= 1100000 && id < 1200000) return imageServerURL() + id; if (id >= 1200000 && id < 1300000) { // Woody files, actually String pw = muricaPassword(); if (empty(pw)) throw fail("Please set 'murica password by running #1008829"); return "https://botcompany.de/files/" + id + "?_pass=" + pw; // XXX, although it typically gets hidden when printing } return fileServerURL() + "/" + id /*+ "?_pass=" + muricaPassword()*/; } static A addAndReturn(Collection c, A a) { if (c != null) c.add(a); return a; } static A addAndReturn(List c, int idx, A a) { if (c != null) c.add(idx, a); return a; } static void loadBinaryPageToFile(String url, File file) { try { print("Loading " + url); loadBinaryPageToFile(openConnection(new URL(url)), file); } catch (Exception __e) { throw rethrow(__e); } } static void loadBinaryPageToFile(URLConnection con, File file) { try { setHeaders(con); loadBinaryPageToFile_noHeaders(con, file); } catch (Exception __e) { throw rethrow(__e); } } static void loadBinaryPageToFile_noHeaders(URLConnection con, File file) { try { assertNotNull(file); File ftemp = new File(f2s(file) + "_temp"); FileOutputStream buf = newFileOutputStream(mkdirsFor(ftemp)); try { InputStream inputStream = con.getInputStream(); long len = 0; try { len = con.getContentLength/*Long*/(); } catch (Throwable e) { printStackTrace(e); } String pat = " {*}" + (len != 0 ? "/" + len : "") + " bytes loaded."; copyStreamWithPrints(inputStream, buf, pat); inputStream.close(); buf.close(); file.delete(); renameFile_assertTrue(ftemp, file); } finally { if (buf != null) buf.close(); } } catch (Exception __e) { throw rethrow(__e); } } static void listThreadLocalAdd(ThreadLocal> tl, A a) { List l = tl.get(); if (l == null) tl.set(l = new ArrayList()); l.add(a); } static A listThreadLocalPopLast(ThreadLocal> tl) { List l = tl.get(); if (l == null) return null; A a = popLast(l); if (empty(l)) tl.set(null); return a; } static BufferedImage imageIO_readURL(String url) { try { return ImageIO.read(new URL(url)); } catch (Exception __e) { throw rethrow(__e); } } static File imageSnippetsCacheDir() { return javaxCachesDir("Image-Snippets"); } static String snippetImageURL_http(String snippetID) { return snippetImageURL_http(snippetID, "png"); } static String snippetImageURL_http(String snippetID, String contentType) { return replacePrefix("https://", "http://", snippetImageURL(snippetID, contentType)).replace(":8443", ":8080"); } static BufferedImage loadBufferedImageFile(File file) { try { if (!isFile(file)) return null; return ImageIO.read(file); } catch (Exception __e) { throw rethrow(__e); } } static boolean loadBufferedImageFixingGIFs_debug = false; static ThreadLocal> loadBufferedImageFixingGIFs_output = new ThreadLocal(); static Image loadBufferedImageFixingGIFs(File file) { try { if (!file.exists()) return null; // Load anything but GIF the normal way if (!isGIF(file)) return ImageIO.read(file); if (loadBufferedImageFixingGIFs_debug) print("loadBufferedImageFixingGIFs" + ": checking gif"); // Get GIF reader ImageReader reader = ImageIO.getImageReadersByFormatName("gif").next(); // Give it the stream to decode from reader.setInput(ImageIO.createImageInputStream(file)); int numImages = reader.getNumImages(true); // Get 'metaFormatName'. Need first frame for that. IIOMetadata imageMetaData = reader.getImageMetadata(0); String metaFormatName = imageMetaData.getNativeMetadataFormatName(); // Find out if GIF is bugged boolean foundBug = false; for (int i = 0; i < numImages && !foundBug; i++) { // Get metadata IIOMetadataNode root = (IIOMetadataNode)reader.getImageMetadata(i).getAsTree(metaFormatName); // Find GraphicControlExtension node int nNodes = root.getLength(); for (int j = 0; j < nNodes; j++) { org.w3c.dom.Node node = root.item(j); if (node.getNodeName().equalsIgnoreCase("GraphicControlExtension")) { // Get delay value String delay = ((IIOMetadataNode)node).getAttribute("delayTime"); // Check if delay is bugged if (Integer.parseInt(delay) == 0) { foundBug = true; } break; } } } if (loadBufferedImageFixingGIFs_debug) print("loadBufferedImageFixingGIFs" + ": " + f2s(file) + " foundBug=" + foundBug); // Load non-bugged GIF the normal way Image image; if (!foundBug) { image = Toolkit.getDefaultToolkit().createImage(f2s(file)); } else { // Prepare streams for image encoding ByteArrayOutputStream baoStream = new ByteArrayOutputStream(); { ImageOutputStream ios = ImageIO.createImageOutputStream(baoStream); try { // Get GIF writer that's compatible with reader ImageWriter writer = ImageIO.getImageWriter(reader); // Give it the stream to encode to writer.setOutput(ios); writer.prepareWriteSequence(null); for (int i = 0; i < numImages; i++) { // Get input image BufferedImage frameIn = reader.read(i); // Get input metadata IIOMetadataNode root = (IIOMetadataNode)reader.getImageMetadata(i).getAsTree(metaFormatName); // Find GraphicControlExtension node int nNodes = root.getLength(); for (int j = 0; j < nNodes; j++) { org.w3c.dom.Node node = root.item(j); if (node.getNodeName().equalsIgnoreCase("GraphicControlExtension")) { // Get delay value String delay = ((IIOMetadataNode)node).getAttribute("delayTime"); // Check if delay is bugged if (Integer.parseInt(delay) == 0) { // Overwrite with a valid delay value ((IIOMetadataNode)node).setAttribute("delayTime", "10"); } break; } } // Create output metadata IIOMetadata metadata = writer.getDefaultImageMetadata(new ImageTypeSpecifier(frameIn), null); // Copy metadata to output metadata metadata.setFromTree(metadata.getNativeMetadataFormatName(), root); // Create output image IIOImage frameOut = new IIOImage(frameIn, null, metadata); // Encode output image writer.writeToSequence(frameOut, writer.getDefaultWriteParam()); } writer.endWriteSequence(); } finally { _close(ios); }} // Create image using encoded data byte[] data = baoStream.toByteArray(); setVar(loadBufferedImageFixingGIFs_output.get(), data); if (loadBufferedImageFixingGIFs_debug) print("Data size: " + l(data)); image = Toolkit.getDefaultToolkit().createImage(data); } return image; } catch (Exception __e) { throw rethrow(__e); } } static int moveToTopRightCorner_inset = 20; static A moveToTopRightCorner(A a) { return moveToTopRightCorner(moveToTopRightCorner_inset, moveToTopRightCorner_inset, a); } static A moveToTopRightCorner(int insetX, int insetY, A a) { { swing(() -> { Window w = getWindow(a); if (w != null) { var bounds = preferredScreenBounds(); w.setLocation(bounds.x2()-w.getWidth()-insetX, bounds.y1()+insetY); } }); } return a; } static JTextField onEnter(JTextField tf, JButton btn) { if (btn != null) onEnter(tf, new Runnable() { public void run() { try { clickButton(btn) ; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "clickButton(btn)"; }}); return tf; } static JTextField onEnter(JTextField tf, Object action) { if (action == null || tf == null) return tf; tf.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent _evt) { try { tf.selectAll(); callF(action); } catch (Throwable __e) { messageBox(__e); }}}); return tf; } static JButton onEnter(JButton btn, final Object action) { if (action == null || btn == null) return btn; btn.addActionListener(actionListener(action)); return btn; } static JList onEnter(JList list, Object action) { list.addKeyListener(enterKeyListener(rCallOnSelectedListItem(list, action))); return list; } static JComboBox onEnter(final JComboBox cb, Runnable action) { { swing(() -> { if (cb.isEditable()) { JTextField text = (JTextField) cb.getEditor().getEditorComponent(); onEnter(text, action); } else { cb.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "enter"); cb.getActionMap().put("enter", abstractAction("", new Runnable() { public void run() { try { cb.hidePopup(); callF(action); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "cb.hidePopup(); callF(action);"; }})); } }); } return cb; } static JTable onEnter(final JTable table, final Object action) { table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Enter"); table.getActionMap().put("Enter", new AbstractAction() { public void actionPerformed(ActionEvent e) { callF(action, table.getSelectedRow()); } }); return table; } /*static JTextArea onEnter(final JTextArea ta, fO action) { addKeyListener(ta, enterKeyListener(action)); ret ta; }*/ static JTextField onEnter(Runnable action, JTextField tf) { return onEnter(tf, action); } static void swingLater(long delay, final Object r) { javax.swing.Timer timer = new javax.swing.Timer(toInt(delay), actionListener(wrapAsActivity(r))); timer.setRepeats(false); timer.start(); } static void swingLater(Object r) { var runnable = toRunnable(r); executingSwingCode(runnable); SwingUtilities.invokeLater(runnable); } static int toMS_int(double seconds) { return toInt_checked((long) (seconds*1000)); } static String fromUtf8(byte[] bytes) { try { return bytes == null ? null : new String(bytes, utf8charset()); } catch (Exception __e) { throw rethrow(__e); } } static Throwable unwrapTrivialExceptionWraps(Throwable e) { if (e == null) return e; while (e.getClass() == RuntimeException.class && e.getCause() != null && eq(e.getMessage(), str(e.getCause()))) e = e.getCause(); return e; } static Throwable innerException2(Throwable e) { if (e == null) return null; while (empty(e.getMessage()) && e.getCause() != null) e = e.getCause(); return e; } static String snippetImageURL(long snippetID) { return snippetImageURL(fsI(snippetID)); } static String snippetImageURL(String snippetID) { return snippetImageURL(snippetID, "png"); } static String snippetImageURL(String snippetID, String contentType) { if (snippetID == null || isURL(snippetID)) return snippetID; long id = parseSnippetID(snippetID); String url; if (isImageServerSnippet(id)) url = imageServerLink(id); else //url = "http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_" + id + "&contentType=image/" + contentType; url = "https://botcompany.de/img/" + id; return url; } static A println(A a) { return print(a); } static String fileServerURL() { return "https://botcompany.de/files"; } public static File mkdirsFor(File file) { return mkdirsForFile(file); } static void copyStreamWithPrints(InputStream in, OutputStream out, String pat) { try { byte[] buf = new byte[65536]; int total = 0; while (true) { int n = in.read(buf); if (n <= 0) return; out.write(buf, 0, n); if ((total+n)/100000 > total/100000) print(pat.replace("{*}", str(roundDownTo(100000, total)))); total += n; } } catch (Exception __e) { throw rethrow(__e); } } static File renameFile_assertTrue(File a, File b) { try { if (a.equals(b)) return b; // no rename necessary if (!a.exists()) throw fail("Source file not found: " + f2s(a)); if (b.exists()) throw fail("Target file exists: " + f2s(b)); mkdirsForFile(b); if (!a.renameTo(b)) throw fail("Can't rename " + f2s(a) + " to " + f2s(b)); return b; } catch (Exception __e) { throw rethrow(__e); } } static boolean isFile(File f) { return f != null && f.isFile(); } static boolean isFile(String path) { return isFile(newFile(path)); } static byte[] isGIF_magic = bytesFromHex("47494638"); // Actual signature is longer, but we're lazy static boolean isGIF(byte[] data) { return byteArrayStartsWith(data, isGIF_magic); } static boolean isGIF(File f) { return isGIF(loadBeginningOfBinaryFile(f, l(isGIF_magic))); } static void setVar(IVar v, A value) { if (v != null) v.set(value); } static IVF1 setVar(IVar v) { return a -> { if (v != null) v.set(a); }; } static Rect preferredScreenBounds() { return screenBounds_safe(preferredScreen()); } static void clickButton(final JButton b) { if (b != null) { swing(() -> { if (b.isEnabled()) b.doClick(); }); } } static void messageBox(final String msg) { print(msg); { swing(() -> { JOptionPane.showMessageDialog(null, msg, "JavaX", JOptionPane.INFORMATION_MESSAGE); }); } } static void messageBox(Throwable e) { //showConsole(); printStackTrace(e); messageBox(hideCredentials(innerException2(e))); } static ActionListener actionListener(final Object runnable) { return actionListener(runnable, null); } static ActionListener actionListener(final Object runnable, final Object instanceToHold) { if (runnable instanceof ActionListener) return (ActionListener) runnable; final Object info = _threadInfo(); return new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent _evt) { try { _threadInheritInfo(info); AutoCloseable __1 = holdInstance(instanceToHold); try { pcallF(runnable); } finally { _close(__1); }} catch (Throwable __e) { messageBox(__e); }}}; } static KeyListener enterKeyListener(final Object action) { return new KeyAdapter() { public void keyPressed(KeyEvent ke) { if (ke.getKeyCode() == KeyEvent.VK_ENTER) pcallF(action); } }; } static Runnable rCallOnSelectedListItem(final JList list, final Object action) { return new Runnable() { public void run() { try { pcallF(action, getSelectedItem(list)) ; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "pcallF(action, getSelectedItem(list))"; }}; } static AbstractAction abstractAction(String name, final Object runnable) { return new AbstractAction(name) { public void actionPerformed(ActionEvent evt) { pcallF(runnable); } }; } static Runnable wrapAsActivity(Object r) { if (r == null) return null; Runnable r2 = toRunnable(r); Object mod = dm_current_generic(); if (mod == null) return r2; return new Runnable() { public void run() { try { AutoCloseable c = (AutoCloseable) (rcall("enter", mod)); AutoCloseable __1 = c; try { r2.run(); } finally { _close(__1); }} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "AutoCloseable c = (AutoCloseable) (rcall enter(mod));\r\n temp c;\r\n r2.r..."; }}; } static int toInt_checked(long l) { if (l != (int) l) throw fail("Too large for int: " + l); return (int) l; } static String imageServerLink(String md5OrID) { if (possibleMD5(md5OrID)) return "https://botcompany.de/images/md5/" + md5OrID; return imageServerLink(parseSnippetID(md5OrID)); } static String imageServerLink(long id) { return "https://botcompany.de/images/" + id; } // TODO: optimize to x-(x%n) in case that's the same thing // (or x-mod(x,n)?) static int roundDownTo(int n, int x) { return x/n*n; } static long roundDownTo(long n, long x) { return x/n*n; } static double roundDownTo(double n, double x) { return floor(x/n)*n; } static byte[] bytesFromHex(String s) { return hexToBytes(s); } static boolean byteArrayStartsWith(byte[] a, byte[] b) { if (a == null || b == null) return false; if (a.length < b.length) return false; for (int i = 0; i < b.length; i++) if (a[i] != b[i]) return false; return true; } static byte[] loadBeginningOfBinaryFile(File file, int maxBytes) { return loadBinaryFilePart(file, 0, maxBytes); } static Rect screenBounds_safe(int iScreen) { return screenBounds(min(iScreen, screenCount()-1)); } static IF0 preferredScreen; static int preferredScreen() { return preferredScreen != null ? preferredScreen.get() : preferredScreen_base(); } final static int preferredScreen_fallback(IF0 _f) { return _f != null ? _f.get() : preferredScreen_base(); } static int preferredScreen_base() { return 0; } static String getSelectedItem(JList l) { return (String) l.getSelectedValue(); } static String getSelectedItem(JComboBox cb) { return strOrNull(cb.getSelectedItem()); } static Object dm_current_generic() { return getWeakRef(dm_current_generic_tl().get()); } static Object rcall(String method, Object o, Object... args) { return call_withVarargs(o, method, args); } static boolean possibleMD5(String s) { return isMD5(s); } static double floor(double d) { return Math.floor(d); } static byte[] loadBinaryFilePart(File file, long start, long end) { try { if (file == null) return null; RandomAccessFile raf = new RandomAccessFile(file, "r"); int n = toInt(min(raf.length(), end-start)); byte[] buffer = new byte[n]; try { raf.seek(start); raf.readFully(buffer, 0, n); return buffer; } finally { raf.close(); } } catch (Exception __e) { throw rethrow(__e); } } static Rect screenBounds(GraphicsDevice screen) { return screen == null ? null : toRect(screen.getDefaultConfiguration().getBounds()); } static Rect screenBounds(int iScreen) { return screenBounds(get(screenDevices(), iScreen)); } static int screenCount() { return l(GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()); } static A getWeakRef(Reference ref) { return ref == null ? null : ref.get(); } static x30_pkg.x30_util.BetterThreadLocal dm_current_generic_tl; static x30_pkg.x30_util.BetterThreadLocal dm_current_generic_tl() { if (dm_current_generic_tl == null) dm_current_generic_tl = vm_generalMap_getOrCreate("currentModule", () -> new x30_pkg.x30_util.BetterThreadLocal()); return dm_current_generic_tl; } static boolean isMD5(String s) { return l(s) == 32 && isLowerHexString(s); } static List screenDevices() { return asList(GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()); } static boolean isLowerHexString(String s) { for (int i = 0; i < l(s); i++) { char c = s.charAt(i); if (c >= '0' && c <= '9' || c >= 'a' && c <= 'f') { // ok } else return false; } return true; } static abstract class VF1 implements IVF1 { public abstract void get(A a); } // Meta - a "minimal" approach to adding meta-level to Java objects static class Meta implements IMeta { // Meta - a "minimal" approach to adding meta-level to Java objects // (implementing the interface IMeta) // We allocate one extra field for each Java object to make it // reasoning-compatible (reasoning-compatible = extensible with // fields of any name at runtime). // // We couldn't go for 0 extra fields (meta values must be linked // directly from the object) and there are no half fields in // Java... so there you go. // // Also, if you don't use any meta data, you are probably not // reasoning about anything. The point of reasoning in JavaX is // to attach information to objects directly used in the program. // Possible information contained in the meta field: // Origin, destination, security level, sender, cost center, // purpose, list of reifications, ... // So here it is. THE FIELD YOU HAVE BEEN WAITING FOR! // [We also have IMeta to retrofit foreign classes (rare but // probably useful).] ////////////////////// // The "meta" field // ////////////////////// // Generic meta value of any kind, but the typical case is it's a // Map with extra field values for the object etc. // "meta" is volatile to avoid synchronization; but you can also synchronize on // _tempMetaMutex() which is usually the object itself. Collections // and maps are exempt from using the collections's monitor as the meta // mutex because their monitor tends to be held for long operations // (e.g. cloneList). For those we use a substantially more complex // algorithm using a weakMap. Probably overkill. I may reconsider. volatile Object meta; // The meta field is not transient, thus by default it will be // persisted like anything else unless you customize your object // to suppress or modulate this. // ...and the interface methods public void _setMeta(Object meta) { this.meta = meta; } public Object _getMeta() { return meta; } // MOST functions are implemented in IMeta (default implementations) // Scaffolding convenience functions final boolean scaffolding(){ return scaffoldingEnabled(); } final boolean scaffolded(){ return scaffoldingEnabled(); } boolean scaffoldingEnabled() { return main.scaffoldingEnabled(this); } boolean scaffoldingEnabled(Object o) { return main.scaffoldingEnabled(o); } // Implementing setMetaToString String toString_base() { return super.toString(); } public String toString() { Object o = metaGet("toString", this); if (o instanceof String) return ((String) o); if (o instanceof IF1) return str(((IF1) o).get(this)); return toString_base(); } } // uses hash sets as inner sets unless subclassed // uses a hash map as the outer map by default static class MultiSetMapimplements IMultiMap { Map> data = new HashMap>(); int size; // number of values MultiSetMap() {} MultiSetMap(boolean useTreeMap) { if (useTreeMap) data = new TreeMap(); } MultiSetMap(MultiSetMap map) { putAll(map); } MultiSetMap(Map> data) { this.data = data;} boolean put(A key, B value) { synchronized(data) { Set set = data.get(key); if (set == null) data.put(key, set = _makeEmptySet()); if (!set.add(value)) return false; { ++size; return true; } }} boolean add(A key, B value) { return put(key, value); } void addAll(A key, Collection values) { synchronized(data) { putAll(key, values); }} void addAllIfNotThere(A key, Collection values) { synchronized(data) { for (B value : values) setPut(key, value); }} void setPut(A key, B value) { synchronized(data) { if (!containsPair(key, value)) put(key, value); }} final boolean contains(A key, B value){ return containsPair(key, value); } boolean containsPair(A key, B value) { synchronized(data) { return get(key).contains(value); }} void putAll(A key, Collection values) { synchronized(data) { for (B value : values) put(key, value); }} void removeAll(A key, Collection values) { synchronized(data) { for (B value : values) remove(key, value); }} public Set get(A key) { synchronized(data) { Set set = data.get(key); return set == null ? Collections. emptySet() : set; }} List getAndClear(A key) { synchronized(data) { List l = cloneList(data.get(key)); remove(key); return l; }} // return null if empty Set getOpt(A key) { synchronized(data) { return data.get(key); }} // returns actual mutable live set // creates the set if not there Set getActual(A key) { synchronized(data) { Set set = data.get(key); if (set == null) data.put(key, set = _makeEmptySet()); return set; }} // TODO: this looks unnecessary void clean(A key) { synchronized(data) { Set list = data.get(key); if (list != null && list.isEmpty()) data.remove(key); }} final public Set keys(){ return keySet(); } public Set keySet() { synchronized(data) { return data.keySet(); }} void remove(A key) { synchronized(data) { size -= l(data.get(key)); data.remove(key); }} void remove(A key, B value) { synchronized(data) { Set set = data.get(key); if (set != null) { if (set.remove(value)) { --size; if (set.isEmpty()) data.remove(key); } } }} void clear() { synchronized(data) { data.clear(); size = 0; }} boolean containsKey(A key) { synchronized(data) { return data.containsKey(key); }} B getFirst(A key) { synchronized(data) { return first(get(key)); }} void addAll(MultiSetMap map) { putAll(map); } void putAll(MultiSetMap map) { synchronized(data) { for (A key : map.keySet()) putAll(key, map.get(key)); }} void putAll(Map map) { synchronized(data) { if (map != null) for (Map.Entry e : map.entrySet()) put(e.getKey(), e.getValue()); }} final public int keyCount(){ return keysSize(); } public int keysSize() { synchronized(data) { return l(data); }} // full size public int size() { synchronized(data) { return size; }} // count values for key int getSize(A key) { return l(data.get(key)); } int count(A key) { return getSize(key); } // expensive operation Set reverseGet(B b) { synchronized(data) { Set l = new HashSet(); for (A key : data.keySet()) if (data.get(key).contains(b)) l.add(key); return l; }} // expensive operation A keyForValue(B b) { synchronized(data) { for (A key : data.keySet()) if (data.get(key).contains(b)) return key; return null; }} Map> asMap() { synchronized(data) { return cloneMap(data); }} public boolean isEmpty() { synchronized(data) { return data.isEmpty(); }} // override in subclasses Set _makeEmptySet() { return new HashSet(); } Collection> allLists() { synchronized(data) { return new HashSet(data.values()); } } List allValues() { return concatLists(values(data)); } List> allEntries() { synchronized(data) { List> l = emptyList(size); for (Map.Entry> __0 : _entrySet( data)) { A a = __0.getKey(); Set set = __0.getValue(); for (B b : set) l.add(pair(a, b)); } return l; }} Object mutex() { return data; } public String toString() { return "mm" + str(data); } Pair firstEntry() { synchronized(data) { if (empty(data)) return null; Map.Entry> entry = data.entrySet().iterator().next(); return pair(entry.getKey(), first(entry.getValue())); }} A firstKey() { synchronized(data) { return main.firstKey(data); }} A lastKey() { synchronized(data) { return (A) ((NavigableMap) data).lastKey(); }} A higherKey(Object a) { synchronized(data) { return (A) ((NavigableMap) data).higherKey(a); }} } static class NowFuture implements Future { T result; NowFuture() {} NowFuture(T result) { this.result = result;} public boolean cancel(final boolean b) { return false; } public boolean isCancelled() { return false; } public boolean isDone() { return true; } public T get() { return result; } public T get(long l, TimeUnit timeUnit) { return result; } } static class Var implements IVar, ISetter { Var() {} Var(A v) { this.v = v;} A v; // you can access this directly if you use one thread public synchronized void set(A a) { if (v != a) { v = a; notifyAll(); } } public synchronized A get() { return v; } public synchronized boolean has() { return v != null; } public void clear() { set(null); } public synchronized A getAndSet(A a) { var value = v; set(a); return value; } public IF0 getter() { return () -> get(); } public IVF1 setter() { return __84 -> set(__84); } public String toString() { return str(this.get()); } } static class AutoInitVar extends Var { Object make; boolean has = false; Lock lock = lock(); AutoInitVar() {} AutoInitVar(Object make) { this.make = make;} public A get() { if (has) return super.get(); Lock __0 = lock; lock(__0); try { if (has) return super.get(); set((A) pcallF(make)); make = null; has = true; return super.get(); } finally { unlock(__0); } } } static class DefunctClassLoader {} static class Scorer { double score, total; List successes, errors; // set to non-null if you want them filled boolean verboseFailures, verboseAll; final void add(double score){ addZeroToOne(score); } void addZeroToOne(double score) { ++total; this.score += clamp(score, 0, 1); } void addZeroToOneError(double error) { addZeroToOne(1-error); } void addError() { add(false); } void addError(A info) { add(false, info); } void error(A info) { addError(info); } void addOK() { add(true); } void addOK(A info) { add(true, info); } void ok() { addOK(); } void ok(A info) { addOK(info); } boolean add(boolean correct) { ++total; if (correct) ++score; return correct; } boolean add(boolean correct, A info) { main.add(correct ? successes : errors, info); if (verboseAll || verboseFailures && !correct) _print((correct ? "[GOOD] " : "[BAD] ") + info); return add(correct); } // works if you use Scorer or Scorer void eq(Object a, Object b) { if (_eq(a, b)) add(true); else add(false, (A) (a + " != " + b)); } void print() { main.print(toString()); } public String toString() { return formatDouble(ratioToPercent(score, total), 1) + "% correct (n=" + formatDouble(total, 1) + ")"; } double get() { return ratioToPercent(score, total); } double percentScore() { return get(); } double score() { return get(); } boolean allCorrect() { return score == total; } void add(Scorer scorer) { if (scorer == null) return; total += scorer.total; score += scorer.score; addAll(successes, scorer.successes); addAll(errors, scorer.errors); } void collectErrors() { errors = new ArrayList(); } void collectSuccesses() { successes = new ArrayList(); } } static interface ITokCondition { boolean get(List tok, int i); // i = N Index } static abstract class TokCondition implements ITokCondition { public abstract boolean get(List tok, int i); // i = N Index } // differences to AbstractList.subList / ArrayList.subList: // -probably doesn't handle modCount the same way // // made from AbstractList.subList static class SubList extends AbstractList implements ISubList { List root; SubList parent; int offset; int size; /** * Constructs a sublist of an arbitrary AbstractList, which is * not a SubList itself. */ public SubList(List root, int fromIndex, int toIndex) { if (root instanceof SubList) { this.parent = (SubList) root; this.root = ((SubList) root).root; this.offset = ((SubList) root).offset + fromIndex; } else { this.parent = null; this.root = root; this.offset = fromIndex; } this.size = toIndex - fromIndex; } public E set(int index, E element) { Objects.checkIndex(index, size); checkForComodification(); return root.set(offset + index, element); } public E get(int index) { Objects.checkIndex(index, size); checkForComodification(); return root.get(offset + index); } public int size() { checkForComodification(); return size; } public void add(int index, E element) { rangeCheckForAdd(index); checkForComodification(); root.add(offset + index, element); updateSizeAndModCount(1); } public E remove(int index) { Objects.checkIndex(index, size); checkForComodification(); E result = root.remove(offset + index); updateSizeAndModCount(-1); return result; } protected void removeRange(int fromIndex, int toIndex) { checkForComodification(); root.subList(offset + fromIndex, offset + toIndex).clear(); updateSizeAndModCount(fromIndex - toIndex); } public boolean addAll(Collection c) { return addAll(size, c); } public boolean addAll(int index, Collection c) { rangeCheckForAdd(index); int cSize = c.size(); if (cSize==0) return false; checkForComodification(); root.addAll(offset + index, c); updateSizeAndModCount(cSize); return true; } public Iterator iterator() { return listIterator(); } public ListIterator listIterator(int index) { checkForComodification(); rangeCheckForAdd(index); return new ListIterator() { private final ListIterator i = root.listIterator(offset + index); public boolean hasNext() { return nextIndex() < size; } public E next() { if (hasNext()) return i.next(); else throw new NoSuchElementException(); } public boolean hasPrevious() { return previousIndex() >= 0; } public E previous() { if (hasPrevious()) return i.previous(); else throw new NoSuchElementException(); } public int nextIndex() { return i.nextIndex() - offset; } public int previousIndex() { return i.previousIndex() - offset; } public void remove() { i.remove(); updateSizeAndModCount(-1); } public void set(E e) { i.set(e); } public void add(E e) { i.add(e); updateSizeAndModCount(1); } }; } public List subList(int fromIndex, int toIndex) { _subListRangeCheck(fromIndex, toIndex, size); return new SubList<>(this, fromIndex, toIndex); } private void rangeCheckForAdd(int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } private String outOfBoundsMsg(int index) { return "Index: "+index+", Size: "+size; } private void checkForComodification() {} private void updateSizeAndModCount(int sizeChange) { SubList slist = this; do { slist.size += sizeChange; slist = slist.parent; } while (slist != null); } public List rootList() { return root; } public List parentList() { return parent; } public int subListOffset() { return offset; } } // In the newest pinging system (with flag PingV3), a ping source // is the object that "allows" some code to run. // When that code calls ping(), the ping source's action (if defined) // is triggered. // This allows randomly interrupting code execution, for example. static class PingSource { // returns true if it slept final public PingSource setAction(IF0 action){ return action(action); } public PingSource action(IF0 action) { this.action = action; return this; } final public IF0 getAction(){ return action(); } public IF0 action() { return action; } volatile IF0 action; // optional description of this ping source String text; // optional thread pool that this ping source likes to run in ThreadPool threadPool; PingSource() {} PingSource(ThreadPool threadPool) { this.threadPool = threadPool;} PingSource(ThreadPool threadPool, String text) { this.text = text; this.threadPool = threadPool;} PingSource(IF0 action) { this.action = action;} // returns true if it slept final boolean get() { var a = action; return a != null && a.get(); } final void ping() { var a = action; if (a != null) a.get(); } void cancel() { action = new Cancelled(); } class Cancelled implements IF0 { public Boolean get() { throw new PingSourceCancelledException(PingSource.this); } } class Encapsulated implements Runnable , IFieldsToList{ Runnable r; Encapsulated() {} Encapsulated(Runnable r) { this.r = r;}public Object[] _fieldsToList() { return new Object[] {r}; } public void run() { try { //System.out.println("Encapsulated running: " + r); try { pingSource_tl().set(PingSource.this); //System.out.println("Ping source set"); ping(); r.run(); //System.out.println("Done running"); } finally { //System.out.println("Finally"); pingSource_tl().set(null); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return PingSource.this + ": " + r; } } void dO(Runnable r) { if (r == null) return; threadPool.acquireThreadOrQueue(new Encapsulated(r)); } public String toString() { String t = text; return nempty(t) ? t : super.toString(); } ISleeper_v2 sleeper() { return threadPool.sleeper(); } } interface IntSize { int size(); default boolean isEmpty() { return size() == 0; } } // -has fast nextElement() and prevElement() // -design allows for more functions like reordering the list // -Saves up to 34% in space over LinkedHashSet // (e.g. 22% for a set of 1,000 Ints) static class CompactLinkedHashSet extends AbstractSet { UnsynchronizedCompactHashSet> entries = new UnsynchronizedCompactHashSet(); Entry head, tail; static class Entry { A value; Entry prev, next; public int hashCode() { return _hashCode(value); } // "magic" equals function for CompactHashSet lookup without temp object public boolean equals(Object o) { return o == this || eq(value, o); } } public boolean add(A a) { if (entries.contains(a)) return false; Entry n = new Entry(); n.value = a; n.prev = tail; if (tail != null) tail.next = n; tail = n; if (head == null) head = n; entries.add(n); return true; } public boolean remove(Object a) { return remove(entries.find(a)); } public boolean remove(Entry node) { if (node == null) return false; if (node.next != null) node.next.prev = node.prev; else tail = node.prev; if (node.prev != null) node.prev.next = node.next; else head = node.next; entries.remove(node); return true; } public int size() { return entries.size(); } public IterableIterator iterator() { return new IterableIterator() { Entry entry = head, prev = null; public boolean hasNext() { return entry != null; } public A next() { A a = entry.value; prev = entry; entry = entry.next; return a; } // untested public void remove() { if (prev == null) throw new IllegalStateException(); CompactLinkedHashSet.this.remove(prev); prev = null; } }; } public void clear() { entries.clear(); head = tail = null; } public boolean contains(Object a) { return entries.contains(a); } public A find(Object o) { Entry e = entries.find(o); return e == null ? null : e.value; } public A prevElement(A a) { Entry e = entries.find(a); if (e == null || e.prev == null) return null; return e.prev.value; } public A nextElement(A a) { Entry e = entries.find(a); if (e == null || e.next == null) return null; return e.next.value; } public A first() { return head == null ? null : head.value; } public A last() { return tail == null ? null : tail.value; } boolean removeIfSame(Object o) { A value = find(o); if (value == o) { remove(value); return true; } return false; } } static class CombinedMap extends AbstractMap { List> maps = new ArrayList(); CombinedMap() {} CombinedMap(Map... maps) { addAllNonNulls(this.maps, maps); } > CombinedMap(Collection maps) { addAllNonNulls(this.maps, maps); } public int size() { return lengthLevel2_maps(maps); } public Set> entrySet() { throw fail(); } public boolean containsKey(Object o) { for (Map map : maps) if (map.containsKey(o)) return true; return false; } @Override public B get(Object o) { for (Map map : maps) if (map.containsKey(o)) return map.get(o); return null; } } static class Fail extends RuntimeException implements IFieldsToList{ Object[] objects; Fail() {} Fail(Object... objects) { this.objects = objects;}public Object[] _fieldsToList() { return new Object[] {objects}; } Fail(Throwable cause, Object... objects) { super(cause); this.objects = objects; } public String toString() { return joinNemptiesWithColon("Fail", getMessage()); } public String getMessage() { return commaCombine(getCause(), objects); } } static class Rect implements WidthAndHeight , IFieldsToList{ static final String _fieldOrder = "x y w h"; int x; int y; int w; int h; Rect() {} Rect(int x, int y, int w, int h) { this.h = h; this.w = w; this.y = y; this.x = x;} public boolean equals(Object o) { if (!(o instanceof Rect)) return false; Rect __1 = (Rect) o; return x == __1.x && y == __1.y && w == __1.w && h == __1.h; } public int hashCode() { int h = 2543108; h = boostHashCombine(h, _hashCode(x)); h = boostHashCombine(h, _hashCode(y)); h = boostHashCombine(h, _hashCode(w)); h = boostHashCombine(h, _hashCode(h)); return h; } public Object[] _fieldsToList() { return new Object[] {x, y, w, h}; } Rect(Rectangle r) { x = r.x; y = r.y; w = r.width; h = r.height; } Rect(Pt p, int w, int h) { this.h = h; this.w = w; x = p.x; y = p.y; } Rect(Rect r) { x = r.x; y = r.y; w = r.w; h = r.h; } final Rectangle getRectangle() { return new Rectangle(x, y, w, h); } public String toString() { return x + "," + y + " / " + w + "," + h; } final int x1() { return x; } final int y1() { return y; } final int x2() { return x + w; } final int y2() { return y + h; } final boolean contains(Pt p) { return contains(p.x, p.y); } final boolean contains(int _x, int _y) { return _x >= x && _y >= y && _x < x+w && _y < y+h; } final boolean contains(Rectangle r) { return rectContains(this, r); } final boolean empty() { return w <= 0 || h <= 0; } final public int getWidth() { return w; } final public int getHeight() { return h; } final public int area() { return w*h; } final public int x() { return x; } final public int y() { return y; } WidthAndHeight widthAndHeight() { return main.widthAndHeight(w, h); } } static class Tok_GettableFields extends Tok_SettableOrGettableFields { // causes problems because non-static inner classes cannot have // static functions final public Tok_GettableFields setAddStaticFieldGetters(boolean addStaticFieldGetters){ return addStaticFieldGetters(addStaticFieldGetters); } public Tok_GettableFields addStaticFieldGetters(boolean addStaticFieldGetters) { this.addStaticFieldGetters = addStaticFieldGetters; return this; } final public boolean getAddStaticFieldGetters(){ return addStaticFieldGetters(); } public boolean addStaticFieldGetters() { return addStaticFieldGetters; } boolean addStaticFieldGetters = false; Tok_GettableFields() { super("gettable"); } String replacement() { return tok_formatDollarVars( "$fMod $type $var aka $getVar() { ret $var; }\n" + (!addStaticFieldGetters ? "" : "static public Field $metaField() { ret findFieldOfClass(selfType.class, $quoted); }\n") + "$modifiers $type", "metaField" , "f_" + var, "quoted" , quoted(var), "fMod" , joinWithSpace(functionModifiers()) + " public", "modifiers" , joinWithSpace(modifiers), "type", type, "var", var, "getVar" , "get" + firstToUpper(var)); } } static class Pt implements Comparable, IDoublePt { int x, y; Pt() {} Pt(Point p) { x = p.x; y = p.y; } Pt(int x, int y) { this.y = y; this.x = x;} Point getPoint() { return new Point(x, y); } public boolean equals(Object o) { return o instanceof Pt && x == ((Pt) o).x && y == ((Pt) o).y; } public int hashCode() { return boostHashCombine(x, y); } // compare in scan order public int compareTo(Pt p) { if (y != p.y) return cmp(y, p.y); return cmp(x, p.x); } public String toString() { return x + ", " + y; } double length() { return sqrt(x*x+y*y); } public Pt minus(Pt p) { return ptMinus(this, p); } public double x_double() { return x; } public double y_double() { return y; } } static abstract class F0 { abstract A get(); } static abstract class F1 { abstract B get(A a); } // you still need to implement hasNext() and next() static abstract class IterableIterator implements Iterator, Iterable { public Iterator iterator() { return this; } public void remove() { unsupportedOperation(); } } abstract static class RandomAccessAbstractList extends AbstractList implements RandomAccess { } static class TreeMultiMap extends MultiMap { TreeMultiMap() { super(true); } TreeMultiMap(MultiMap map) { this(); putAll(map); } NavigableMap> innerMap() { return (NavigableMap) data; } } static abstract class F2 { abstract C get(A a, B b); } // optimized for search - O(1) for searching for a certain element // set is O(log m) with m = number of occurrences of element final static class ContentsIndexedList extends RandomAccessAbstractList implements IContentsIndexedList, IContentsIndexedList2 { Map>> index = new HashMap(); // tokens by contents, sorted by index final ArrayList> list = new ArrayList(); final static class Elem extends HasIndex { A s; // actual token public String toString() { return "Elem " + quote(s) + "@" + idx; } } ContentsIndexedList() {} ContentsIndexedList(Map>> index) { this.index = index;} // use different type of index (e.g. ciMap) ContentsIndexedList(Collection l) { addAll(l); } public A get(int i) { return list.get(i).s; } public int size() { return list.size(); } public A set(int i, A s) { Elem t = list.get(i); A old = t.s; if (eq(old, s)) return old; removeFromIdx(t); t.s = s; addToIdx(t); return old; } public boolean add(A s) { ++modCount; Elem t = new Elem(); t.s = s; t.idx = size(); list.add(t); addToIdx(t); return true; } public void add(int i, A s) { ++modCount; Elem t = new Elem(); t.s = s; t.idx = i; list.add(i, t); reorder(i+1); addToIdx(t); } public boolean addAll(int i, Collection l) { int n = l.size(); if (n == 0) return false; ++modCount; List> l2 = emptyList(n); int j = i; for (A s : l) { Elem t = new Elem(); t.s = s; t.idx = j++; l2.add(t); } list.addAll(i, l2); reorder(i+n); for (Elem t : l2) addToIdx(t); return true; } public A remove(int i) { ++modCount; Elem t = list.get(i); removeFromIdx(t); list.remove(i); reorder(i); return t.s; } void reorder(int fromIdx) { int n = size(); for (int i = fromIdx; i < n; i++) list.get(i).idx = i; } void removeFromIdx(Elem t) { TreeSet> idx = index.get(t.s); idx.remove(t); if (idx.isEmpty()) index.remove(t.s); } void addToIdx(Elem t) { TreeSet> idx = index.get(t.s); if (idx == null) index.put(t.s, idx = new TreeSet()); idx.add(t); } @Override public int indexOf(Object s) { TreeSet> l = index.get(s); return l == null ? -1 : first(l).idx; } @Override public int lastIndexOf(Object s) { TreeSet> l = index.get(s); return l == null ? -1 : last(l).idx; } @Override public boolean contains(Object s) { return index.containsKey(s); } public void clear() { ++modCount; index.clear(); list.clear(); } protected void removeRange(int fromIndex, int toIndex) { if (fromIndex == toIndex) return; ++modCount; for (int i = fromIndex; i < toIndex; i++) removeFromIdx(list.get(i)); list.subList(fromIndex, toIndex).clear(); reorder(fromIndex); } public int[] indicesOf(A o) { TreeSet> idx = index.get(o); if (idx == null) return emptyIntArray(); int[] a = new int[idx.size()]; int i = 0; for (Elem t : idx) a[i++] = t.idx; return a; } public TreeSet indicesOf_treeSetOfHasIndex(A o) { return (TreeSet) index.get(o); } } interface PCallPolicy { void handlePcallFail(Throwable e); } public static interface IF0 { A get(); } static interface Hasher { int hashCode(A a); boolean equals(A a, A b); } static interface IContentsIndexedList2 extends List { TreeSet indicesOf_treeSetOfHasIndex(A o); } static abstract class CloseableIterableIterator extends IterableIterator implements AutoCloseable { public void close() throws Exception {} } static interface IF2 { C get(A a, B b); } static interface Producer { public A next(); // null when end } static interface IF1 { B get(A a); } static interface IVF1 { void get(A a); } static interface IVF2 { void get(A a, B b); } static interface IVar extends IF0 { void set(A a); A get(); // reified type of value (if available) default Class getType() { return null; } default IF0 getter() { return () -> get(); } default IVF1 setter() { return __1 -> set(__1); } default boolean has() { return get() != null; } default void clear() { set(null); } } static interface IIntPred { boolean get(int a); } static interface TokReplacer { // return string to replace section with // only C to C (start to end, exclusively) is replaced abstract String get(List tok, int start, int end); // start = C Index, end = N index } // immutable, has strong refs // Do not run in a synchronized block - it goes wrong in the presence // of elaborate classloaders (like in Gazelle BEA) // see #1102990 and #1102991 final static class _MethodCache { final Class c; final HashMap> cache = new HashMap(); _MethodCache(Class c) { this.c = c; _init(); } void _init() { Class _c = c; java.lang.Module myModule = getClass().getModule(); boolean anyHiddenClasses = false; while (_c != null) { boolean exported = classIsExportedTo(_c, myModule); if (!exported) anyHiddenClasses = true; else for (Method m : _c.getDeclaredMethods()) if ((anyHiddenClasses || !isAbstract(m)) && !reflection_isForbiddenMethod(m)) multiMapPut(cache, m.getName(), makeAccessible(m)); _c = _c.getSuperclass(); } // add default methods - this might lead to a duplication // because the overridden method is also added, but it's not // a problem except for minimal performance loss. // If any classes in the hierarchy were inaccessible, we add // all interface methods (see test_callForbiddenMethodByReflection for a test) for (Class intf : allInterfacesImplementedBy(c)) for (Method m : intf.getDeclaredMethods()) if ((anyHiddenClasses || m.isDefault()) && !reflection_isForbiddenMethod(m)) multiMapPut(cache, m.getName(), makeAccessible(m)); } // Returns only matching methods Method findMethod(String method, Object[] args) { try { List m = cache.get(method); if (m == null) return null; int n = m.size(); for (int i = 0; i < n; i++) { Method me = m.get(i); if (call_checkArgs(me, args, false)) return me; } return null; } catch (Exception __e) { throw rethrow(__e); } } Method findStaticMethod(String method, Object[] args) { try { List m = cache.get(method); if (m == null) return null; int n = m.size(); for (int i = 0; i < n; i++) { Method me = m.get(i); if (isStaticMethod(me) && call_checkArgs(me, args, false)) return me; } return null; } catch (Exception __e) { throw rethrow(__e); } } //Cl allMethods() { ret allValues(cache); } } static class Tok_SettableWithVar extends Tok_SettableWithChangeFields { Tok_SettableWithVar() { super("settableWithVar"); } String replacement() { return tok_formatDollarVars( "public transient simplyCached FieldVar<$boxedType> $varFunc() {\r\n ret new FieldVar<$boxedType>(this, $fieldName, -> $var(), $var -> $var($var)); }\n", "varFunc" , "var" + firstToUpper(var), "var", var, "boxedType", boxedType(), "fieldName" , quoted(var)) + super.replacement(); } } static class Matches { String[] m; Matches() {} Matches(String... m) { this.m = m;} String get(int i) { return i < m.length ? m[i] : null; } String unq(int i) { return unquote(get(i)); } String tlc(int i) { return unq(i).toLowerCase(); } boolean bool(int i) { return "true".equals(unq(i)); } String rest() { return m[m.length-1]; } // for matchStart int psi(int i) { return Integer.parseInt(unq(i)); } public String toString() { return "Matches(" + joinWithComma(quoteAll(asList(m))) + ")"; } public int hashCode() { return _hashCode(toList(m)); } public boolean equals(Object o) { return o instanceof Matches && arraysEqual(m, ((Matches) o).m); } } static class OrderedMultiIterator> extends IterableIterator { static class Stream> implements Comparable> , IFieldsToList{ Iterator iterator; A element; Stream() {} Stream(Iterator iterator, A element) { this.element = element; this.iterator = iterator;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + iterator + ", " + element + ")"; }public Object[] _fieldsToList() { return new Object[] {iterator, element}; } public int compareTo(Stream stream) { return element.compareTo(stream.element); } boolean advance() { if (!iterator.hasNext()) return false; element = iterator.next(); return true; } } ArrayList> streams = new ArrayList(); boolean sorted = false; void add(Iterable it) { add(iteratorOrNull(it)); } void add(Iterator iterator) { if (iterator == null || !iterator.hasNext()) return; A element = iterator.next(); streams.add(new Stream(iterator, element)); sorted = false; } void addAll(Iterable> iterators) { for (var it : unnullForIteration(iterators)) add(it); } public boolean hasNext() { return nempty(streams); } public A next() { if (!sorted) { sortInPlace(streams); sorted = true; } var stream = first(streams); A element = stream.element; if (!stream.advance()) streams.remove(0); else { // put stream in the right place int i = 0, n = streams.size()-1; Stream stream2; while (i < n && stream.compareTo(stream2 = streams.get(i+1)) >= 0) streams.set(i++, stream2); streams.set(i, stream); } return element; } } // for the version with MasterSymbol (used WAY back in "Smart Bot"!) see #1010608 static class Symbol implements CharSequence { String text; Symbol() {} Symbol(String text, boolean dummy) { this.text = text;} // weird signature to prevent accidental calling public int hashCode() { return _hashCode(text); } public String toString() { return text; } public boolean equals(Object o) { return this == o; } // implementation of CharSequence methods public int length() { return text.length(); } public char charAt(int index) { return text.charAt(index); } public CharSequence subSequence(int start, int end) { return text.substring(start, end); } } static interface IMeta { // see class "Meta" for the bla bla public void _setMeta(Object meta); public Object _getMeta(); default public IAutoCloseableF0 _tempMetaMutex() { return new IAutoCloseableF0() { public Object get() { return IMeta.this; } public void close() {} }; } // actually query another object default public Object getMeta(Object obj, Object key){ return metaGet(obj, key); } default public Object metaGet(Object obj, Object key) { // call global function return metaMapGet(obj, key); } default public Object metaGet(String key, Object obj) { // call global function return metaMapGet(obj, key); } default public Object getMeta(Object key){ return metaGet(key); } default public Object metaGet(Object key) { if (key == null) return null; Object meta = _getMeta(); if (meta instanceof Map) return ((Map) meta).get(key); return null; } default public void metaSet(IMeta obj, Object key, Object value){ metaPut(obj, key, value); } default public void metaPut(IMeta obj, Object key, Object value) { // call global function metaMapPut(obj, key, value); } default public void metaSet(Object key, Object value){ metaPut(key, value); } default public void metaPut(Object key, Object value) { if (key == null) return; Map map = convertObjectMetaToMap(this); syncMapPutOrRemove(map, key, value); } } static interface IContentsIndexedList extends List { int[] indicesOf(A o); } static class Tok_SettableWithChangeFields extends Tok_SettableOrGettableFields { Tok_SettableWithChangeFields() { super("settableWithChange"); } Tok_SettableWithChangeFields(String keyword) { super(keyword); } String replacement() { return tok_formatDollarVars( "$fMod selfType $var aka $setVar($type $var) { if (!eq(this.$var, $var)) { this.$var = $var; change(); } this; }\n" + "gettable $modifiers $type", "fMod" , joinWithSpace(functionModifiers()) + " public", "modifiers" , joinWithSpace(modifiers), "type", type, "var", var, "setVar" , "set" + firstToUpper(var)); } } // records its full size (total value count) in a field now static class MultiMap implements IMultiMap { Map> data = new HashMap>(); int fullSize; MultiMap() {} MultiMap(boolean useTreeMap) { if (useTreeMap) data = new TreeMap(); } MultiMap(MultiMap map) { putAll(map); } MultiMap(Map> data) { this.data = data;} void put(A key, B value) { synchronized(data) { List list = data.get(key); if (list == null) data.put(key, list = _makeEmptyList()); list.add(value); ++fullSize; }} void add(A key, B value) { put(key, value); } void addAll(A key, Collection values) { putAll(key, values); } void addAllIfNotThere(A key, Collection values) { synchronized(data) { for (B value : values) setPut(key, value); }} void setPut(A key, B value) { synchronized(data) { if (!containsPair(key, value)) put(key, value); }} boolean containsPair(A key, B value) { synchronized(data) { return get(key).contains(value); }} void putAll(Collection keys, B value) { synchronized(data) { for (A key : unnullForIteration(keys)) put(key, value); }} void putAll(A key, Collection values) { synchronized(data) { if (nempty(values)) getActual(key).addAll(values); }} void putAll(Iterable> pairs) { synchronized(data) { for (Pair p : unnullForIteration(pairs)) put(p.a, p.b); }} void removeAll(A key, Collection values) { synchronized(data) { for (B value : values) remove(key, value); }} public List get(A key) { synchronized(data) { List list = data.get(key); return list == null ? Collections. emptyList() : list; }} List getOpt(A key) { synchronized(data) { return data.get(key); }} List getAndClear(A key) { synchronized(data) { List l = cloneList(data.get(key)); remove(key); return l; }} // returns actual mutable live list // creates the list if not there List getActual(A key) { synchronized(data) { List list = data.get(key); if (list == null) data.put(key, list = _makeEmptyList()); return list; }} void clean(A key) { synchronized(data) { List list = data.get(key); if (list != null && list.isEmpty()) { fullSize -= l(list); data.remove(key); } }} final public Set keys(){ return keySet(); } public Set keySet() { synchronized(data) { return data.keySet(); }} void remove(A key) { synchronized(data) { fullSize -= l(this.getOpt(key)); data.remove(key); }} final void remove(Pair p){ removePair(p); } void removePair(Pair p) { if (p != null) remove(p.a, p.b); } void remove(A key, B value) { synchronized(data) { List list = data.get(key); if (list != null) { if (list.remove(value)) fullSize--; if (list.isEmpty()) data.remove(key); } }} void clear() { synchronized(data) { data.clear(); }} boolean containsKey(A key) { synchronized(data) { return data.containsKey(key); }} B getFirst(A key) { synchronized(data) { List list = get(key); return list.isEmpty() ? null : list.get(0); }} void addAll(MultiMap map) { putAll(map); } void putAll(MultiMap map) { synchronized(data) { for (A key : map.keySet()) putAll(key, map.get(key)); }} void putAll(Map map) { synchronized(data) { if (map != null) for (Map.Entry e : map.entrySet()) put(e.getKey(), e.getValue()); }} final public int keyCount(){ return keysSize(); } public int keysSize() { synchronized(data) { return l(data); }} final public int fullSize(){ return size(); } public int size() { synchronized(data) { return fullSize; }} // expensive operation List reverseGet(B b) { synchronized(data) { List l = new ArrayList(); for (A key : data.keySet()) if (data.get(key).contains(b)) l.add(key); return l; }} Map> asMap() { synchronized(data) { return cloneMap(data); }} public boolean isEmpty() { synchronized(data) { return data.isEmpty(); }} // override in subclasses List _makeEmptyList() { return new ArrayList(); } // returns live lists Collection> allLists() { synchronized(data) { return new ArrayList(data.values()); } } Collection> values() { return allLists(); } List allValues() { return concatLists(data.values()); } Object mutex() { return data; } public String toString() { return "mm" + str(data); } Map> innerMap() { return data; } } // Note: This does have the values problem (complicated values can cause memory leaks) static class BetterThreadLocal { Map map = newWeakHashMap(); BetterThreadLocal() {} BetterThreadLocal(A value) { set(value); } boolean isSet() { return map.containsKey(currentThread()); } A get() { if (map.containsKey(currentThread())) return map.get(currentThread()); A value = initialValue(); set(value); return value; } A get(Thread thread) { return thread == null ? null : map.get(thread); } void set(A a) { map.put(currentThread(), a); } public A initialValue() { return null; } } static class RandomAccessSubList extends SubList implements RandomAccess { RandomAccessSubList(List root, int fromIndex, int toIndex) { super(root, fromIndex, toIndex); } } static interface IResourceLoader { String loadSnippet(String snippetID); String getTranspiled(String snippetID); // with libs int getSnippetType(String snippetID); String getSnippetTitle(String snippetID); File loadLibrary(String snippetID); //ifndef NoJavaXJar default File pathToJavaXJar() { return pathToJavaxJar_noResourceLoader(); } //endifndef // may return null, then caller compiles themselves default File getSnippetJar(String snippetID, String transpiledSrc) { return null; } } /* * @(#)WeakHashMap.java 1.5 98/09/30 * * Copyright 1998 by Sun Microsystems, Inc., * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. * All rights reserved. * * This software is the confidential and proprietary information * of Sun Microsystems, Inc. ("Confidential Information"). You * shall not disclose such Confidential Information and shall use * it only in accordance with the terms of the license agreement * you entered into with Sun. */ // From https://github.com/mernst/plume-lib/blob/df0bfafc3c16848d88f4ea0ef3c8bf3367ae085e/java/src/plume/WeakHasherMap.java static final class WeakHasherMap extends AbstractMap implements Map { private Hasher hasher = null; /*@Pure*/ private boolean keyEquals(Object k1, Object k2) { return (hasher==null ? k1.equals(k2) : hasher.equals(k1, k2)); } /*@Pure*/ private int keyHashCode(Object k1) { return (hasher==null ? k1.hashCode() : hasher.hashCode(k1)); } // The WeakKey class can't be static because it depends on the hasher. // That in turn means that its methods can't be static. // However, I need to be able to call the methods such as create() that // were static in the original version of this code. // This finesses that. private /*@Nullable*/ WeakKey WeakKeyCreate(K k) { if (k == null) return null; else return new WeakKey(k); } private /*@Nullable*/ WeakKey WeakKeyCreate(K k, ReferenceQueue q) { if (k == null) return null; else return new WeakKey(k, q); } // Cannot be a static class: uses keyHashCode() and keyEquals() private final class WeakKey extends WeakReference { private int hash; /* Hashcode of key, stored here since the key may be tossed by the GC */ private WeakKey(K k) { super(k); hash = keyHashCode(k); } private /*@Nullable*/ WeakKey create(K k) { if (k == null) return null; else return new WeakKey(k); } private WeakKey(K k, ReferenceQueue q) { super(k, q); hash = keyHashCode(k); } private /*@Nullable*/ WeakKey create(K k, ReferenceQueue q) { if (k == null) return null; else return new WeakKey(k, q); } /* A WeakKey is equal to another WeakKey iff they both refer to objects that are, in turn, equal according to their own equals methods */ /*@Pure*/ @Override public boolean equals(/*@Nullable*/ Object o) { if (o == null) return false; // never happens if (this == o) return true; // This test is illegal because WeakKey is a generic type, // so use the getClass hack below instead. // if (!(o instanceof WeakKey)) return false; if (!(o.getClass().equals(WeakKey.class))) return false; Object t = this.get(); @SuppressWarnings("unchecked") Object u = ((WeakKey)o).get(); if ((t == null) || (u == null)) return false; if (t == u) return true; return keyEquals(t, u); } /*@Pure*/ @Override public int hashCode() { return hash; } } /* Hash table mapping WeakKeys to values */ private HashMap hash; /* Reference queue for cleared WeakKeys */ private ReferenceQueue queue = new ReferenceQueue(); /* Remove all invalidated entries from the map, that is, remove all entries whose keys have been discarded. This method should be invoked once by each public mutator in this class. We don't invoke this method in public accessors because that can lead to surprising ConcurrentModificationExceptions. */ @SuppressWarnings("unchecked") private void processQueue() { WeakKey wk; while ((wk = (WeakKey)queue.poll()) != null) { // unchecked cast hash.remove(wk); } } /* -- Constructors -- */ /** * Constructs a new, empty WeakHashMap with the given * initial capacity and the given load factor. * * @param initialCapacity the initial capacity of the * WeakHashMap * * @param loadFactor the load factor of the WeakHashMap * * @throws IllegalArgumentException If the initial capacity is less than * zero, or if the load factor is * nonpositive */ public WeakHasherMap(int initialCapacity, float loadFactor) { hash = new HashMap(initialCapacity, loadFactor); } /** * Constructs a new, empty WeakHashMap with the given * initial capacity and the default load factor, which is * 0.75. * * @param initialCapacity the initial capacity of the * WeakHashMap * * @throws IllegalArgumentException If the initial capacity is less than * zero */ public WeakHasherMap(int initialCapacity) { hash = new HashMap(initialCapacity); } /** * Constructs a new, empty WeakHashMap with the default * capacity and the default load factor, which is 0.75. */ public WeakHasherMap() { hash = new HashMap(); } /** * Constructs a new, empty WeakHashMap with the default * capacity and the default load factor, which is 0.75. * The WeakHashMap uses the specified hasher for hashing * keys and comparing them for equality. * @param h the Hasher to use when hashing values for this map */ public WeakHasherMap(Hasher h) { hash = new HashMap(); hasher = h; } /* -- Simple queries -- */ /** * Returns the number of key-value mappings in this map. * Note: In contrast to most implementations of the * Map interface, the time required by this operation is * linear in the size of the map. */ /*@Pure*/ @Override public int size() { return entrySet().size(); } /** * Returns true if this map contains no key-value mappings. */ /*@Pure*/ @Override public boolean isEmpty() { return entrySet().isEmpty(); } /** * Returns true if this map contains a mapping for the * specified key. * * @param key the key whose presence in this map is to be tested */ /*@Pure*/ @Override public boolean containsKey(Object key) { @SuppressWarnings("unchecked") K kkey = (K) key; return hash.containsKey(WeakKeyCreate(kkey)); } /* -- Lookup and modification operations -- */ /** * Returns the value to which this map maps the specified key. * If this map does not contain a value for this key, then return * null. * * @param key the key whose associated value, if any, is to be returned */ /*@Pure*/ @Override public /*@Nullable*/ V get(Object key) { // type of argument is Object, not K @SuppressWarnings("unchecked") K kkey = (K) key; return hash.get(WeakKeyCreate(kkey)); } /** * Updates this map so that the given key maps to the given * value. If the map previously contained a mapping for * key then that mapping is replaced and the previous value is * returned. * * @param key the key that is to be mapped to the given * value * @param value the value to which the given key is to be * mapped * * @return the previous value to which this key was mapped, or * null if if there was no mapping for the key */ @Override public V put(K key, V value) { processQueue(); return hash.put(WeakKeyCreate(key, queue), value); } /** * Removes the mapping for the given key from this map, if * present. * * @param key the key whose mapping is to be removed * * @return the value to which this key was mapped, or null if * there was no mapping for the key */ @Override public V remove(Object key) { // type of argument is Object, not K processQueue(); @SuppressWarnings("unchecked") K kkey = (K) key; return hash.remove(WeakKeyCreate(kkey)); } /** * Removes all mappings from this map. */ @Override public void clear() { processQueue(); hash.clear(); } /* -- Views -- */ /* Internal class for entries */ // This can't be static, again because of dependence on hasher. @SuppressWarnings("TypeParameterShadowing") private final class Entry implements Map.Entry { private Map.Entry ent; private K key; /* Strong reference to key, so that the GC will leave it alone as long as this Entry exists */ Entry(Map.Entry ent, K key) { this.ent = ent; this.key = key; } /*@Pure*/ @Override public K getKey() { return key; } /*@Pure*/ @Override public V getValue() { return ent.getValue(); } @Override public V setValue(V value) { return ent.setValue(value); } /*@Pure*/ private boolean keyvalEquals(K o1, K o2) { return (o1 == null) ? (o2 == null) : keyEquals(o1, o2); } /*@Pure*/ private boolean valEquals(V o1, V o2) { return (o1 == null) ? (o2 == null) : o1.equals(o2); } /*@Pure*/ @SuppressWarnings("NonOverridingEquals") public boolean equals(Map.Entry e /* Object o*/) { // if (! (o instanceof Map.Entry)) return false; // Map.Entry e = (Map.Entry)o; return (keyvalEquals(key, e.getKey()) && valEquals(getValue(), e.getValue())); } /*@Pure*/ @Override public int hashCode() { V v; return (((key == null) ? 0 : keyHashCode(key)) ^ (((v = getValue()) == null) ? 0 : v.hashCode())); } } /* Internal class for entry sets */ private final class EntrySet extends AbstractSet> { Set> hashEntrySet = hash.entrySet(); @Override public Iterator> iterator() { return new Iterator>() { Iterator> hashIterator = hashEntrySet.iterator(); Map.Entry next = null; @Override public boolean hasNext() { while (hashIterator.hasNext()) { Map.Entry ent = hashIterator.next(); WeakKey wk = ent.getKey(); K k = null; if ((wk != null) && ((k = wk.get()) == null)) { /* Weak key has been cleared by GC */ continue; } next = new Entry(ent, k); return true; } return false; } @Override public Map.Entry next() { if ((next == null) && !hasNext()) throw new NoSuchElementException(); Map.Entry e = next; next = null; return e; } @Override public void remove() { hashIterator.remove(); } }; } /*@Pure*/ @Override public boolean isEmpty() { return !(iterator().hasNext()); } /*@Pure*/ @Override public int size() { int j = 0; for (Iterator> i = iterator(); i.hasNext(); i.next()) j++; return j; } @Override public boolean remove(Object o) { processQueue(); if (!(o instanceof Map.Entry)) return false; @SuppressWarnings("unchecked") Map.Entry e = (Map.Entry)o; // unchecked cast Object ev = e.getValue(); WeakKey wk = WeakKeyCreate(e.getKey()); Object hv = hash.get(wk); if ((hv == null) ? ((ev == null) && hash.containsKey(wk)) : hv.equals(ev)) { hash.remove(wk); return true; } return false; } /*@Pure*/ @Override public int hashCode() { int h = 0; for (Iterator> i = hashEntrySet.iterator(); i.hasNext(); ) { Map.Entry ent = i.next(); WeakKey wk = ent.getKey(); Object v; if (wk == null) continue; h += (wk.hashCode() ^ (((v = ent.getValue()) == null) ? 0 : v.hashCode())); } return h; } } private /*@Nullable*/ Set> entrySet = null; /** * Returns a Set view of the mappings in this map. */ /*@SideEffectFree*/ @Override public Set> entrySet() { if (entrySet == null) entrySet = new EntrySet(); return entrySet; } // find matching key K findKey(Object key) { processQueue(); K kkey = (K) key; // TODO: use replacement for HashMap to avoid reflection WeakKey wkey = WeakKeyCreate(kkey); WeakKey found = hashMap_findKey(hash, wkey); return found == null ? null : found.get(); } } // just a marker interface for non-persistable classes interface TransientObject {} static class proxy_InvocationHandler implements InvocationHandler { Object target; proxy_InvocationHandler() {} proxy_InvocationHandler(Object target) { this.target = target;} public Object invoke(Object proxy, Method method, Object[] args) { return call(target, method.getName(), unnull(args)); } } static class Tok_MethodDecl { List tok; int iStart, iModifiers, iTypeArgs, iType, iEndOfType, iJavaXMod; int iName, iOpening, iClosing; final public String getName(){ return name(); } public String name() { return name; } String name; List allNames = new ArrayList(); int iBody; boolean parsed = false; Tok_MethodDecl(List tok, int iStart) { this.iStart = iStart; this.tok = tok; iOpening = indexOf(tok, iStart, "("); if (iOpening < 0) return; iName = iOpening-2; name = main.get(tok, iName); allNames.add(name); if (!isIdentifier(name)) return; while (eqGet(tok, iName-2, "aka") && isIdentifier(main.get(tok, iName-2))) { iName -= 4; name = main.get(tok, iName); allNames.add(name); } // find end of arguments iClosing = findEndOfBracketPart2(tok, iOpening)-1; // find end of block or semicolon iBody = indexOfAny(tok, iClosing, "{", ";"); // find javax modifiers, return type & modifiers iJavaXMod = tok_leftScanJavaxModifiers(tok, iName); iEndOfType = iJavaXMod; iType = tok_leftScanType(tok, iJavaXMod); iTypeArgs = tok_leftScanTypeArgsOpt(tok, iType); iModifiers = leftScanModifiers(tok, iTypeArgs); iStart = iModifiers; reverseInPlace(allNames); parsed = true; } List args_unparsed_cache; List args_unparsed() { if (args_unparsed_cache == null) args_unparsed_cache = args_unparsed_load(); return args_unparsed_cache;} List args_unparsed_load() { return tok_parseArgsDeclList2(subList(tok, iOpening+1, iClosing)); } // return type List tokType() { return subList(tok, iType-1, iName); } String type() { return join(tokType()); } Boolean isVoid_cache; boolean isVoid() { if (isVoid_cache == null) isVoid_cache = isVoid_load(); return isVoid_cache;} boolean isVoid_load() { return containsOneOf(codeTokens(tokType()), javaxVoidAliases()); } List tokModifiers() { return subList(tok, iStart, iName-1); } boolean get() { return parsed; } List argDecls_cache; List argDecls() { if (argDecls_cache == null) argDecls_cache = argDecls_load(); return argDecls_cache;} List argDecls_load() { return tok_argDecls(subList(tok, iOpening+1, iClosing)); } List argNames() { return map(argDecls(), a -> a.name); } boolean hasBody() { return eqGet(tok, iBody, "{"); } Integer iEndOfBody_cache; int iEndOfBody() { if (iEndOfBody_cache == null) iEndOfBody_cache = iEndOfBody_load(); return iEndOfBody_cache;} int iEndOfBody_load() { return hasBody() ? tok_scanBlock_idx(tok, iBody) : iBody+2; } int iEnd() { return iEndOfBody(); } } // A version of ContentsIndexedList specialized for tokens // optimized for search - O(1) for searching for a token // set is O(log m) with m = number of occurrences of token final static class TokenIndexedList3 extends RandomAccessAbstractList implements IContentsIndexedList, IContentsIndexedList2 { final HashMap> index = new HashMap(); // tokens by contents, sorted by index final ArrayList list = new ArrayList(); final static class Token extends HasIndex { String s; // actual token public String toString() { return "Token " + quote(s) + "@" + idx; } } TokenIndexedList3() {} TokenIndexedList3(Collection l) { addAll(l); } public String get(int i) { return list.get(i).s; } public int size() { return list.size(); } public String set(int i, String s) { Token t = list.get(i); String old = t.s; if (eq(old, s)) return old; removeFromIdx(t); t.s = s; addToIdx(t); return old; } public boolean add(String s) { ++modCount; Token t = new Token(); t.s = s; t.idx = size(); list.add(t); addToIdx(t); return true; } public void add(int i, String s) { ++modCount; Token t = new Token(); t.s = s; t.idx = i; list.add(i, t); reorder(i+1); addToIdx(t); } public boolean addAll(int i, Collection l) { int n = l.size(); if (n == 0) return false; ++modCount; List l2 = emptyList(n); int j = i; for (String s : l) { Token t = new Token(); t.s = s; t.idx = j++; l2.add(t); } list.addAll(i, l2); reorder(i+n); for (Token t : l2) addToIdx(t); return true; } public String remove(int i) { ++modCount; Token t = list.get(i); removeFromIdx(t); list.remove(i); reorder(i); return t.s; } void reorder(int fromIdx) { int n = size(); for (int i = fromIdx; i < n; i++) list.get(i).idx = i; } void removeFromIdx(Token t) { TreeSet idx = index.get(t.s); idx.remove(t); if (idx.isEmpty()) index.remove(t.s); } void addToIdx(Token t) { TreeSet idx = index.get(t.s); if (idx == null) index.put(t.s, idx = new TreeSet()); idx.add(t); } @Override public int indexOf(Object s) { TreeSet l = index.get(s); return l == null ? -1 : first(l).idx; } @Override public int lastIndexOf(Object s) { TreeSet l = index.get(s); return l == null ? -1 : last(l).idx; } @Override public boolean contains(Object s) { return index.containsKey(s); } public void clear() { ++modCount; index.clear(); list.clear(); } protected void removeRange(int fromIndex, int toIndex) { if (fromIndex == toIndex) return; ++modCount; for (int i = fromIndex; i < toIndex; i++) removeFromIdx(list.get(i)); list.subList(fromIndex, toIndex).clear(); reorder(fromIndex); } public int[] indicesOf(String o) { TreeSet idx = index.get(o); if (idx == null) return emptyIntArray(); int[] a = new int[idx.size()]; int i = 0; for (Token t : idx) a[i++] = t.idx; return a; } public TreeSet indicesOf_treeSetOfHasIndex(String o) { return (TreeSet) index.get(o); } } static class Pair implements Comparable> { final public Pair setA(A a){ return a(a); } public Pair a(A a) { this.a = a; return this; } final public A getA(){ return a(); } public A a() { return a; } A a; final public Pair setB(B b){ return b(b); } public Pair b(B b) { this.b = b; return this; } final public B getB(){ return b(); } public B b() { return b; } B b; Pair() {} Pair(A a, B b) { this.b = b; this.a = a;} public int hashCode() { return hashCodeFor(a) + 2*hashCodeFor(b); } public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Pair)) return false; Pair t = (Pair) o; return eq(a, t.a) && eq(b, t.b); } public String toString() { return "<" + a + ", " + b + ">"; } public int compareTo(Pair p) { if (p == null) return 1; int i = ((Comparable) a).compareTo(p.a); if (i != 0) return i; return ((Comparable) b).compareTo(p.b); } } static class T3 { A a; B b; C c; T3() {} T3(A a, B b, C c) { this.c = c; this.b = b; this.a = a;} T3(T3 t) { a = t.a; b = t.b; c = t.c; } public int hashCode() { return _hashCode(a) + 2*_hashCode(b) - 4*_hashCode(c); } public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof T3)) return false; T3 t = (T3) o; return eq(a, t.a) && eq(b, t.b) && eq(c, t.c); } public String toString() { return "(" + quoteBorderless(a) + ", " + quoteBorderless(b) + ", " + quoteBorderless(c) + ")"; } } static class CompilerBot { static boolean verbose = false; static File compileSnippet(String snippetID) { return compileSnippet(snippetID, ""); } static Pair compileSnippet2(String snippetID) { return compileSnippet2(snippetID, ""); } // returns jar path static File compileSnippet(String snippetID, String javaTarget) { return compileSnippet2(snippetID, javaTarget).a; } // returns jar path, Java source static Pair compileSnippet2(String snippetID, String javaTarget) { String transpiledSrc = getServerTranspiled2(snippetID); if (transpiledSrc == null) throw fail("Snippet not found or not public: " + snippetID); int i = transpiledSrc.indexOf('\n'); String libs = transpiledSrc.substring(0, Math.max(0, i)); if (verbose) print("Compiling snippet: " + snippetID + ". Libs: " + libs); transpiledSrc = transpiledSrc.substring(i+1); return pair(compile(transpiledSrc, libs, javaTarget, snippetID), transpiledSrc); } static File compile(String src) { return compile(src, ""); } static File compile(String src, String libs) { return compile(src, libs, null); } static File compile(String src, String dehlibs, String javaTarget) { return compile(src, dehlibs, javaTarget, null); } static File compile(String src, String dehlibs, String javaTarget, String progID) { if (verbose) print("Compiling " + l(src) + " chars"); // Note: This is different from the calculation in x30 // (might lead to programs being compiled twice) String md5 = md5(dehlibs + "\n" + src + "\n" + fsIOpt(progID)); File jar = getJarFile(md5); if (jar == null || jar.length() <= 22) { // have to compile //print("Have to compile: " + progID + " / " + md5); List tok = javaTok(src); List mainClass = findMainClass(tok); boolean canRename = mainClass != null && useDummyMainClasses() && isSnippetID(progID) && !tok_classHasModifier(mainClass, "public"); if (verbose) print("useRenaming: " + useDummyMainClasses() + ", canRename: " + canRename + ", progID: " + progID); String mainClassName = joinNemptiesWithDot(tok_packageName(tok), or(getClassDeclarationName(mainClass), "main")); AutoCloseable __1 = tempSetTL(javaCompileToJar_addMoreFiles, dir -> { if (!eq(mainClassName, "main")) saveTextFile(newFile(dir, "main-class"), mainClassName); saveTextFile(newFile(dir, manifestPathInJar()), manifestTextForMainClass(mainClassName)); }); try { javaCompileToJar_optionalRename(src, dehlibs, jar, canRename ? progID : null, progID); } finally { _close(__1); }} else { if (verbose) print("Getting classes from cache (" + jar.getAbsolutePath() + ", " + jar.length() + " bytes)"); touchFile(jar); // so we can find the unused ones easier } return jar; } // look in non-virtual JavaX-Caches first (important for packaged programs) // Edit: Huh? This is strange. static File getJarFile(String md5) { assertTrue(isMD5(md5)); String fileName = md5 + ".jar"; File f = newFile(destDir(), fileName); return fileExists(f) ? f : userDir(appendSlash(compilerBotDestDirSubName()) + fileName); } /*swappable*/ static File destDir() { return compilerBotDestDir(); } } static interface IResourceHolder { A add(A a); Collection takeAll(); } static class EvalJavaPrep { List global = new ArrayList(); List outer = new ArrayList(); } // progID is just for information static class JavaXClassLoader extends URLClassLoader { String progID; Set files = syncLinkedHashSet(); Set libraryIDs = syncLinkedHashSet(); Set triedToLoad = synchroSet(); Set loadedClasses = synchroSet(); boolean retired = false; Object retiredMarker; IF1 findClass_extension; String mainClassName; boolean verbose = false; JavaXClassLoader(String progID, List files) { this(progID, files, getSystemClassLoader()); } JavaXClassLoader(String progID, List files, ClassLoader parent) { // sadly can't see this constructor //super(progID, new URL[0], parent, vm_globalACC()); super(new URL[0], parent); this.progID = progID; for (File f : unnullForIteration(files)) addFile(f); // TODO: how to get around this fixACCInClassLoader(this); } Class super_findClass(String name) throws ClassNotFoundException { return super.findClass(name); } protected Class findClass(String name) throws ClassNotFoundException { if (verbose) System.out.println(this + " findClass: " + name); if (findClass_extension != null) { Class c = findClass_extension.get(name); if (verbose) System.out.println("extension returned: " + c); if (c != null) return c; } boolean triedBefore = !triedToLoad.add(name); try { Class c = super.findClass(name); if (verbose) System.out.println("super.findClass returned: " + c); loadedClasses.add(c); if (eq(name, mainClassName())) callOpt(javax(), "registerAMainClass", c); return c; } catch (ClassNotFoundException e) { if (verbose) System.out.println(getStackTrace(e)); throw new ClassNotFoundException("Class " + name + " not found in " + joinWithComma(map(__71 -> f2s(__71), files)) + " (progID=" + progID + ")" + (triedBefore ? ", tried to load before" : ""), e); } } public String toString() { return shortClassName(this) + "[" + systemHashCodeHex(this) + "] - " + progID; } String mainClassName() { if (mainClassName == null) { mainClassName = "main"; try { mainClassName = or2(trim(loadTextFileResource(this, "main-class")), mainClassName); } catch (Throwable __e) { pcallFail(__e); } } return mainClassName; } boolean addFile(File f, String libraryID) { if (nempty(libraryID)) if (!libraryIDs.add(libraryID)) return false; return addFile(f); } boolean addFile(File f) { try { if (!files.add(f)) return false; addURL(f.toURI().toURL()); mainClassName(); // calculate early. no good loading text files later return true; } catch (Exception __e) { throw rethrow(__e); } } Set libraryIDs() { return libraryIDs; } boolean hasLibraryID(String libraryID) { return libraryIDs.contains(libraryID); } protected transient IF1 findLibrary; protected String findLibrary(String libname) { return findLibrary != null ? findLibrary.get(libname) : findLibrary_base(libname); } final protected String findLibrary_fallback(IF1 _f, String libname) { return _f != null ? _f.get(libname) : findLibrary_base(libname); } protected String findLibrary_base(String libname) { return super.findLibrary(libname); } // make public public void addURL(URL url) { super.addURL(url); } } // it's unclear whether the end is inclusive or exclusive // (usually exclusive I guess) static class IntRange { int start, end; IntRange() {} IntRange(int start, int end) { this.end = end; this.start = start;} IntRange(IntRange r) { start = r.start; end = r.end; } public boolean equals(Object o) { return stdEq2(this, o); } public int hashCode() { return stdHash2(this); } final int length() { return end-start; } final boolean empty() { return start >= end; } final boolean isEmpty() { return start >= end; } static String _fieldOrder = "start end"; public String toString() { return "[" + start + ";" + end + "]"; } boolean contains(int i) { return i >= start && i <= end; } } static class JavaXClassLoaderWithParent extends JavaXClassLoader { ClassLoader virtualParent; JavaXClassLoaderWithParent(String progID, List files, ClassLoader virtualParent) { super(progID, files); this.virtualParent = virtualParent; } protected Class findClass(String name) throws ClassNotFoundException { if (virtualParent != null && !eq(name, "main") && !name.startsWith("main$")) { try { return virtualParent.loadClass(name); } catch (ClassNotFoundException e) {} } return super.findClass(name); } public URL findResource(String name) { if (virtualParent != null) { URL url = virtualParent.getResource(name); if (url != null) return url; } return super.findResource(name); } ClassLoader getVirtualParent() { return virtualParent; } } // elements are put to front when added (not when accessed) static class MRUCache extends LinkedHashMap { int maxSize = 10; MRUCache() {} MRUCache(int maxSize) { this.maxSize = maxSize;} protected boolean removeEldestEntry(Map.Entry eldest) { return size() > maxSize; } Object _serialize() { return ll(maxSize, cloneLinkedHashMap(this)); } static MRUCache _deserialize(List l) { MRUCache m = new MRUCache(); m.maxSize = (int) first(l); m.putAll((LinkedHashMap) second(l)); return m; } } static class JavaXClassLoaderWithParent2 extends JavaXClassLoader { ClassLoader virtualParent; List classesToSkip; // classes that should be taken from parent JavaXClassLoaderWithParent2(String progID, List files, ClassLoader virtualParent, List classesToSkip) { super(progID, files); this.virtualParent = virtualParent; this.classesToSkip = classesToSkip; } protected Class findClass(String name) throws ClassNotFoundException { if (shouldDelegate(name)) { Class c = virtualParent.loadClass(name); if (c != null) return c; } return super.findClass(name); } boolean shouldDelegate(String name) { for (String s : classesToSkip) if (eq(name, s) || startsWith(name, s + "$")) return true; return false; } } static class Tok_IdentifierSemicolonToReturnStatement implements IFieldsToList{ List tok; Tok_IdentifierSemicolonToReturnStatement() {} Tok_IdentifierSemicolonToReturnStatement(List tok) { this.tok = tok;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + tok + ")"; }public Object[] _fieldsToList() { return new Object[] {tok}; } Set exceptions = defaultExceptions; static Set defaultExceptions = litset("break", "continue", "return", "else", "endifdef", "endif"); Set precedingTokens = defaultPrecedingTokens; static Set defaultPrecedingTokens = litset("}", ";"); TokCondition cond = new TokCondition() { public boolean get(List tok, int nIdx) { return contains(precedingTokens, _get(tok, nIdx-1)) && !contains(exceptions, tok.get(nIdx+1)); } }; public void run() { try { for (String pre : precedingTokens) jreplace(tok, ";", "ret $1;", cond); } catch (Exception __e) { throw rethrow(__e); } } } // TODO: subclass RuntimeException and use Meta instead of DynamicObject static class PersistableThrowable extends DynamicObject { String className; String msg; String stacktrace; final public PersistableThrowable setActualThrowable(Throwable actualThrowable){ return actualThrowable(actualThrowable); } public PersistableThrowable actualThrowable(Throwable actualThrowable) { this.actualThrowable = actualThrowable; return this; } final public Throwable getActualThrowable(){ return actualThrowable(); } public Throwable actualThrowable() { return actualThrowable; } transient Throwable actualThrowable; PersistableThrowable() {} PersistableThrowable(Throwable e) { actualThrowable = e; if (e == null) className = "Crazy Null Error"; else { className = getClassName(e).replace('/', '.'); msg = e.getMessage(); stacktrace = getStackTrace_noRecord(e); } } public String toString() { return nempty(msg) ? className + ": " + msg : className; } RuntimeException asRuntimeException() { if (actualThrowable != null) return main.asRuntimeException(actualThrowable); return new Fail(this); } } static class TokenRange extends IntRange { TokenRange() {} TokenRange(int start, int end) { this.end = end; this.start = start;} } static class Tok_SettableFields extends Tok_SettableOrGettableFields { Tok_SettableFields() { super("settable"); recognizedModifiers = listPlus(recognizedModifiers, "void"); } String replacement() { boolean returnThis = !contains(modifiers, "void"); String returnType = returnThis ? "selfType" : "void"; return tok_formatDollarVars( "$fMod $returnType $var aka $setVar($type $var) { this.$var = $var; $returnStatement } gettable $modifiers $type", "fMod" , joinWithSpace(functionModifiers()) + " public", "modifiers" , joinWithSpace(listMinus(modifiers, "void")), "type", type, "var", var, "returnType", returnType, "$returnStatement" , returnThis ? "this;" : "", "setVar" , "set" + firstToUpper(var)); } } static class HasIndex implements Comparable { int idx; HasIndex() {} HasIndex(int idx) { this.idx = idx;} public int compareTo(HasIndex h) { return idx-h.idx; } final int get() { return idx; } } static class PingSourceCancelledException extends RuntimeException implements IFieldsToList{ PingSource pingSource; PingSourceCancelledException() {} PingSourceCancelledException(PingSource pingSource) { this.pingSource = pingSource;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + pingSource + ")"; }public Object[] _fieldsToList() { return new Object[] {pingSource}; } } static interface ISetter { void set(A a); } static class Tok_ArgDecl implements IFieldsToList{ List tok; String type; String name; Tok_ArgDecl() {} Tok_ArgDecl(List tok, String type, String name) { this.name = name; this.type = type; this.tok = tok;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + tok + ", " + type + ", " + name + ")"; }public Object[] _fieldsToList() { return new Object[] {tok, type, name}; } //S modifiers; } // The idea is to leave max as the actual number of cores the system // has (numberOfCores()), and in case of being fully booked, raise an // alert (customerMustWaitAlert) which can be handled by a strategy // object (different reactions are possible). // If nothing is done in such an event, clients are processed serially // (no guarantees of order), split up among the available threads. /* SYNChronisation order: 1. PooledThread 2. ThreadPool */ static class ThreadPool implements AutoCloseable { int max = numberOfCores(); List all = new ArrayList(); Set used = new HashSet(); Set free = new HashSet(); boolean verbose, retired; // our own ping surce so we can start threads & keep them running class InternalPingSource extends PingSource {} InternalPingSource internalPingSource = new InternalPingSource(); MultiSleeper sleeper = new MultiSleeper(); ThreadPool() {} ThreadPool(int max) { this.max = max;} synchronized int maxSize() { return max; } synchronized int total() { return l(used)+l(free); } transient Set onCustomerMustWaitAlert; public ThreadPool onCustomerMustWaitAlert(Runnable r) { onCustomerMustWaitAlert = createOrAddToSyncLinkedHashSet(onCustomerMustWaitAlert, r); return this; } public ThreadPool removeCustomerMustWaitAlertListener(Runnable r) { main.remove(onCustomerMustWaitAlert, r); return this; } public void customerMustWaitAlert() { if (onCustomerMustWaitAlert != null) for (var listener : onCustomerMustWaitAlert) pcallF_typed(listener); } void fireCustomerMustWaitAlert() { vmBus_send("customerMustWaitAlert", this, currentThread()); customerMustWaitAlert(); } // DOESN'T WAIT. adds action to a thread's queue if nothing is // available immediately. PooledThread acquireThreadOrQueue(Runnable action) { if (action == null) return null; PooledThread t; synchronized(this) { if (_hasFreeAfterCreating()) { t = _firstFreeThread(); markUsed(t); } else t = _anyThread(); } t.addWork(action); // will move it from free to used return t; } // run in synchronized block boolean _hasFreeAfterCreating() { checkNotRetired(); if (nempty(free)) return true; if (total() < max) { PooledThread t = newThread(); all.add(t); free.add(t); return true; } return false; } // WAITS until thread is available PooledThread acquireThreadOrWait(Runnable action) { try { if (action == null) return null; PooledThread t; while (true) { synchronized(this) { if (_hasFreeAfterCreating()) { t = _firstFreeThread(); break; } else _waitWaitWait(); } } t.addWork(action); return t; } catch (Exception __e) { throw rethrow(__e); } } PooledThread _firstFreeThread() { return first(free); } PooledThread _anyThread() { return random(used); } class PooledThread extends Thread { PooledThread(String name) { super(name); } AppendableChain q; synchronized Runnable _grabWorkOrSleep() { try { Runnable r = first(q); if (r == null) { markFree(this); if (verbose) print("Thread sleeps"); synchronized(this) { wait(); } if (verbose) print("Thread woke up"); return null; } q = popFirst(q); return r; } catch (Exception __e) { throw rethrow(__e); } } public void run() { try { pingSource_tl().set(internalPingSource); while (!retired()) { ping(); Runnable r = _grabWorkOrSleep(); if (verbose) print(this + " work: " + r); if (r != null) try { if (verbose) print(this + " running: " + r); r.run(); pingSource_tl().set(internalPingSource); if (verbose) print(this + " done"); } catch (Throwable e) { pingSource_tl().set(internalPingSource); if (verbose) print(this + " error"); printStackTrace(e); } finally { pingSource_tl().set(internalPingSource); if (verbose) print("ThreadPool finally"); } } } catch (Exception __e) { throw rethrow(__e); } } synchronized boolean isEmpty() { return empty(q); } // append to q (do later) void addWork(Runnable r) { if (verbose) print("Added work to " + this + ": " + r); synchronized(this) { q = chainPlus(q, r); notifyAll(); } } } PooledThread newThread() { PooledThread t = new PooledThread("Thread Pool Inhabitant " + n2(total()+1)); t.start(); return t; } synchronized void markFree(PooledThread t) { used.remove(t); free.add(t); notifyAll(); } synchronized void markUsed(PooledThread t) { free.remove(t); used.add(t); } synchronized public String toString() { return retired() ? "Retired ThreadPool" : "ThreadPool " + roundBracket(commaCombine( n2(used) + " used out of " + n2(total()), max <= total() ? null : "could grow to " + n2(max))); } synchronized boolean retired() { return retired; } synchronized void retire() { if (verbose) print("ThreadPool Retiring"); retired = true; for (var thread : free) syncNotifyAll(thread); // wake it up so it exits } void checkNotRetired() { if (retired()) throw fail("retired"); } // We could do a soft-close here (stop the idle threads, let running threads finish, then end those too, stop accepting new orders) // or a hard close (interrupt all threads, stop accepting new orders) synchronized public void close() { try { retire(); } catch (Exception __e) { throw rethrow(__e); } } // run in synchronized block void _waitWaitWait() { try { do { fireCustomerMustWaitAlert(); wait(); checkNotRetired(); } while (empty(free)); } catch (Exception __e) { throw rethrow(__e); } } void dO(String text, Runnable r) { if (r == null) return; new PingSource(this, text).dO(r); } ISleeper_v2 sleeper() { return sleeper; } } abstract static class Tok_SettableOrGettableFields extends Tok_FieldModifierKeyword { Tok_SettableOrGettableFields(String keyword) { super(keyword); } List functionModifiers() { return ll(); //listMinus(modifiers, "volatile", "transient", "public", "protected", "private"); } } static interface IAutoCloseableF0 extends IF0, AutoCloseable {} /* * #! * Ontopia Engine * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * !# */ // modified by Stefan Reich // Implements the Set interface more compactly than // java.util.HashSet by using a closed hashtable. // Note: equals is always called on the _stored_ object, not the one // passed as an argument to find(), contains() etc. // (In case you want to put special magic in your equals() function) static class UnsynchronizedCompactHashSet extends java.util.AbstractSet { protected final static int INITIAL_SIZE = 3; public final static double LOAD_FACTOR = 0.75; protected final static Object nullObject = new Object(); protected final static Object deletedObject = new Object(); protected int elements; protected int freecells; protected A[] objects; protected int modCount; UnsynchronizedCompactHashSet() { this(INITIAL_SIZE); } UnsynchronizedCompactHashSet(int size) { // NOTE: If array size is 0, we get a // "java.lang.ArithmeticException: / by zero" in add(Object). objects = (A[]) new Object[(size==0 ? 1 : size)]; elements = 0; freecells = objects.length; modCount = 0; } UnsynchronizedCompactHashSet(Collection c) { this(c.size()); addAll(c); } @Override public Iterator iterator() { return new CompactHashIterator(); } @Override public int size() { return elements; } @Override public boolean isEmpty() { return elements == 0; } @Override public boolean contains(Object o) { return find(o) != null; } A find(Object o) { if (o == null) o = nullObject; int hash = o.hashCode(); int index = (hash & 0x7FFFFFFF) % objects.length; int offset = 1; // search for the object (continue while !null and !this object) while(objects[index] != null && !(objects[index].hashCode() == hash && objects[index].equals(o))) { index = ((index + offset) & 0x7FFFFFFF) % objects.length; offset = offset*2 + 1; if (offset == -1) offset = 2; } return objects[index]; } boolean removeIfSame(Object o) { A value = find(o); if (value == o) { remove(value); return true; } return false; } @Override public boolean add(Object o) { if (o == null) o = nullObject; int hash = o.hashCode(); int index = (hash & 0x7FFFFFFF) % objects.length; int offset = 1; int deletedix = -1; // search for the object (continue while !null and !this object) while(objects[index] != null && !(objects[index].hashCode() == hash && objects[index].equals(o))) { // if there's a deleted object here we can put this object here, // provided it's not in here somewhere else already if (objects[index] == deletedObject) deletedix = index; index = ((index + offset) & 0x7FFFFFFF) % objects.length; offset = offset*2 + 1; if (offset == -1) offset = 2; } if (objects[index] == null) { // wasn't present already if (deletedix != -1) // reusing a deleted cell index = deletedix; else freecells--; modCount++; elements++; // here we face a problem regarding generics: // add(A o) is not possible because of the null Object. We cant do 'new A()' or '(A) new Object()' // so adding an empty object is a problem here // If (! o instanceof A) : This will cause a class cast exception // If (o instanceof A) : This will work fine objects[index] = (A) o; // do we need to rehash? if (1 - (freecells / (double) objects.length) > LOAD_FACTOR) rehash(); return true; } else // was there already return false; } @Override public boolean remove(Object o) { if (o == null) o = nullObject; int hash = o.hashCode(); int index = (hash & 0x7FFFFFFF) % objects.length; int offset = 1; // search for the object (continue while !null and !this object) while(objects[index] != null && !(objects[index].hashCode() == hash && objects[index].equals(o))) { index = ((index + offset) & 0x7FFFFFFF) % objects.length; offset = offset*2 + 1; if (offset == -1) offset = 2; } // we found the right position, now do the removal if (objects[index] != null) { // we found the object // same problem here as with add objects[index] = (A) deletedObject; modCount++; elements--; return true; } else // we did not find the object return false; } @Override public void clear() { elements = 0; for (int ix = 0; ix < objects.length; ix++) objects[ix] = null; freecells = objects.length; modCount++; } @Override public Object[] toArray() { Object[] result = new Object[elements]; Object[] objects = this.objects; int pos = 0; for (int i = 0; i < objects.length; i++) if (objects[i] != null && objects[i] != deletedObject) { if (objects[i] == nullObject) result[pos++] = null; else result[pos++] = objects[i]; } // unchecked because it should only contain A return result; } // not sure if this needs to have generics @Override public T[] toArray(T[] a) { int size = elements; if (a.length < size) a = (T[])java.lang.reflect.Array.newInstance( a.getClass().getComponentType(), size); A[] objects = this.objects; int pos = 0; for (int i = 0; i < objects.length; i++) if (objects[i] != null && objects[i] != deletedObject) { if (objects[i] == nullObject) a[pos++] = null; else a[pos++] = (T) objects[i]; } return a; } protected void rehash() { int garbagecells = objects.length - (elements + freecells); if (garbagecells / (double) objects.length > 0.05) // rehash with same size rehash(objects.length); else // rehash with increased capacity rehash(objects.length*2 + 1); } protected void rehash(int newCapacity) { int oldCapacity = objects.length; @SuppressWarnings("unchecked") A[] newObjects = (A[]) new Object[newCapacity]; for (int ix = 0; ix < oldCapacity; ix++) { Object o = objects[ix]; if (o == null || o == deletedObject) continue; int hash = o.hashCode(); int index = (hash & 0x7FFFFFFF) % newCapacity; int offset = 1; // search for the object while(newObjects[index] != null) { // no need to test for duplicates index = ((index + offset) & 0x7FFFFFFF) % newCapacity; offset = offset*2 + 1; if (offset == -1) offset = 2; } newObjects[index] = (A) o; } objects = newObjects; freecells = objects.length - elements; } private class CompactHashIterator implements Iterator { private int index; private int lastReturned = -1; private int expectedModCount; @SuppressWarnings("empty-statement") public CompactHashIterator() { for (index = 0; index < objects.length && (objects[index] == null || objects[index] == deletedObject); index++) ; expectedModCount = modCount; } @Override public boolean hasNext() { return index < objects.length; } @SuppressWarnings("empty-statement") @Override public T next() { /*if (modCount != expectedModCount) throw new ConcurrentModificationException();*/ int length = objects.length; if (index >= length) { lastReturned = -2; throw new NoSuchElementException(); } lastReturned = index; for (index += 1; index < length && (objects[index] == null || objects[index] == deletedObject); index++) ; if (objects[lastReturned] == nullObject) return null; else return (T) objects[lastReturned]; } @Override public void remove() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (lastReturned == -1 || lastReturned == -2) throw new IllegalStateException(); // delete object if (objects[lastReturned] != null && objects[lastReturned] != deletedObject) { objects[lastReturned] = (A) deletedObject; elements--; modCount++; expectedModCount = modCount; // this is expected; we made the change } } } int capacity() { return objects.length; } // returns true if there was a shrink boolean shrinkToFactor(double factor) { if (factor > LOAD_FACTOR) throw fail("Shrink factor must be equal to or smaller than load factor: " + factor + " / " + LOAD_FACTOR); int newCapacity = max(INITIAL_SIZE, iround(size()/factor)); if (newCapacity >= capacity()) return false; rehash(newCapacity); return true; } } static interface IFieldsToList { Object[] _fieldsToList(); } interface ISleeper_v2 { default Sleeping doLater(long targetTime, Runnable r) { return doLater(sysTimeToTimestamp(targetTime), r); } Sleeping doLater(Timestamp targetTime, Runnable r); public default Sleeping doAfter(double seconds, Runnable r) { return doLater(tsNow().plusSeconds(seconds), r); } } interface IMultiMap { public Set keySet(); public Collection get(A a); public int size(); public int keyCount(); } interface IDoublePt { public double x_double(); public double y_double(); } static interface ISubList { public List rootList(); public List parentList(); public int subListOffset(); } static interface WidthAndHeight { default int w(){ return getWidth(); } default int width(){ return getWidth(); } int getWidth(); default int h(){ return getHeight(); } default int height(){ return getHeight(); } int getHeight(); public default Rect bounds() { return rect(0, 0, getWidth(), getHeight()); } default int area() { return toInt(areaAsLong()); } default long areaAsLong() { return longMul(w(), h()); } } abstract static class Sleeping implements AutoCloseable , IFieldsToList{ Timestamp targetTime; Runnable action; Sleeping() {} Sleeping(Timestamp targetTime, Runnable action) { this.action = action; this.targetTime = targetTime;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + targetTime + ", " + action + ")"; }public Object[] _fieldsToList() { return new Object[] {targetTime, action}; } long remainingMS() { return targetTime.minus(tsNow()); } } // AppendableChain has one "smart" head element (with size counter // and pointer to the chain's last element), all the other nodes are // maximally simple (MinimalChain). // This allows O(1) front insertion, front removal and back insertion // (not removal at the back though) which is fine for what I need this // for (event queues). // // Stefan Reich, Oct 21 static class AppendableChain extends MinimalChain implements Iterable, IntSize { MinimalChain last; // pointer to last element in chain (which may be us) final public int getSize(){ return size(); } public int size() { return size; } int size; // total length of chain AppendableChain() {} // only used internally AppendableChain(A element) { this.element = element; size = 1; last = this; } // intermediate constructor called by itemPlusChain() AppendableChain(A element, AppendableChain next) { this.next = next; this.element = element; if (next == null) return; MinimalChain b = new MinimalChain(); b.element = next.element; b.next = next.next; this.next = b; last = next.last; size = next.size+1; } public String toString() { return str(toList()); } // append at the end boolean add(A a) { MinimalChain newLast = new MinimalChain(a); last.next = newLast; last = newLast; ++size; return true; } // drop first element AppendableChain popFirst() { if (next == null) return null; element = next.element; if (last == next) last = this; next = next.next; --size; return this; } ArrayList toList() { ArrayList l = emptyList(size); MinimalChain c = this; while (c != null) { l.add(c.element); c = c.next; } return l; } //public Iterator iterator() { ret toList().iterator(); } class ACIt extends IterableIterator < A > { MinimalChain c = AppendableChain.this; public boolean hasNext() { return c != null; } public A next() { var a = c.element; c = c.next; return a; } } public IterableIterator iterator() { return new ACIt(); } } static class MultiSleeper implements ISleeper_v2, AutoCloseable { MultiSetMap entries = treeMultiSetMap(); RestartableCountdown countdown = new RestartableCountdown(); private void check() { var time = nextWakeUpTime(); var action = firstValue(entries); countdown.setTargetTime(time == null ? 0 : time.sysTime(), new Runnable() { public void run() { try { Set toCall; synchronized(MultiSleeper.this) { toCall = entries.get(time); entries.remove(time); check(); } pcallFAll(toCall); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "Set toCall;\r\n synchronized(MultiSleeper.this) {\r\n toCal..."; }}); } private synchronized void removeEntry(Timestamp targetTime, Runnable action) { entries.remove(targetTime, action); } // API synchronized Timestamp nextWakeUpTime() { return firstKey(entries); } public synchronized Sleeping doLater(Timestamp targetTime, Runnable r) { if (r == null || targetTime == null) return null; targetTime = max(targetTime, tsNow()); entries.put(targetTime, r); check(); return new Sleeping(targetTime, r) { public void close() { try { removeEntry(targetTime, r); } catch (Exception __e) { throw rethrow(__e); } } }; } public void close() { try { { cleanUp(countdown); countdown = null; } } catch (Exception __e) { throw rethrow(__e); } } } static class Timestamp implements Comparable , IFieldsToList{ long date; Timestamp(long date) { this.date = date;} public boolean equals(Object o) { if (!(o instanceof Timestamp)) return false; Timestamp __1 = (Timestamp) o; return date == __1.date; } public int hashCode() { int h = 2059094262; h = boostHashCombine(h, _hashCode(date)); return h; } public Object[] _fieldsToList() { return new Object[] {date}; } Timestamp() { date = now(); } Timestamp(Date date) { if (date != null) this.date = date.getTime(); } final long toLong(){ return unixDate(); } long unixDate() { return date; } long unixSeconds() { return unixDate()/1000; } public String toString() { return formatLocalDateWithSeconds(date); } // Hmm. Should Timestamp(0) be equal to null? Question, questions... public int compareTo(Timestamp t) { return t == null ? 1 : cmp(date, t.date); } Timestamp plus(Seconds seconds) { return plus(seconds == null ? null : seconds.getDouble()); } final Timestamp plusSeconds(double seconds){ return plus(seconds); } Timestamp plus(double seconds) { return new Timestamp(date+toMS(seconds)); } // returns milliseconds long minus(Timestamp ts) { return unixDate()-ts.unixDate(); } Timestamp minus(long milliseconds) { return new Timestamp(date-milliseconds); } long sysTime() { return clockTimeToSystemTime(date); } Duration minusAsDuration(Timestamp ts) { return Duration.ofMillis(minus(ts)); } } abstract static class Tok_FieldModifierKeyword implements IFieldsToList{ String keyword; Tok_FieldModifierKeyword() {} Tok_FieldModifierKeyword(String keyword) { this.keyword = keyword;} public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + keyword + ")"; }public Object[] _fieldsToList() { return new Object[] {keyword}; } final public Tok_FieldModifierKeyword setTok(List tok){ return tok(tok); } public Tok_FieldModifierKeyword tok(List tok) { this.tok = tok; return this; } final public List getTok(){ return tok(); } public List tok() { return tok; } List tok; int iEndOfLModifiers, iLModifiers, iRModifiers, iEndOfRModifiers, iType, iEndOfType; String type, var; List modifiers; Collection recognizedModifiers = javaModifiers(); void run(List tok) { this.tok = tok; int i = -1; while ((i = jfind(tok, i+1, keyword + " ")) >= 0) { iEndOfLModifiers = i; iLModifiers = leftScanModifiers(tok, iEndOfLModifiers, recognizedModifiers); iRModifiers = i+2; iEndOfRModifiers = tok_scanModifiers_idx(tok, iRModifiers); iType = iEndOfRModifiers; iEndOfType = tok_endOfType(tok, iEndOfRModifiers); type = joinSubList_cToC(tok, iType, iEndOfType); var = identifierOrQuestionMark(get(tok, iEndOfType)); modifiers = identifiersOnly(joinLists( subList(tok, iLModifiers, iEndOfLModifiers), subList(tok, iRModifiers, iEndOfRModifiers))); String replacement = replacement(); printVars("i", i, "iRModifiers", iRModifiers, "iEndOfRModifiers", iEndOfRModifiers, "iType", iType, "iEndOfType", iEndOfType, "type", type, "var", var, "replacement", replacement); tokReplace_reTok(tok, iLModifiers, iEndOfType-1, replacement); } } String boxedType() { return tok_toNonPrimitiveTypes(type); } abstract String replacement(); } static class MinimalChain implements Iterable { A element; MinimalChain next; MinimalChain() {} MinimalChain(A element) { this.element = element;} MinimalChain(A element, MinimalChain next) { this.next = next; this.element = element;} public String toString() { return str(toList()); } ArrayList toList() { ArrayList l = new ArrayList(); MinimalChain c = this; while (c != null) { l.add(c.element); c = c.next; } return l; } void setElement(A a) { element = a; } void setNext(MinimalChain next) { this.next = next; } // TODO: optimize public Iterator iterator() { return toList().iterator(); } A get() { return element; } } static class RestartableCountdown implements AutoCloseable { java.util.Timer timer; long targetTime; // in sys time long /*firings,*/ totalSleepTime; // stats synchronized void setTargetTime(long targetTime, Runnable action) { if (targetTime <= 0) stop(); else if (targetTime != this.targetTime) { start(targetTime-sysNow(), action); this.targetTime = targetTime; } } // stops the countdown and restarts it synchronized void start(long delayMS, Object action) { stop(); if (delayMS <= 0) { startThread(new Runnable() { public void run() { try { callF(action); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "callF(action);"; }}); } else { totalSleepTime += delayMS; timer = doLater_daemon(delayMS, action); targetTime = sysNow()+delayMS; } } void start(double delaySeconds, Object action) { start(toMS(delaySeconds), action); } synchronized void stop() { cancelTimer(timer); timer = null; targetTime = 0; } public void close() { stop(); } } static class Seconds implements Comparable , IFieldsToList{ double seconds; Seconds() {} Seconds(double seconds) { this.seconds = seconds;} public boolean equals(Object o) { if (!(o instanceof Seconds)) return false; Seconds __1 = (Seconds) o; return seconds == __1.seconds; } public int hashCode() { int h = -660217249; h = boostHashCombine(h, _hashCode(seconds)); return h; } public Object[] _fieldsToList() { return new Object[] {seconds}; } final double get(){ return seconds(); } final double getDouble(){ return seconds(); } double seconds() { return seconds; } public String toString() { return formatDouble(seconds, 3) + " s"; } public int compareTo(Seconds s) { return cmp(seconds, s.seconds); } Seconds div(double x) { return new Seconds(get()/x); } Seconds minus(Seconds x) { return new Seconds(get()-x.get()); } } /*sinterface ISleeper extends ISleeper_v2, AutoCloseable { void doLater(long targetSysTime, Runnable r); // call only once }*/ static A getAndClear(IVar v) { A a = v.get(); v.set(null); return a; } static Set keySet(Map map) { return map == null ? new HashSet() : map.keySet(); } static Set keySet(Object map) { return keys((Map) map); } static Set keySet(MultiMap mm) { return mm.keySet(); } static int keysSize(MultiMap mm) { return lKeys(mm); } static A reverseGet(List l, int idx) { if (l == null || idx < 0) return null; int n = l(l); return idx < n ? l.get(n-1-idx) : null; } static > List allValues(Map map) { List out = new ArrayList(); for (var l : values(map)) addAll(out, l); return out; } static Map.Entry firstEntry(Map map) { return empty(map) ? null : first(map.entrySet()); } static A firstKey(Map map) { return first(keys(map)); } static A firstKey(IMultiMap map) { return map == null ? null : first(map.keySet()); } static float clamp(float x, float a, float b) { return x < a ? a : x > b ? b : x; } static double clamp(double x, double a, double b) { return x < a ? a : x > b ? b : x; } static int clamp(int x, int a, int b) { return x < a ? a : x > b ? b : x; } static long clamp(long x, long a, long b) { return x < a ? a : x > b ? b : x; } static A _print(String s, A a) { return print(s, a); } static A _print(A a) { return print(a); } static void _print() { print(); } static boolean _eq(Object a, Object b) { return eq(a, b); } static String toString(Object o) { return strOrNull(o); } static String formatDouble(double d, int digits) { String format = digits <= 0 ? "0" : "0." + rep(digits, '#'); return decimalFormatEnglish(format, d); } static String formatDouble(double d) { return str(d); } static double ratioToPercent(double x, double y) { return x*100/y; } static ListIterator listIterator(List l) { return l == null ? emptyListIterator() : l.listIterator(); } static boolean hasNext(Iterator it) { return it != null && it.hasNext(); } static void _subListRangeCheck(int fromIndex, int toIndex, int size) { subListRangeCheck(fromIndex, toIndex, size); } static int _hashCode(Object a) { return a == null ? 0 : a.hashCode(); } static String find(String pattern, String text) { Matcher matcher = Pattern.compile(pattern).matcher(text); if (matcher.find()) return matcher.group(1); return null; } static A find(Collection c, Object... data) { for (A x : c) if (checkFields(x, data)) return x; return null; } static void addAllNonNulls(Collection c, Iterable b) { if (c != null && b != null) for (A a : b) if (a != null) c.add(a); } static void addAllNonNulls(Collection c, B... b) { if (c != null && b != null) for (A a : b) if (a != null) c.add(a); } static int lengthLevel2_maps(Collection l) { int sum = 0; for (Map c : l) sum += l(c); return sum; } static String joinNemptiesWithColon(String... strings) { return joinNempties(": ", strings); } static String joinNemptiesWithColon(Collection strings) { return joinNempties(": ", strings); } static int boostHashCombine(int a, int b) { return a ^ (b + 0x9e3779b9 + (a << 6) + (a >>> 2)); // OLD (changed) 2022/3/10: ret a ^ (b + 0x9e3779b9 + (a << 6) + (a >> 2)); } static WidthAndHeight widthAndHeight(BufferedImage image) { return image == null ? null : widthAndHeight(image.getWidth(), image.getHeight()); } static WidthAndHeight widthAndHeight(int w) { return widthAndHeight(w, w); } static WidthAndHeight widthAndHeight(int w, int h) { return new WidthAndHeightFinal(w, h); } static double sqrt(double x) { return Math.sqrt(x); } static Pt ptMinus(Pt a, Pt b) { if (b == null) return a; return new Pt(a.x-b.x, a.y-b.y); } static UnsupportedOperationException unsupportedOperation() { throw new UnsupportedOperationException(); } static boolean classIsExportedTo(Class c, java.lang.Module destModule) { if (c == null || destModule == null) return false; java.lang.Module srcModule = c.getModule(); String packageName = c.getPackageName(); return srcModule.isExported(packageName, destModule); } static Set allInterfacesImplementedBy(Object o) { return allInterfacesImplementedBy(_getClass(o)); } static Set allInterfacesImplementedBy(Class c) { if (c == null) return null; HashSet set = new HashSet(); allInterfacesImplementedBy_find(c, set); return set; } static void allInterfacesImplementedBy_find(Class c, Set set) { if (c.isInterface() && !set.add(c)) return; do { for (Class intf : c.getInterfaces()) allInterfacesImplementedBy_find(intf, set); } while ((c = c.getSuperclass()) != null); } static Method findStaticMethod(Class c, String method, Object... args) { Class _c = c; while (c != null) { for (Method m : c.getDeclaredMethods()) { if (!m.getName().equals(method)) continue; if ((m.getModifiers() & Modifier.STATIC) == 0 || !findStaticMethod_checkArgs(m, args)) continue; return m; } c = c.getSuperclass(); } return null; } static boolean findStaticMethod_checkArgs(Method m, Object[] args) { Class[] types = m.getParameterTypes(); if (types.length != args.length) return false; for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) return false; return true; } static List quoteAll(String[] l) { return quoteAll(asList(l)); } static List quoteAll(Collection l) { List x = new ArrayList(); for (String s : l) x.add(quote(s)); return x; } static boolean arraysEqual(Object[] a, Object[] b) { if (a.length != b.length) return false; for (int i = 0; i < a.length; i++) if (neq(a[i], b[i])) return false; return true; } static String shortClassName_dropNumberPrefix(Object o) { return dropNumberPrefix(shortClassName(o)); } static Iterator iteratorOrNull(Iterable c) { return c == null ? null : c.iterator(); } static List sortInPlace(List l, final Object comparator) { return sortedInPlace(l, comparator); } static List sortInPlace(List l) { return sortedInPlace(l); } static Object metaGet(IMeta o, Object key) { return metaMapGet(o, key); } static Object metaGet(Object o, Object key) { return metaMapGet(o, key); } static Object metaGet(String key, IMeta o) { return metaMapGet(o, key); } static Object metaGet(String key, Object o) { return metaMapGet(o, key); } static Object metaMapGet(IMeta o, Object key) { return o == null ? null : o.metaGet(key); // We now let the object itself do it (overridable!) } static Object metaMapGet(Object o, Object key) { return metaMapGet(toIMeta(o), key); } static void metaPut(IMeta o, Object key, Object value) { metaMapPut(o, key, value); } static void metaPut(Object o, Object key, Object value) { metaMapPut(o, key, value); } static Map convertObjectMetaToMap(IMeta o) { return convertObjectMetaToMap(o, () -> makeObjectMetaMap()); } static Map convertObjectMetaToMap(IMeta o, IF0 createEmptyMap) { if (o == null) return null; // The following shortcut depends on the assumption that a meta field never reverts // to null when it was a map Object meta = o._getMeta(); if (meta instanceof Map) return ((Map) meta); // non-shortcut path (create meta) var mutex = tempMetaMutex(o); try { var actualMutex = mutex.get(); synchronized(actualMutex) { meta = o._getMeta(); if (meta instanceof Map) return ((Map) meta); Map map = createEmptyMap.get(); if (meta != null) map.put("previousMeta" , meta); o._setMeta(map); return map; } } finally { _close(mutex); }} static void syncMapPutOrRemove(Map map, A key, B value) { syncMapPut2(map, key, value); } // TODO: use actualUserHome()? // (there was a problem with onLocallyInferiorJavaX() always triggering inside #1013896) static File pathToJavaxJar() { IResourceLoader rl = vm_getResourceLoader(); if (rl != null) return rl.pathToJavaXJar(); return pathToJavaxJar_noResourceLoader(); } static File pathToJavaxJar_noResourceLoader() { try { int x = latestInstalledJavaX(); File xfile = new File(userHome(), ".javax/x" + Math.max(x, 30) + ".jar"); if (!xfile.isFile()) { print("Saving " + f2s(xfile)); String url = x30JarServerURL(); byte[] data = loadBinaryPage(url); if (data.length < 1000000) throw fail("Could not load " + url); saveBinaryFile(xfile.getPath(), data); } return xfile; } catch (Exception __e) { throw rethrow(__e); } } static Method hashMap_findKey_method; static A hashMap_findKey(HashMap map, Object key) { try { if (hashMap_findKey_method == null) hashMap_findKey_method = findMethodNamed(HashMap.class, "getNode"); Map.Entry entry = (Map.Entry) hashMap_findKey_method.invoke(map, hashMap_internalHash(key), key); // java.util.Map.Entry entry = (java.util.Map.Entry) call(hash, 'getNode, hashMap_internalHash(key), wkey); return entry == null ? null : entry.getKey(); } catch (Exception __e) { throw rethrow(__e); } } static List reverseInPlace(List l) { return reverseList(l); } static List tok_argDecls(List tok) { return map(tok_typesAndNamesOfParams(tok), p -> new Tok_ArgDecl(tok, p.a, p.b)); } static String a(String noun) { if (eq(noun, "")) return "?"; return ("aeiou".indexOf(noun.charAt(0)) >= 0 ? "an " : "a ") + noun; } static String a(String contents, Object... params) { return hfulltag("a", contents, params); } static String b(Object contents, Object... params) { return fulltag("b", contents, params); } static int hashCodeFor(Object a) { return a == null ? 0 : a.hashCode(); } static String quoteBorderless(Object o) { if (o == null) return "null"; return quoteBorderless(str(o)); } static String quoteBorderless(String s) { if (s == null) return "null"; StringBuilder out = new StringBuilder((int) (l(s)*1.5)); quoteBorderless_impl(s, out); return out.toString(); } static void quoteBorderless_impl(String s, StringBuilder out) { int l = s.length(); for (int i = 0; i < l; i++) { char c = s.charAt(i); if (c == '\\' || c == '"') out.append('\\').append(c); else if (c == '\r') out.append("\\r"); else if (c == '\n') out.append("\\n"); else out.append(c); } } static boolean getServerTranspiled2_allowLocalFallback = true, getServerTranspiled2_localFallbackVerbose = true; // to avoid checking server for transpilations too often when booting OS static Map getServerTranspiled2_tempCache; static String getServerTranspiled2(String id) { IResourceLoader rl = vm_getResourceLoader(); if (rl != null) return rl.getTranspiled(id); return getServerTranspiled2_noResourceLoader(id); } static String getServerTranspiled2_noResourceLoader(String id) { id = fsIOpt(id); String transpiled = mapGet(getServerTranspiled2_tempCache, id); if (transpiled != null) return transpiled; //if (getServerTranspiled2_tempCache != null) print("CACHE FAIL on " + id); transpiled = loadCachedTranspilation(id); String md5 = null; if (machineIsOffline() || isOfflineMode() || isLocalSnippet(id)) return transpiled; if (transpiled != null) md5 = md5(transpiled); String transpiledSrc; try { transpiledSrc = getServerTranspiled(formatSnippetID(id), md5); } catch (Throwable e) { if (!getServerTranspiled2_allowLocalFallback) rethrow(e); printExceptionShort(e); if (getServerTranspiled2_localFallbackVerbose) print("Fallback to local code"); return transpiled; } if (eq(transpiledSrc, "SAME")) { if (!isTrue(loadPage_silent.get())) printWithMS("SAME"); return mapPut_returnValue(getServerTranspiled2_tempCache, id, transpiled); } return mapPut_returnValue(getServerTranspiled2_tempCache, id, transpiledSrc); } static String fsIOpt(String s) { return formatSnippetIDOpt(s); } static boolean useDummyMainClasses() { return true; //ret eq("1", trim(loadTextFile(getProgramFile(#1008755, "use-dummy-main-classes")))); } static boolean tok_classHasModifier(List classDecl, String modifier) { if (classDecl == null) return false; int i = classDecl.indexOf("class"); return subList(classDecl, 0, i).contains(modifier); } static String joinNemptiesWithDot(Object... strings) { return joinNempties(".", strings); } static String joinNemptiesWithDot(Iterable strings) { return joinNempties(".", strings); } static String manifestPathInJar() { return "META-INF/MANIFEST.MF"; } static String manifestTextForMainClass(String mainClass) { return "Manifest-Version: 1.0\n" + "Main-Class: " + mainClass + "\n\n"; } // before you use this, add a RAM disk cleaner static boolean javaCompileToJar_useRAMDisk = false; static ThreadLocal> javaCompileToJar_localLibraries = new ThreadLocal(); static ThreadLocal> javaCompileToJar_addMoreFiles = new ThreadLocal(); static File javaCompileToJar_optionalRename(String src, File destJar, String progIDForRename) { return javaCompileToJar_optionalRename(src, "", destJar, progIDForRename); } static synchronized File javaCompileToJar_optionalRename(String src, String dehlibs, File destJar, String progIDForRename) { return javaCompileToJar_optionalRename(src, dehlibs, destJar, progIDForRename, null); } // returns path to jar static synchronized File javaCompileToJar_optionalRename(String src, String dehlibs, File destJar, String progIDForRename, String progID) { String javaTarget = null; // use default target //print("Compiling " + l(src) + " chars"); String dummyClass = "main"; if (progIDForRename != null) { dummyClass = dummyMainClassName(progIDForRename); src += "\nclass " + dummyClass + "{}"; } String md5 = md5(src); File jar = destJar; Class j = getJavaX(); if (javaTarget != null) setOpt(j, "javaTarget", javaTarget); //setOpt(j, "verbose", true); File srcDir = tempDir(); String fileName = dummyClass + ".java"; // deriver name of main Java file from source List tok = javaTok(src); String packageName = tok_packageName(tok); if (packageName != null) fileName = packageName.replace(".", "/") + "/" + tok_firstClassName(tok) + ".java"; File mainJava = new File(srcDir, fileName); //print("main java: " + mainJava.getAbsolutePath()); saveTextFile(mainJava, src); File classesDir = javaCompileToJar_useRAMDisk ? tempDirPossiblyInRAMDisk() : tempDir(); //print("Compiling to " + f2s(classesDir)); try { List libraries = cloneList(getAndClearTL(javaCompileToJar_localLibraries)); Matcher m = Pattern.compile("\\d+").matcher(dehlibs); while (m.find()) { String libID = m.group(); //print("libID=" + quote(libID)); assertTrue(isSnippetID(libID)); //print("Adding library " + libID); libraries.add(loadLibraryOrSrcLib(libID)); } libraries.add(pathToJavaxJar()); String compilerOutput; try { compilerOutput = (String) call(j, "compileJava", srcDir, libraries, classesDir); } catch (Throwable e) { compilerOutput = (String) get(getJavaX(), "javaCompilerOutput"); //fail("Compile Error. " + cleanJavaCompilerOutput(compilerOutput) + " " + e); //compilerOutput = indentx("> ", cleanJavaCompilerOutput(compilerOutput)); //throw JavaCompilerException(compilerOutput, e); if (!swic(e.getMessage(), "Java compiler returned errors.")) compilerOutput = appendWithNewLine(compilerOutput, str(e)); //printStackTrace(e); throw fail(compilerOutput, e); } compilerOutput = cleanJavaCompilerOutput("Annotation processing got disabled, since it requires a 1.6 compliant JVM"); if (nempty(compilerOutput)) { print("Compiler said: " + compilerOutput); //fail("Compile Error. " + compilerOutput); } // sanity test if (!anyFileWithExtensionInDir(classesDir, ".class")) { printWithIndent("SRC> ", src); throw fail("No classes generated (was compiling " + nChars(src) + ")"); } // add sources to .jar saveTextFile(new File(classesDir, "main.java"), src); // add information about libraries to jar if (nempty(dehlibs)) saveTextFile(new File(classesDir, "libraries"), dehlibs); // add prog id to jar saveTextFile(new File(classesDir, "progID"), progID); // save pointer to main Java source //saveTextFile(new File(classesDir, "main-src"), fileName); callF(javaCompileToJar_addMoreFiles.get(), classesDir); //print("Zipping: " + classesDir.getAbsolutePath() + " to " + jar.getAbsolutePath()); dir2zip_recurse_verbose = false; int n = dir2zip_recurse(classesDir, jar); // cache on success only //print("Files zipped: " + n); return jar; } finally { if (isInRAMDisk(classesDir)) deleteDirectory(classesDir); } } // will create the file or update its last modified timestamp static File touchFile(File file) { try { closeRandomAccessFile(newRandomAccessFile(mkdirsForFile(file), "rw")); return file; } catch (Exception __e) { throw rethrow(__e); } } static String appendSlash(String s) { return addSlash(s); } static String compilerBotDestDirSubName() { return "JavaX-Caches/Compilations"; } static File compilerBotDestDir() { return actualUserDir(compilerBotDestDirSubName()); } static File compilerBotDestDir(String sub) { return newFile(compilerBotDestDir(), sub); } // I believe this was meant to mitigate memory leaks. // Disabled now because JDK 17 doesn't allow it anyways. static void fixACCInClassLoader(Object o) { /*pcall { AccessControlContext acc = vm_globalACC(); if (acc != null) replaceACCInClassLoader(o, acc); }*/ } static HashMap findClass_cache = new HashMap(); // currently finds only inner classes of class "main" // returns null on not found // this is the simple version that is not case-tolerant static Class findClass(String name) { synchronized(findClass_cache) { if (findClass_cache.containsKey(name)) return findClass_cache.get(name); if (!isJavaIdentifier(name)) return null; Class c; try { c = Class.forName("main$" + name); } catch (ClassNotFoundException e) { c = null; } findClass_cache.put(name, c); return c; } } static String systemHashCodeHex(Object o) { return intToHex(identityHashCode(o)); } static String loadTextFileResource(ClassLoader cl, String name) { return inputStreamToString(cl.getResourceAsStream(name)); } static boolean stdEq2(Object a, Object b) { if (a == null) return b == null; if (b == null) return false; if (a.getClass() != b.getClass()) return false; for (String field : allFields(a)) if (neq(getOpt(a, field), getOpt(b, field))) return false; return true; } static int stdHash2(Object a) { if (a == null) return 0; return stdHash(a, toStringArray(allFields(a))); } static ClassLoader getVirtualParent(ClassLoader cl) { return (ClassLoader) rcallOpt("getVirtualParent", cl); } static List listPlus(Collection l, A... more) { return concatLists(l, asList(more)); } // runnable = Runnable or String (method name) static Thread newThread(Object runnable) { return new BetterThread(_topLevelErrorHandling(toRunnable(runnable))); } static Thread newThread(Object runnable, String name) { if (name == null) name = defaultThreadName(); return new BetterThread(_topLevelErrorHandling(toRunnable(runnable)), name); } static Thread newThread(String name, Object runnable) { return newThread(runnable, name); } static int random(int n) { return random(n, defaultRandomGenerator()); } static int random(int n, Random r) { return random(r, n); } static long random(long n) { return random(n, defaultRandomGenerator()); } static long random(long n, Random r) { return random(r, n); } static int random(Random r, int n) { return n <= 0 ? 0 : getRandomizer(r).nextInt(n); } static long random(Random r, long n) { return n <= 0 ? 0 : getRandomizer(r).nextLong(n); } static double random(double max) { return random()*max; } static double random() { return defaultRandomGenerator().nextInt(100001)/100000.0; } static double random(double min, double max) { return min+random()*(max-min); } // min <= value < max static int random(int min, int max) { return min+random(max-min); } // min <= value < max static long random(long min, long max) { return min+random(max-min); } static int random(int min, int max, Random r) { return random(r, min, max); } static int random(Random r, int min, int max) { return min+random(r, max-min); } static A random(List l) { return oneOf(l); } static A random(Collection c) { if (c instanceof List) return random((List) c); int i = random(l(c)); return collectionGet(c, i); } static int random(IntRange r) { return random(r.start, r.end); } static Pair random(Map map) { return entryToPair(random(entries(map))); } static A popFirst(List l) { if (empty(l)) return null; A a = first(l); l.remove(0); return a; } static A popFirst(Collection l) { if (empty(l)) return null; A a = first(l); l.remove(a); return a; } static Pair popFirst(Map map) { if (map == null) return null; var it = map.entrySet().iterator(); if (!it.hasNext()) return null; var p = mapEntryToPair(it.next()); it.remove(); return p; } static List popFirst(int n, List l) { List part = cloneSubList(l, 0, n); removeSubList(l, 0, n); return part; } static AppendableChain popFirst(AppendableChain a) { return a == null ? null : a.popFirst(); } // Yes the nomenclature is a bit illogical static Chain chainPlus(Chain chain, A a) { return new Chain(a, chain); } static Chain chainPlus(Chain chain, A... l) { for (A a : unnullForIteration(l)) chain = chainPlus(chain, a); return chain; } static ReverseChain chainPlus(ReverseChain chain, A a) { return new ReverseChain(chain, a); } static ReverseChain chainPlus(ReverseChain chain, A... l) { for (A a : unnullForIteration(l)) chain = chainPlus(chain, a); return chain; } static AppendableChain chainPlus(AppendableChain chain, A a) { if (chain == null) return new AppendableChain(a); chain.add(a); return chain; } static AppendableChain chainPlus(AppendableChain chain, A... l) { for (A a : unnullForIteration(l)) chain = chainPlus(chain, a); return chain; } static void syncNotifyAll(Object o) { if (o != null) synchronized(o) { o.notifyAll(); } } static java.util.Timer doLater(long delay, final Object r) { ping(); final java.util.Timer timer = new java.util.Timer(); timer.schedule(timerTask(r, timer), delay); return vmBus_timerStarted(timer); } static java.util.Timer doLater(double delaySeconds, final Object r) { return doLater(toMS(delaySeconds), r); } static Timestamp sysTimeToTimestamp(long now) { return now == 0 ? null : new Timestamp(now - clockToSysTimeDiff()); } static Timestamp tsNow() { return new Timestamp(); } static int getWidth(Component c) { return c == null ? 0 : (int) swingCall(c, "getWidth"); } static int getHeight(Component c) { return c == null ? 0 : (int) swingCall(c, "getHeight"); } static Rect rect(int x, int y, int w, int h) { return new Rect(x, y, w, h); } static Rect rect(Pt p, int w, int h) { return new Rect(p.x, p.y, w, h); } static Rect rect(int w, int h) { return new Rect(0, 0, w, h); } static long longMul(long a, long b) { return a*b; } static MultiSetMap treeMultiSetMap() { return new MultiSetMap(true); } static MultiSetMap treeMultiSetMap(Comparator comparator) { return new MultiSetMap(new TreeMap>(comparator)); } static B firstValue(Map map) { return first(values(map)); } static B firstValue(MultiSetMap map) { return map == null ? null : first(firstValue(map.data)); } static B firstValue(MultiMap map) { return map == null ? null : first(firstValue(map.data)); } static String formatLocalDateWithSeconds(long time) { return localDateWithSeconds(time); } static String formatLocalDateWithSeconds() { return localDateWithSeconds(); } static BigInteger plus(BigInteger a, BigInteger b) { return a.add(b); } static BigInteger plus(BigInteger a, long b) { return a.add(bigint(b)); } static long plus(long a, long b) { return a+b; } static int plus(int a, int b) { return a+b; } static float plus(float a, float b) { return a+b; } static double plus(double a, double b) { return a+b; } static long toMS(double seconds) { return (long) (seconds*1000); } static long toMS(Duration d) { return d == null ? 0 : d.toMillis(); } static long clockTimeToSystemTime(long now) { return now == 0 ? 0 : now + clockToSysTimeDiff(); } static List minus(Collection a, Object... b) { Set set = asSet(b); List l = new ArrayList(); for (Object s : unnull(a)) if (!set.contains(s)) l.add(s); return l; } static BigInteger minus(BigInteger a, BigInteger b) { return a.subtract(b); } static Complex minus(Complex c) { return c == null ? null : complex(-c.re(), -c.im()); } static int minus(int a, int b) { return a-b; } static int minus(int a) { return -a; } static double minus(double a, double b) { return a-b; } static double minus(double a) { return -a; } static long minus(long a, long b) { return a-b; } static long minus(long a) { return -a; } static List javaModifiers() { return getJavaModifiers(); } static int tok_scanModifiers_idx(List tok, int i) { return tok_skipModifiers(tok, i); } static String identifierOrQuestionMark(String s) { return isIdentifier(s) ? s : "?"; } static List joinLists(Iterable... lists) { return concatLists(lists); } static List joinLists(Collection> lists) { return concatLists(lists); } static Thread startThread(Object runnable) { return startThread(defaultThreadName(), runnable); } static Thread startThread(String name, Runnable runnable) { runnable = wrapAsActivity(runnable); return startThread(newThread(runnable, name)); } static Thread startThread(String name, Object runnable) { runnable = wrapAsActivity(runnable); return startThread(newThread(toRunnable(runnable), name)); } static Thread startThread(Thread t) { _registerThread(t); t.start(); return t; } static java.util.Timer doLater_daemon(long delay, final Object r) { final java.util.Timer timer = new java.util.Timer(true); timer.schedule(timerTask(r, timer), delay); return timer; } static java.util.Timer doLater_daemon(double delaySeconds, final Object r) { return doLater_daemon(toMS(delaySeconds), r); } static void cancelTimer(javax.swing.Timer timer) { if (timer != null) timer.stop(); } static void cancelTimer(java.util.Timer timer) { if (timer != null) timer.cancel(); } static void cancelTimer(Object o) { if (o instanceof java.util.Timer) cancelTimer((java.util.Timer) o); else if (o instanceof javax.swing.Timer) cancelTimer((javax.swing.Timer) o); else if (o instanceof AutoCloseable) { try { ((AutoCloseable) o).close(); } catch (Throwable __e) { pcallFail(__e); }} } static int seconds() { return seconds(java.util.Calendar.getInstance()); } static int seconds(java.util.Calendar c) { return c.get(java.util.Calendar.SECOND); } static int lKeys(MultiMap mm) { return mm == null ? 0 : mm.keysSize(); } static String decimalFormatEnglish(String format, double d) { return decimalFormatEnglish(format).format(d); } static java.text.DecimalFormat decimalFormatEnglish(String format) { return new java.text.DecimalFormat(format, new java.text.DecimalFormatSymbols(Locale.ENGLISH)); } static ListIterator emptyListIterator() { return Collections.emptyListIterator(); } static void subListRangeCheck(int fromIndex, int toIndex, int size) { if (fromIndex < 0) throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); if (toIndex > size) throw new IndexOutOfBoundsException("toIndex = " + toIndex); if (fromIndex > toIndex) throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); } static boolean checkFields(Object x, Object... data) { for (int i = 0; i < l(data); i += 2) if (neq(getOpt(x, (String) data[i]), data[i+1])) return false; return true; } static String dropNumberPrefix(String s) { return dropFirst(s, indexOfNonDigit(s)); } static List sortedInPlace(List l, final Object comparator) { sort(l, makeComparator(comparator)); return l; } static List sortedInPlace(List l) { sort(l); return l; } static IMeta toIMeta(Object o) { return initIMeta(o); } static Map makeObjectMetaMap() { //ret synchroLinkedHashMap(); return new CompactHashMap(); } static IAutoCloseableF0 tempMetaMutex(IMeta o) { return o == null ? null : o._tempMetaMutex(); } static void syncMapPut2(Map map, A key, B value) { if (map != null && key != null) synchronized(collectionMutex(map)) { if (value != null) map.put(key, value); else map.remove(key); } } static int latestInstalledJavaX() { File[] files = new File(userHome(), ".javax").listFiles(); int v = 0; if (files != null) for (File f : files) { Matcher m = regexpMatcher("x(\\d\\d\\d?)\\.jar", f.getName()); if (m.matches()) v = Math.max(v, Integer.parseInt(m.group(1))); } return v; } static String x30JarServerURL() { return "https://botcompany.de:9898/x30.jar"; } static int hashMap_internalHash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } static List reverseList(List l) { Collections.reverse(l); return l; } static String hfulltag(String tag) { return hfulltag(tag, ""); } static String hfulltag(String tag, Object contents, Object... params) { return hopeningTag(tag, params) + str(contents) + ""; } static String fulltag(String tag) { return hfulltag(tag); } static String fulltag(String tag, Object contents, Object... params) { return hfulltag(tag, contents, params); } static String loadCachedTranspilation(String id) { try { return loadTextFilePossiblyGZipped(getCachedTranspilationFile(id)); } catch (Throwable __e) { return null; } } static boolean machineIsOffline() { return isFalse(callF(vmGeneralMap_get("areWeOnline"))); } static boolean isOfflineMode() { return eq("1", trim(loadProgramTextFile("#1005806", "offline-mode"))); } static boolean isLocalSnippet(String snippetID) { return isLocalSnippetID(snippetID); } static boolean isLocalSnippet(long snippetID) { return isLocalSnippetID(snippetID); } static String getServerTranspiled(String snippetID) { return getServerTranspiled(snippetID, null); } static boolean getServerTranspiled_printStackTrace = false; // returns "SAME" if md5 matches static String getServerTranspiled(String snippetID, String expectedMD5) { try { if (getServerTranspiled_printStackTrace) printStackTrace(); long id = parseSnippetID(snippetID); /*S t = getTranspilationFromBossBot(id); if (t != null) return t;*/ String text = loadPage_utf8(tb_mainServer() + "/tb-int/get-transpiled.php?raw=1&withlibs=1&id=" + id + "&utf8=1" + (l(expectedMD5) > 1 ? "&md5=" + urlencode(expectedMD5) : "") + standardCredentials()); if (nempty(text) && neq(text, "SAME")) saveTranspiledCode(snippetID, text); return text; } catch (Exception __e) { throw rethrow(__e); } } static void printExceptionShort(Throwable e) { printExceptionShort("", e); } static void printExceptionShort(String prefix, Throwable e) { print(prefix, exceptionToStringShort(e)); } static void printWithMS(A a) { printWithMS("", a); } static void printWithMS(String prefix, A a) { printWithMSTime(prefix, a); } static B mapPut_returnValue(Map map, A key, B value) { mapPut(map, key, value); return value; } static String dummyMainClassName(String progID) { return "m" + psI(progID); } static File tempDir() { return makeTempDir(); } static String tok_firstClassName(List tok) { int i = jfind(tok, "class "); return i < 0 ? null : tok.get(i+2); } static File tempDirPossiblyInRAMDisk() { File f = linux_fileInRamDisk(aGlobalID()); if (f != null) { f.mkdirs(); return f; } return makeTempDir(); } static A getAndClearTL(ThreadLocal tl) { return getAndClearThreadLocal(tl); } static boolean loadLibraryOrSrcLib_srcLibsEnabled = true; // to avoid checking src libs too often when booting OS static ThreadLocal> loadLibraryOrSrcLib_tempCache = new ThreadLocal(); static ThreadLocal> loadLibraryOrSrcLib_compiler = new ThreadLocal(); static File loadLibraryOrSrcLib(String snippetID) { return loadLibraryOrSrcLib(snippetID, loadLibraryOrSrcLib_compiler.get()); } static File loadLibraryOrSrcLib(String snippetID, IF1 compiler) { try { vmBus_send("loadLibraryOrSrcLib", snippetID); long id = parseSnippetID(snippetID); if (loadLibraryOrSrcLib_tempCache.get() != null) { File f = loadLibraryOrSrcLib_tempCache.get().get(id); if (f != null) { print(snippetID + " from tempCache: " + f); return f; } } boolean srcLib = loadLibraryOrSrcLib_srcLibsEnabled && isMarkedAsSrcLib(snippetID); if (srcLib) { print(snippetID + " marked as src lib, compiling"); File f; if (compiler != null) f = compiler.get(snippetID); else f = pairA(hotwire_compile(snippetID)); print("Src lib: " + f); mapPut(loadLibraryOrSrcLib_tempCache.get(), id, f); return f; } File f = DiskSnippetCache_getLibrary(id); if (fileSize(f) != 0) return f/* with print(snippetID + " from disk cache: " + f)*/; try { print("Trying " + snippetID + " as binary library"); return loadDataSnippetToFile(snippetID); } catch (Throwable e) { if (loadLibraryOrSrcLib_srcLibsEnabled) { print("Trying " + snippetID + " as src lib"); if (nempty(loadSnippet(snippetID))) { print("Is src lib."); markAsSrcLib(snippetID); return pairA(hotwire_compile(snippetID)); } } throw rethrow(e); } } catch (Exception __e) { throw rethrow(__e); } } static String appendWithNewLine(String a, String b) { if (empty(b)) return a; if (empty(a)) return b; return addSuffix(a, "\n") + b; } static String cleanJavaCompilerOutput(String s) { return dropPrefixTrim("Annotation processing got disabled, since it requires a 1.6 compliant JVM", s); } static boolean anyFileWithExtensionInDir(File dir, String ext) { return nempty(filesWithExtension(ext, findAllFiles_noDirs(dir))); } static String nChars(long n) { return n2(n, "char"); } static String nChars(String s) { return nChars(l(s)); } static boolean dir2zip_recurse_verbose = false; static int dir2zip_recurse(File inDir, File zip) { return dir2zip_recurse(inDir, zip, ""); } // TODO: the zero files case? static int dir2zip_recurse(File inDir, File zip, String outPrefix) { try { mkdirsForFile(zip); FileOutputStream fout = newFileOutputStream(zip); ZipOutputStream outZip = new ZipOutputStream(fout); try { return dir2zip_recurse(inDir, outZip, outPrefix, 0); } finally { outZip.close(); } } catch (Exception __e) { throw rethrow(__e); } } static int dir2zip_recurse(File inDir, ZipOutputStream outZip) { return dir2zip_recurse(inDir, outZip, "", 0); } static int dir2zip_recurse(File inDir, ZipOutputStream outZip, String outPrefix, int level) { try { if (++level >= 20) throw fail("woot? 20 levels in zip?"); List files = new ArrayList(); for (File f : listFiles(inDir)) files.add(f); int n = 0; sortFilesByName(files); for (File f : files) { if (f.isDirectory()) { if (dir2zip_recurse_verbose) print("dir2zip_recurse: Scanning " + f.getAbsolutePath()); n += dir2zip_recurse(f, outZip, outPrefix + f.getName() + "/", level); } else { if (dir2zip_recurse_verbose) print("Copying " + f.getName()); outZip.putNextEntry(new ZipEntry(outPrefix + f.getName())); InputStream fin; try { fin = new FileInputStream(f); } catch (Throwable e) { print(e); continue; } AutoCloseable __1 = fin; try { copyStream(fin, outZip); ++n; } finally { _close(__1); }} } return n; } catch (Exception __e) { throw rethrow(__e); } } static boolean isInRAMDisk(File f) { return startsWithOneOf(f2s(f), "/dev/shm/", "/run/shm/"); } static void deleteDirectory(File dir) { deleteDirectory(dir, false, false); } static void deleteDirectory(File dir, boolean verbose, boolean testRun) { deleteAllFilesInDirectory(dir, verbose, testRun); if (verbose) print((testRun ? "Would delete " : "Deleting ") + dir.getAbsolutePath()); if (!testRun) dir.delete(); } static void closeRandomAccessFile(RandomAccessFile f) { if (f != null) try { f.close(); callJavaX("dropIO", f); } catch (Throwable e) { printStackTrace(e); } } static RandomAccessFile newRandomAccessFile(File path, String mode) { try { boolean forWrite = mode.indexOf('w') >= 0; if (forWrite) mkdirsForFile(path); RandomAccessFile f = new RandomAccessFile(path, mode); callJavaX("registerIO", f, path, forWrite); return f; } catch (Exception __e) { throw rethrow(__e); } } static File actualUserDir() { return new File(actualUserHome()); } static File actualUserDir(String path) { return new File(actualUserHome(), path); } static String intToHex(int i) { return bytesToHex(intToBytes(i)); } static String inputStreamToString(InputStream in) { return utf8streamToString(in); } static Map> allFields_cache = weakHashMap(); static Set allFields(Object o) { if (o == null) return emptySet(); Class _c = _getClass(o); Set fields = allFields_cache.get(_c); if (fields == null) allFields_cache.put(_c, fields = asTreeSet(keys(getOpt_getFieldMap(o)))); return fields; } static int stdHash(Object a, String... fields) { if (a == null) return 0; int hash = getClassName(a).hashCode(); for (String field : fields) hash = boostHashCombine(hash, hashCode(getOpt(a, field))); return hash; } static Object rcallOpt(String method, Object o, Object... args) { return callOpt_withVarargs(o, method, args); } static Runnable _topLevelErrorHandling(Runnable r) { if (r == null) return null; // maybe we don't want this anymore. just dm_current_generic() Object info = _threadInfo(); Object mod = dm_current_generic(); Runnable r2 = r; if (info != null || mod == null) r2 = new Runnable() { public void run() { try { AutoCloseable __1 = (AutoCloseable) (rcall("enter", mod)); try { _threadInheritInfo(info); r.run(); } finally { _close(__1); }} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "temp (AutoCloseable) rcall enter(mod);\r\n _threadInheritInfo(info);\r\n ..."; }}; r2 = rPcall(r2); return r2; } static String defaultThreadName_name; static String defaultThreadName() { if (defaultThreadName_name == null) defaultThreadName_name = "A thread by " + programID(); return defaultThreadName_name; } static Random getRandomizer(Random r) { return r != null ? r : defaultRandomGenerator(); } static A oneOf(List l) { if (empty(l)) return null; int n = l.size(); return n == 1 ? first(l) : l.get(defaultRandomizer().nextInt(n)); } static char oneOf(String s) { return empty(s) ? '?' : s.charAt(random(l(s))); } static A oneOf(A... l) { return oneOf(asList(l)); } static A collectionGet(Collection c, int idx) { if (c == null || idx < 0 || idx >= l(c)) return null; if (c instanceof List) return listGet((List) c, idx); Iterator it = c.iterator(); for (int i = 0; i < idx; i++) if (it.hasNext()) it.next(); else return null; return it.hasNext() ? it.next() : null; } static Pair entryToPair(Map.Entry e) { return mapEntryToPair(e); } static Set> entries(Map map) { return _entrySet(map); } static TimerTask timerTask(final Object r, final java.util.Timer timer) { return new TimerTask() { public void run() { if (!licensed()) timer.cancel(); else pcallF(r); } }; } static A vmBus_timerStarted(A timer) { vmBus_send("timerStarted", timer, costCenter()); return timer; } static long clockToSysTimeDiff() { return sysNow()-now(); } static Object swingCall(final Object o, final String method, final Object... args) { return swing(new F0() { public Object get() { try { return call(o, method, args); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "return call(o, method, args);"; }}); } static String localDateWithSeconds(long time) { SimpleDateFormat format = simpleDateFormat_local("yyyy/MM/dd HH:mm:ss"); return format.format(time); } static String localDateWithSeconds() { return localDateWithSeconds(now()); } static BigInteger bigint(String s) { return new BigInteger(s); } static BigInteger bigint(long l) { return BigInteger.valueOf(l); } static Complex complex(double re, double im) { return new Complex(re, im); } static Complex complex(double re) { return new Complex(re, 0.0); } static Complex complex(double[] reIm) { if (empty(reIm)) return null; if (l(reIm) != 2) throw fail("Need 2 doubles to make complex number"); return complex(reIm[0], reIm[1]); } static int indexOfNonDigit(String s) { int n = l(s); for (int i = 0; i < n; i++) if (!isDigit(s.charAt(i))) return i; return -1; } static String hopeningTag(String tag, Map params) { return hopeningTag(tag, mapToParams(params)); } static String hopeningTag(String tag, Object... params) { StringBuilder buf = new StringBuilder(); buf.append("<" + tag); params = unrollParams(params); for (int i = 0; i < l(params); i += 2) { String name = (String) get(params, i); Object val = get(params, i+1); if (nempty(name) && val != null) { if (eqOneOf(val, html_valueLessParam(), true)) buf.append(" " + name); else { String s = str(val); if (!empty(s)) buf.append(" " + name + "=" + htmlQuote(s)); } } } buf.append(">"); return str(buf); } static String loadTextFilePossiblyGZipped(String fileName) { return loadTextFilePossiblyGZipped(fileName, null); } static String loadTextFilePossiblyGZipped(String fileName, String defaultContents) { File gz = new File(fileName + ".gz"); return gz.exists() ? loadGZTextFile(gz) : loadTextFile(fileName, defaultContents); } static String loadTextFilePossiblyGZipped(File fileName) { return loadTextFilePossiblyGZipped(fileName, null); } static String loadTextFilePossiblyGZipped(File fileName, String defaultContents) { return loadTextFilePossiblyGZipped(fileName.getPath(), defaultContents); } static File getCachedTranspilationFile(String id) { return newFile(getCodeProgramDir(id), "Transpilation"); } static Object vmGeneralMap_get(Object key) { return vm_generalMap_get(key); } static String loadProgramTextFile(String name) { return loadTextFile(getProgramFile(name)); } static String loadProgramTextFile(String progID, String name) { return loadTextFile(getProgramFile(progID, name)); } static String loadProgramTextFile(String progID, String name, String defaultText) { return loadTextFile(getProgramFile(progID, name), defaultText); } static void saveTranspiledCode(String progID, String code) { File dir = getCodeProgramDir(progID); new File(dir, "Transpilation").delete(); saveGZTextFile(new File(dir, "Transpilation.gz"), code); } static void printWithMSTime(A a) { printWithMSTime("", a); } static void printWithMSTime(String prefix, A a) { print(hmsWithColonsAndMS() + ": " + combinePrintParameters(prefix, a)); } static File linux_fileInRamDisk(String name) { if (!isLinux()) return null; File dir = newFile("/dev/shm"); if (dir.isDirectory()) return newFile(dir, name); return null; } static String aGlobalID() { return randomID(globalIDLength()); } static String aGlobalID(Random random) { return randomID(random, globalIDLength()); } static boolean isMarkedAsSrcLib(String snippetID) { if (snippetID == null) return false; IResourceLoader rl = vm_getResourceLoader(); if (rl != null) return isJavaxCompilableSnippetType(rl.getSnippetType(snippetID)); return fileExists(javaxCodeDir("srclibs/" + psI(snippetID))); } static Object hotwire_onCompile; // voidfunc(Pair) static boolean hotwire_serially = false; static Lock hotwire_overInternalBot_lock = lock(); static boolean hotwire_compileOnServer = false; static Class hotwire_overInternalBot(String progID) { return hotwire_overInternalBot(progID, "main"); } static Class hotwire_overInternalBot(String progID, String mainClass) { return hotwire_overInternalBot(progID, __ -> mainClass); } static Class hotwire_overInternalBot(String progID, IF1 calculateMainClass) { try { Pair p; try { p = hotwire_compile(progID); } catch (Throwable e) { throw rethrow("Error hotwiring " + progID, e); } File jar = p.a; assertTrue(jar.getAbsolutePath(), jar.isFile()); List files = hotwire_collectJars(jar); // make class loader JavaXClassLoader classLoader = hotwire_makeClassLoader(files); classLoader.progID = progID; String mainClass = calculateMainClass == null ? "main" : calculateMainClass.get(classLoader); return hotwire_finish(classLoader, progID, p.b, mainClass); } catch (Exception __e) { throw rethrow(__e); } } // returns pair(jar, transpiled src) static Pair hotwire_compile(String progID) { Pair p = hotwire_compileOnServer && !isLocalSnippetID(progID) ? compileSnippetThroughServer(progID) : CompilerBot.compileSnippet2(progID); Lock __0 = hotwire_serially ? hotwire_overInternalBot_lock : null; lock(__0); try { callF(hotwire_onCompile, p); return p; } finally { unlock(__0); } } static void markAsSrcLib(String snippetID) { saveTextFile(javaxCodeDir("srclibs/" + psI(snippetID)), ""); } static String addSuffix(String s, String suffix) { return s == null || s.endsWith(suffix) ? s : s + suffix; } static List filesWithExtension(String ext, List files) { return filesEndingWith(files, addPrefixIfNotEmpty2(".", ext)); } static List findAllFiles_noDirs(List dirs) { return findAllFiles_noDirs(asObjectArray(dirs)); } // dirs are String's or File's static List findAllFiles_noDirs(Object... dirs) { List l = new ArrayList(); for (Object dir : dirs) { ping(); if (dir instanceof String && ((String) dir).endsWith("/.")) { // "/." means non-recurse for (File f : listFiles(dropSuffix("/.", ((String) dir)))) { ping(); if (f.isFile()) l.add(f); } } else findAllFiles_noDirs_impl(toFile(dir), l); } return l; } static void findAllFiles_noDirs_impl(File dir, List l) { for (File f : listFiles(dir)) { ping(); if (f.isDirectory()) findAllFiles_noDirs_impl(f, l); else l.add(f); } } static File[] listFiles(File dir) { File[] files = dir == null ? null : dir.listFiles(); return files == null ? new File[0] : files; } static File[] listFiles(String dir) { return listFiles(new File(dir)); } static List sortFilesByName(List l) { sort(l, (a, b) -> stdcompare(a.getName(), b.getName())); return l; } static int deleteAllFilesInDirectory_minPathLength = 10; static void deleteAllFilesInDirectory(File dir) { deleteAllFilesInDirectory(dir, false, false); } static void deleteAllFilesInDirectory(File dir, boolean verbose, boolean testRun) { dir = getCanonicalFile(dir); assertTrue(f2s(dir), l(f2s(dir)) >= deleteAllFilesInDirectory_minPathLength); File[] files = dir.listFiles(); if (files == null) return; for (File f : files) { if (!isSymLink(f) && f.isDirectory()) // just delete the symlink, don't follow it deleteDirectory(f, verbose, testRun); else { if (verbose) print((testRun ? "Would delete " : "Deleting ") + f.getAbsolutePath()); if (!testRun) f.delete(); } } } static Object callJavaX(String method, Object... args) { return callOpt(getJavaX(), method, args); } static byte[] intToBytes(int i) { return new byte[] { (byte) (i >>> 24), (byte) (i >>> 16), (byte) (i >>> 8), (byte) i}; } static String utf8streamToString(InputStream in) { return readerToString(utf8bufferedReader(in)); } static TreeSet asTreeSet(Collection set) { return set == null ? null : set instanceof TreeSet ? (TreeSet) set : new TreeSet(set); } static Runnable rPcall(Runnable r) { return r == null ? null : () -> { try { r.run(); } catch (Throwable __e) { pcallFail(__e); } }; } static Random defaultRandomizer() { return defaultRandomGenerator(); } static A listGet(List l, int idx) { return l != null && idx >= 0 && idx < l.size() ? l.get(idx) : null; } static Object costCenter() { return mc(); } static SimpleDateFormat simpleDateFormat_local(String format) { SimpleDateFormat sdf = new SimpleDateFormat(format); sdf.setTimeZone(localTimeZone()); return sdf; } static Object[] mapToParams(Map map) { return mapToObjectArray(map); } static Object[] unrollParams(Object[] params) { if (l(params) == 1 && params[0] instanceof Map) return mapToParams((Map) params[0]); return params; } static Object html_valueLessParam_cache; static Object html_valueLessParam() { if (html_valueLessParam_cache == null) html_valueLessParam_cache = html_valueLessParam_load(); return html_valueLessParam_cache;} static Object html_valueLessParam_load() { return new Object(); } static String htmlQuote(String s) { return "\"" + htmlencode_forParams(s) + "\""; } static String loadGZTextFile(File file) { try { if (!file.isFile()) return null; ping(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); InputStream fis = new FileInputStream(file); try { GZIPInputStream gis = newGZIPInputStream(fis); byte[] buffer = new byte[1024]; int len; while ((len = gis.read(buffer)) != -1) baos.write(buffer, 0, len); baos.close(); return fromUtf8(baos.toByteArray()); // TODO: use a Reader } finally { _close(fis); }} catch (Exception __e) { throw rethrow(__e); } } static File getCodeProgramDir() { return getCodeProgramDir(getProgramID()); } static File getCodeProgramDir(String snippetID) { return new File(javaxCodeDir(), formatSnippetID(snippetID)); } static File getCodeProgramDir(long snippetID) { return getCodeProgramDir(formatSnippetID(snippetID)); } static void saveGZTextFile(File file, String contents) { saveGZTextFile(file, contents, "UTF-8"); } static void saveGZTextFile(File file, String contents, String encoding) { try { File parentFile = file.getParentFile(); if (parentFile != null) parentFile.mkdirs(); String tempFileName = file.getPath() + "_temp"; File tempFile = new File(tempFileName); if (contents != null) { if (tempFile.exists()) try { String saveName = tempFileName + ".saved." + now(); copyFile(tempFile, new File(saveName)); } catch (Throwable e) { printStackTrace(e); } FileOutputStream fileOutputStream = newFileOutputStream(tempFile.getPath()); GZIPOutputStream gos = new GZIPOutputStream(fileOutputStream); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(gos, encoding); PrintWriter printWriter = new PrintWriter(outputStreamWriter); printWriter.print(contents); printWriter.close(); gos.close(); fileOutputStream.close(); } if (file.exists() && !file.delete()) throw new IOException("Can't delete " + file.getPath()); if (contents != null) if (!tempFile.renameTo(file)) throw new IOException("Can't rename " + tempFile + " to " + file); } catch (Exception __e) { throw rethrow(__e); } } static String hmsWithColonsAndMS() { return hmsWithColonsAndMS(now()); } static String hmsWithColonsAndMS(long time) { return simpleDateFormat_local("HH:mm:ss:SSS").format(time); } static Cache isLinux_cache = new Cache<>(() -> isLinux_load()); static boolean isLinux() { return isLinux_cache.get(); } static Boolean isLinux_load() { return !isWindows() && !isMac() && !isAndroid(); } static int globalIDLength() { return 16; } static boolean isJavaxCompilableSnippetType(int type) { return isJavaxCompilableSnippetTypeExceptInclude(type) || type == javaxIncludeSnippetType(); } static List hotwire_collectJars(File jar) { List libIDs = hotwire_libraryIDsFromJar_deleteJarOnFail(jar); List files = ll(jar); // main program has to be first entry! (e.g. for hotwire_makeClassLoader_stickyAndSrcLibs) for (String libID : libIDs) files.add(loadLibraryOrSrcLib(libID)); return files; } // returns (jar, transpiled src) static Pair compileSnippetThroughServer(String progID) { String transpiledSrc = getServerTranspiled2(progID); String md5 = md5(transpiledSrc + "\n" + progID); File jar = CompilerBot.getJarFile(md5); if (jar == null || jar.length() <= 22) { byte[] jarData = null; boolean dontLoad = false; IResourceLoader rl = vm_getResourceLoader(); if (rl != null) { dontLoad = true; File jar2 = rl.getSnippetJar(progID, transpiledSrc); if (jar2 != null) return pair(jar2, transpiledSrc); } if (!dontLoad) { try { jarData = loadBinaryPage(jarBotURL() + psI(progID) + "?md5=" + md5(transpiledSrc)); } catch (Throwable __e) { pcallFail(__e); }} if (!isJAR(jarData)) { if (jarData != null) { print(bytesToHex(takeFirstOfByteArray(8, jarData))); print("fallback to CompilerBot: " + fromUtf8(takeFirstOfByteArray(80, jarData))); } return CompilerBot.compileSnippet2(progID); } saveBinaryFile(jar, jarData); } return pair(jar, transpiledSrc); } static List filesEndingWith(File dir, String suffix) { return listFilesWithSuffix(dir, suffix); } static List filesEndingWith(List l, String suffix) { List out = new ArrayList(); for (File f : unnull(l)) if (!f.isDirectory() && (empty(suffix) || endsWithIgnoreCase(f.getName(), suffix))) out.add(f); return out; } static List filesEndingWith(String suffix, File dir) { return filesEndingWith(dir, suffix); } static Object[] asObjectArray(Collection l) { return toObjectArray(l); } static File toFile(Object o) { if (o instanceof File) return (File) o; if (o instanceof String) return new File((String) o); throw fail("Not a file: " + o); } static File getCanonicalFile(String path) { try { return path == null ? null : newFile(path).getCanonicalFile(); } catch (Exception __e) { throw rethrow(__e); } } static File getCanonicalFile(File f) { try { return f == null ? null : f.getCanonicalFile(); } catch (Exception __e) { throw rethrow(__e); } } static boolean isSymLink(File f) { return f != null && Files.isSymbolicLink(toPath(f)); } static String readerToString(Reader r) { try { if (r == null) return null; try { StringBuilder buf = new StringBuilder(); int n = 0; while (true) { int ch = r.read(); if (ch < 0) break; buf.append((char) ch); ++n; //if ((n % loadPage_verboseness) == 0) print(" " + n + " chars read"); } return buf.toString(); } finally { r.close(); } } catch (Exception __e) { throw rethrow(__e); } } static TimeZone localTimeZone() { return getTimeZone(standardTimeZone()); // TimeZone.getDefault()? } static Object[] mapToObjectArray(Map map) { List l = new ArrayList(); for (Object o : keys(map)) { l.add(o); l.add(map.get(o)); } return toObjectArray(l); } static Object[] mapToObjectArray(Object f, Collection l) { int n = l(l); Object[] array = new Object[n]; if (n != 0) { Iterator it = iterator(l); for (int i = 0; i < n; i++) array[i] = callF(f, it.next()); } return array; } static Object[] mapToObjectArray(Object f, Object[] l) { int n = l(l); Object[] array = new Object[n]; for (int i = 0; i < n; i++) array[i] = callF(f, l[i]); return array; } static Object[] mapToObjectArray(Collection l, IF1 f) { return mapToObjectArray(f, l); } static Object[] mapToObjectArray(A[] l, IF1 f) { return mapToObjectArray(f, l); } static Object[] mapToObjectArray(IF1 f, A[] l) { int n = l(l); Object[] array = new Object[n]; for (int i = 0; i < n; i++) array[i] = f.get(l[i]); return array; } static Object[] mapToObjectArray(IF1 f, Collection l) { int n = l(l); Object[] array = new Object[n]; if (n != 0) { Iterator it = iterator(l); for (int i = 0; i < n; i++) array[i] = callF(f, it.next()); } return array; } // this should be on by default now I think, but it may break // legacy code... static ThreadLocal htmlencode_forParams_useV2 = new ThreadLocal(); static String htmlencode_forParams(String s) { if (s == null) return ""; if (isTrue(htmlencode_forParams_useV2.get())) return htmlencode_forParams_v2(s); StringBuilder out = new StringBuilder(Math.max(16, s.length())); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c > 127 || c == '"' || c == '<' || c == '>') { out.append("&#"); out.append((int) c); out.append(';'); } else out.append(c); } return out.toString(); } public static boolean isWindows() { return System.getProperty("os.name").contains("Windows"); } static boolean isMac() { return System.getProperty("os.name").toLowerCase().contains("mac"); } static boolean isJavaxCompilableSnippetTypeExceptInclude(int type) { return isJavaxApplicationSnippetType(type) || isJavaxModuleSnippetType(type) || type == snippetType_dynModule(); } static int javaxIncludeSnippetType() { return 42; } static List hotwire_libraryIDsFromJar_deleteJarOnFail(File jar) { try { return hotwire_libraryIDsFromJar(jar); } catch (Throwable _e) { jar.delete(); throw rethrow(_e); } } static String jarBotURL() { return "https://botcompany.de/jar/"; } static String jarBotURL(String snippetID) { return jarBotURL() + psI(snippetID); } static byte[] isJAR_magic = bytesFromHex("504B0304"); static boolean isJAR(byte[] data) { return byteArrayStartsWith(data, isJAR_magic); } static boolean isJAR(File f) { return isJAR(loadBeginningOfBinaryFile(f, l(isJAR_magic))); } static List listFilesWithSuffix(File dir, String suffix) { List l = new ArrayList(); for (File f : listFiles(dir)) if (!f.isDirectory() && (empty(suffix) || endsWithIgnoreCase(f.getName(), suffix))) l.add(f); return l; } static List listFilesWithSuffix(String suffix, File dir) { return listFilesWithSuffix(dir, suffix); } static Path toPath(File f) { return f == null ? null : f.toPath(); } static TimeZone getTimeZone(String name) { return TimeZone.getTimeZone(name); } static String standardTimeZone_name = "Europe/Berlin"; static String standardTimeZone() { return standardTimeZone_name; } static String htmlencode_forParams_v2(String s) { if (s == null) return ""; StringBuilder out = new StringBuilder(Math.max(16, s.length())); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c > 127 || c == '"' || c == '<' || c == '>' || c == '&') { out.append("&#"); out.append((int) c); out.append(';'); } else out.append(c); } return out.toString(); } static boolean isJavaxApplicationSnippetType(int type) { return type == snippetType_javaxSource() || type == snippetType_JavaXDesktop(); } static boolean isJavaxModuleSnippetType(int type) { return type == snippetType_javaxModule() || type == snippetType_javaxDesktopModule(); } static int snippetType_dynModule() { return 57; } static List hotwire_libraryIDsFromJar(File jar) { String dehlibs = unnull(loadTextFileFromZip(jar, "libraries")); return regexpExtractAll("\\d+", dehlibs); } static int snippetType_javaxSource() { return 34; } static int snippetType_JavaXDesktop() { return 55; } static int snippetType_javaxModule() { return 54; } static int snippetType_javaxDesktopModule() { return 58; } static List regexpExtractAll(String pat, String s) { if (s == null) return null; Matcher m = regexpMatcher(pat, s); List out = new ArrayList(); while (m.find()) out.add(m.group()); return out; } static class Chain implements Iterable { A element; Chain next; int size; Chain() {} Chain(A element) { this.element = element; size = 1; } Chain(A element, Chain next) { this.next = next; this.element = element; size = next != null ? next.size+1 : 1; } public String toString() { return str(toList()); } ArrayList toList() { ArrayList l = emptyList(size); Chain c = this; while (c != null) { l.add(c.element); c = c.next; } return l; } // TODO: optimize public Iterator iterator() { return toList().iterator(); } } // size: // 64 bytes for 0 to 1 elements // 96 bytes for 2 to 4 elements /* * #! * Ontopia Engine * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * !# */ static class CompactHashMap extends CompactAbstractMap { final static int INITIAL_SIZE = 3; final static double LOAD_FACTOR = 0.6; // This object is used to represent a null KEY (null value are kept as is) final static Object nullObject = new Object(); /** * When a key is deleted this object is put into the hashtable in * its place, so that other entries with the same key (collisions) * further down the hashtable are not lost after we delete an object * in the collision chain. */ final static Object deletedObject = new Object(); int elements; int freecells; Object[] table; // key, value, key, value, ... //int modCount; CompactHashMap() { this(INITIAL_SIZE); } CompactHashMap(int size) { table = new Object[(size==0 ? 1 : size)*2]; elements = 0; freecells = tableSize(); //modCount = 0; } // TODO: allocate smarter CompactHashMap(Map map) { this(0); if (map != null) putAll(map); } // ===== MAP IMPLEMENTATION ============================================= /** * Returns the number of key/value mappings in this map. */ public synchronized int size() { return elements; } /** * Returns true if this map contains no mappings. */ public synchronized boolean isEmpty() { return elements == 0; } /** * Removes all key/value mappings in the map. */ public synchronized void clear() { elements = 0; for (int ix = 0; ix < tableSize(); ix++) { key(ix, null); value(ix, null); } freecells = tableSize(); //modCount++; } /** * Returns true if this map contains the specified key. */ public synchronized boolean containsKey(Object k) { return key(findKeyIndex(k)) != null; } /** * Returns true if this map contains the specified value. */ public synchronized boolean containsValue(Object v) { if (v == null) v = (V)nullObject; for (int ix = 0; ix < tableSize(); ix++) if (value(ix) != null && value(ix).equals(v)) return true; return false; } /** * Returns a read-only set view of the map's keys. */ public synchronized Set> entrySet() { return new EntrySet(); } /** * Removes the mapping with key k, if there is one, and returns its * value, if there is one, and null if there is none. */ public synchronized V remove(Object k) { int index = findKeyIndex(k); // we found the right position, now do the removal if (key(index) != null) { // we found the object // same problem here as with put V v = value(index); key(index, deletedObject); value(index, deletedObject); //modCount++; elements--; return v; } else // we did not find the key return null; } /** * Adds the specified mapping to this map, returning the old value for * the mapping, if there was one. */ public synchronized V put(K k, V v) { if (k == null) k = (K)nullObject; int hash = k.hashCode(); int index = (hash & 0x7FFFFFFF) % tableSize(); int offset = 1; int deletedix = -1; // search for the key (continue while !null and !this key) while(key(index) != null && !(key(index).hashCode() == hash && key(index).equals(k))) { // if there's a deleted mapping here we can put this mapping here, // provided it's not in here somewhere else already if (key(index) == deletedObject) deletedix = index; index = ((index + offset) & 0x7FFFFFFF) % tableSize(); offset = offset*2 + 1; if (offset == -1) offset = 2; } if (key(index) == null) { // wasn't present already if (deletedix != -1) // reusing a deleted cell index = deletedix; else freecells--; //modCount++; elements++; key(index, k); value(index, v); // rehash with increased capacity if (1 - (freecells / (double) tableSize()) > LOAD_FACTOR) rehash(tableSize()*2 + 1); return null; } else { // was there already //modCount++; V oldv = value(index); value(index, v); return oldv; } } /** * INTERNAL: Rehashes the hashmap to a bigger size. */ void rehash(int newCapacity) { int oldCapacity = tableSize(); Object[] newTable = new Object[newCapacity*2]; for (int ix = 0; ix < oldCapacity; ix++) { Object k = key(ix); if (k == null || k == deletedObject) continue; int hash = k.hashCode(); int index = (hash & 0x7FFFFFFF) % newCapacity; int offset = 1; // search for the key while(newTable[index*2] != null) { // no need to test for duplicates index = ((index + offset) & 0x7FFFFFFF) % newCapacity; offset = offset*2 + 1; if (offset == -1) offset = 2; } newTable[index*2] = k; newTable[index*2+1] = value(ix); } table = newTable; freecells = tableSize() - elements; } /** * Returns the value for the key k, if there is one, and null if * there is none. */ public synchronized V get(Object k) { return value(findKeyIndex(k)); } /** * Returns a virtual read-only collection containing all the values * in the map. */ public synchronized Collection values() { return new ValueCollection(); } /** * Returns a virtual read-only set of all the keys in the map. */ public synchronized Set keySet() { return new KeySet(); } // --- Internal utilities final int findKeyIndex(Object k) { if (k == null) k = nullObject; int hash = k.hashCode(); int index = (hash & 0x7FFFFFFF) % tableSize(); int offset = 1; // search for the key (continue while !null and !this key) while(key(index) != null && !(key(index).hashCode() == hash && key(index).equals(k))) { index = ((index + offset) & 0x7FFFFFFF) % tableSize(); offset = offset*2 + 1; if (offset == -1) offset = 2; } return index; } // --- Key set class KeySet extends AbstractSet { public int size() { synchronized(CompactHashMap.this) { return elements; }} public boolean contains(Object k) { synchronized(CompactHashMap.this) { return containsKey(k); }} public Iterator iterator() { synchronized(CompactHashMap.this) { return new KeyIterator(); }} } class KeyIterator implements Iterator { private int ix; private KeyIterator() { synchronized(CompactHashMap.this) { // walk up to first value, so that hasNext() and next() return // correct results for (; ix < tableSize(); ix++) if (value(ix) != null && key(ix) != deletedObject) break; } } public boolean hasNext() { synchronized(CompactHashMap.this) { return ix < tableSize(); }} public void remove() { throw new UnsupportedOperationException("Collection is read-only"); } public K next() { synchronized(CompactHashMap.this) { if (ix >= tableSize()) throw new NoSuchElementException(); K key = (K) key(ix++); // walk up to next value for (; ix < tableSize(); ix++) if (key(ix) != null && key(ix) != deletedObject) break; // ix now either points to next key, or outside array (if no next) return key; }} } // --- Entry set class EntrySet extends AbstractSet> { public int size() { synchronized(CompactHashMap.this) { return elements; }} public boolean contains(Object o) { synchronized(CompactHashMap.this) { if (o instanceof Map.Entry) { Object key = ((Map.Entry) o).getKey(); if (!containsKey((Map.Entry) o)) return false; return eq(((Map.Entry) o).getValue(), get(key)); } return false; }} public Iterator> iterator() { return new EntryIterator(); } } class EntryIterator implements Iterator> { private int ix; private EntryIterator() { synchronized(CompactHashMap.this) { // walk up to first value, so that hasNext() and next() return // correct results for (; ix < tableSize(); ix++) if (value(ix) != null && key(ix) != deletedObject) break; } } public boolean hasNext() { synchronized(CompactHashMap.this) { return ix < tableSize(); }} public void remove() { throw new UnsupportedOperationException("Collection is read-only"); } public Map.Entry next() { synchronized(CompactHashMap.this) { if (ix >= tableSize()) throw new NoSuchElementException(); K key = key(ix); V val = value(ix); ++ix; // walk up to next value for (; ix < tableSize(); ix++) if (key(ix) != null && key(ix) != deletedObject) break; // ix now either points to next key, or outside array (if no next) return simpleMapEntry(key, val); }} } // --- Value collection class ValueCollection extends AbstractCollection { public int size() { synchronized(CompactHashMap.this) { return elements; }} public Iterator iterator() { return new ValueIterator(); } public boolean contains(Object v) { return containsValue(v); } } class ValueIterator implements Iterator { private int ix; private ValueIterator() { synchronized(CompactHashMap.this) { // walk up to first value, so that hasNext() and next() return // correct results for (; ix < table.length/2; ix++) if (value(ix) != null && value(ix) != deletedObject) break; } } public boolean hasNext() { synchronized(CompactHashMap.this) { return ix < tableSize(); }} public void remove() { throw new UnsupportedOperationException("Collection is read-only"); } public V next() { synchronized(CompactHashMap.this) { if (ix >= tableSize()) throw new NoSuchElementException(); V value = (V) value(ix++); // walk up to next value for (; ix < tableSize(); ix++) if (value(ix) != null && value(ix) != deletedObject) break; // ix now either points to next value, or outside array (if no next) return value; }} } K key(int i) { return (K) table[i*2]; } void key(int i, Object key) { table[i*2] = key; } V value(int i) { return (V) table[i*2+1]; } void value(int i, Object value) { table[i*2+1] = value; } int tableSize() { return table.length/2; } } static class ReverseChain implements Iterable { A element; ReverseChain prev; int size; ReverseChain() {} ReverseChain(ReverseChain prev, A element) { this.element = element; this.prev = prev; if (prev == null) size = 1; else { prev.check(); size = prev.size+1; } } void check() { if (size < 1) throw fail("You called the ReverseChain default constructor. Don't do that"); } public String toString() { return str(toList()); } ArrayList toList() { check(); ArrayList l = emptyList(size); for (int i = 0; i < size; i++) l.add(null); int i = size; ReverseChain c = this; while (c != null) { l.set(--i, c.element); c = c.prev; } return l; } public Iterator iterator() { return toList().iterator(); } } // a variant of thread where you can get the Runnable target later. // Also notes its existence on the VM bus. // We should use this exclusively instead of Thread. static class BetterThread extends Thread { Runnable target; BetterThread(Runnable target) { this.target = target; _created(); } BetterThread(Runnable target, String name) { super(name); this.target = target; _created(); } void _created() { vmBus_send("threadCreated", this); } public void run() { try { try { vmBus_send("threadStarted", this); if (target != null) target.run(); } finally { vmBus_send("threadEnded", this); } } catch (Exception __e) { throw rethrow(__e); } } Runnable getTarget() { return target; } } static class Complex implements IFieldsToList{ static final String _fieldOrder = "re im"; double re; double im; Complex() {} Complex(double re, double im) { this.im = im; this.re = re;} public boolean equals(Object o) { if (!(o instanceof Complex)) return false; Complex __1 = (Complex) o; return re == __1.re && im == __1.im; } public int hashCode() { int h = -1679819632; h = boostHashCombine(h, _hashCode(re)); h = boostHashCombine(h, _hashCode(im)); return h; } public Object[] _fieldsToList() { return new Object[] {re, im}; } double abs() { return sqrt(re*re+im*im); } double re() { return re; } double im() { return im; } final double angle(){ return phase(); } double phase() { return Math.atan2(im, re); } double fracAngle() { return fracNonNeg(angle()/twoPi()); } // angle as 0 to 1 public String toString() { if (im != 0) return re == 0 ? im + "i" : re + plusPrefixUnlessMinus(str(im)) + "i"; else return str(re); } } static final class WidthAndHeightFinal extends Meta implements WidthAndHeight , IFieldsToList{ static final String _fieldOrder = "width height"; int width; int height; WidthAndHeightFinal() {} WidthAndHeightFinal(int width, int height) { this.height = height; this.width = width;} public boolean equals(Object o) { if (!(o instanceof WidthAndHeightFinal)) return false; WidthAndHeightFinal __0 = (WidthAndHeightFinal) o; return width == __0.width && height == __0.height; } public int hashCode() { int h = -1177452162; h = boostHashCombine(h, _hashCode(width)); h = boostHashCombine(h, _hashCode(height)); return h; } public Object[] _fieldsToList() { return new Object[] {width, height}; } public int getWidth() { return width; } public int getHeight() { return height; } WidthAndHeightFinal(int wAndH) { this(wAndH, wAndH); } public String toString() { return n2(width) + "*" + n2(height) + " px"; } } static class Cache { Object maker; // func -> A A value; long loaded; static boolean debug = false; long changeCount; Lock lock = lock(); Cache() {} Cache(Object maker) { this.maker = maker;} Cache(IF0 maker) { this.maker = maker;} A get() { if (hasLock(lock)) return value; // Must be called from within maker Lock __0 = lock; lock(__0); try { if (loaded == 0) { value = make(); changeCount++; loaded = sysNow(); } return value; } finally { unlock(__0); } } void clear() { Lock __1 = lock; lock(__1); try { if (debug && loaded != 0) print("Clearing cache"); value = null; changeCount++; loaded = 0; } finally { unlock(__1); } } // clear if older than x seconds // 0 does not do anything void clear(double seconds) { Lock __2 = lock; lock(__2); try { if (seconds != 0 && loaded != 0 && sysNow() >= loaded+seconds*1000) clear(); } finally { unlock(__2); } } // override void set(A a) { Lock __3 = lock; lock(__3); try { value = a; ++changeCount; loaded = sysNow(); } finally { unlock(__3); } } A make() { return (A) callF(maker); } } abstract static class CompactAbstractMap implements Map { public int size() { return entrySet().size(); } public boolean isEmpty() { return size() == 0; } public boolean containsValue(Object value) { Iterator> i = entrySet().iterator(); if (value == null) { while (i.hasNext()) { Entry e = i.next(); if (e.getValue() == null) return true; } } else { while (i.hasNext()) { Entry e = i.next(); if (value.equals(e.getValue())) return true; } } return false; } public boolean containsKey(Object key) { Iterator> i = entrySet().iterator(); if (key == null) { while (i.hasNext()) { Entry e = i.next(); if (e.getKey() == null) return true; } } else { while (i.hasNext()) { Entry e = i.next(); if (key.equals(e.getKey())) return true; } } return false; } public V get(Object key) { Iterator> i = entrySet().iterator(); if (key == null) { while (i.hasNext()) { Entry e = i.next(); if (e.getKey() == null) return e.getValue(); } } else { while (i.hasNext()) { Entry e = i.next(); if (key.equals(e.getKey())) return e.getValue(); } } return null; } public V put(K key, V value) { throw new UnsupportedOperationException(); } public V remove(Object key) { Iterator> i = entrySet().iterator(); Entry correctEntry = null; if (key == null) { while (correctEntry == null && i.hasNext()) { Entry e = i.next(); if (e.getKey() == null) correctEntry = e; } } else { while (correctEntry == null && i.hasNext()) { Entry e = i.next(); if (key.equals(e.getKey())) correctEntry = e; } } V oldValue = null; if (correctEntry != null) { oldValue = correctEntry.getValue(); i.remove(); } return oldValue; } public void putAll(Map m) { for (Entry e : m.entrySet()) put(e.getKey(), e.getValue()); } public void clear() { entrySet().clear(); } public Set keySet() { return new AbstractSet() { public Iterator iterator() { return new Iterator() { private Iterator> i = entrySet().iterator(); public boolean hasNext() { return i.hasNext(); } public K next() { return i.next().getKey(); } public void remove() { i.remove(); } }; } public int size() { return CompactAbstractMap.this.size(); } public boolean isEmpty() { return CompactAbstractMap.this.isEmpty(); } public void clear() { CompactAbstractMap.this.clear(); } public boolean contains(Object k) { return CompactAbstractMap.this.containsKey(k); } }; } public Collection values() { return new AbstractCollection() { public Iterator iterator() { return new Iterator() { private Iterator> i = entrySet().iterator(); public boolean hasNext() { return i.hasNext(); } public V next() { return i.next().getValue(); } public void remove() { i.remove(); } }; } public int size() { return CompactAbstractMap.this.size(); } public boolean isEmpty() { return CompactAbstractMap.this.isEmpty(); } public void clear() { CompactAbstractMap.this.clear(); } public boolean contains(Object v) { return CompactAbstractMap.this.containsValue(v); } }; } public abstract Set> entrySet(); public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Map)) return false; Map m = (Map) o; if (m.size() != size()) return false; try { for (Entry e : entrySet()) { K key = e.getKey(); V value = e.getValue(); if (value == null) { if (!(m.get(key) == null && m.containsKey(key))) return false; } else { if (!value.equals(m.get(key))) return false; } } } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; } return true; } public int hashCode() { int h = 0; for (Entry entry : entrySet()) h += entry.hashCode(); return h; } public String toString() { Iterator> i = entrySet().iterator(); if (!i.hasNext()) return "{}"; StringBuilder sb = new StringBuilder(); sb.append('{'); for (; ; ) { Entry e = i.next(); K key = e.getKey(); V value = e.getValue(); sb.append(key == this ? "(this Map)" : key); sb.append('='); sb.append(value == this ? "(this Map)" : value); if (!i.hasNext()) return sb.append('}').toString(); sb.append(',').append(' '); } } protected Object clone() throws CloneNotSupportedException { CompactAbstractMap result = (CompactAbstractMap) super.clone(); return result; } public static class SimpleEntry implements Entry, java.io.Serializable { @java.io.Serial private static final long serialVersionUID = -8499721149061103585L; @SuppressWarnings("serial") private final K key; @SuppressWarnings("serial") private V value; public SimpleEntry(K key, V value) { this.key = key; this.value = value; } public SimpleEntry(Entry entry) { this.key = entry.getKey(); this.value = entry.getValue(); } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { V oldValue = this.value; this.value = value; return oldValue; } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Entry e = (Entry) o; return eq(key, e.getKey()) && eq(value, e.getValue()); } public int hashCode() { return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } public String toString() { return key + "=" + value; } } public static class SimpleImmutableEntry implements Entry, java.io.Serializable { @java.io.Serial private static final long serialVersionUID = 7138329143949025153L; @SuppressWarnings("serial") private final K key; @SuppressWarnings("serial") private final V value; public SimpleImmutableEntry(K key, V value) { this.key = key; this.value = value; } public SimpleImmutableEntry(Entry entry) { this.key = entry.getKey(); this.value = entry.getValue(); } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { throw new UnsupportedOperationException(); } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Entry e = (Entry) o; return eq(key, e.getKey()) && eq(value, e.getValue()); } public int hashCode() { return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } public String toString() { return key + "=" + value; } } } static boolean scaffoldingEnabled(Object o) { return metaGet(o, "scaffolding") != null; } static Value value(A a) { return new Value(a); } static boolean containsKey(Map map, A key) { return map != null && map.containsKey(key); } static Map.Entry simpleMapEntry(A key, B value) { return new Map.Entry() { public A getKey() { return key; } public B getValue() { return value; } public B setValue(B newValue) { throw unimplemented(); } }; } static double fracNonNeg(double d) { return frac_nonNeg(d); } static double twoPi() { return Math.PI*2; } static String plusPrefixUnlessMinus(String s) { return startsWith(s, "-") ? s : "+" + s; } static boolean hasLock(Lock lock) { return ((ReentrantLock) lock).isHeldByCurrentThread(); } static RuntimeException unimplemented() { throw fail("TODO"); } static RuntimeException unimplemented(String msg) { throw fail("TODO: " + msg); } static RuntimeException unimplemented(Object obj) { throw fail("TODO: implement method in " + className(obj)); } static double frac_nonNeg(double d) { return mod(d, 1); } // better modulo that gives positive numbers always static int mod(int n, int m) { return (n % m + m) % m; } static long mod(long n, long m) { return (n % m + m) % m; } static BigInteger mod(BigInteger n, int m) { return n.mod(bigint(m)); } static double mod(double n, double m) { return (n % m + m) % m; } static class Value implements IF0 , IFieldsToList{ A value; Value() {} Value(A value) { this.value = value;} public boolean equals(Object o) { if (!(o instanceof Value)) return false; Value __1 = (Value) o; return eq(value, __1.value); } public int hashCode() { int h = 82420049; h = boostHashCombine(h, _hashCode(value)); return h; } public Object[] _fieldsToList() { return new Object[] {value}; } public A get() { return value; } public String toString() { return str(get()); } } }